ctx

ctx

MCP server for context switching across git worktrees and Claude Code agent sessions, providing a board of worktree status and distilled task summaries.

Category
访问服务器

README

ctx

A daemon-less CLI, TUI, and MCP companion for context-switching across git worktrees and Claude Code agent sessions.

The ctx board: one row per worktree, showing agent status, last activity, and a distilled one-line task

The problem

Working across multiple git worktrees, each with one or more Claude Code agent sessions, makes context switching expensive.

  • Returning to one tab: you forget what an agent was doing after deep work elsewhere, and waste tokens asking it to re-summarize.
  • Cross-worktree overview: there is no board showing branch, agent status, last activity, and a one-line task summary across all your worktrees.
  • Agent cold-start: new or resumed agent sessions re-ask or re-explore state that already exists in transcripts and git.

ctx solves all three by reading your existing Claude Code transcripts (~/.claude/projects/**/*.jsonl) and git state, distilling them into a compact per-worktree record, and serving that record to humans (CLI, TUI) and agents (hook injection, MCP) alike.

There is no background daemon. State is derived on demand and cached in one JSON file per worktree.

Requirements

  • Bun 1.2 or newer.
  • git 2.31 or newer. ctx neutralizes repository-controlled git config via GIT_CONFIG_COUNT, which older git ignores silently; rather than probe unprotected, it declines to read git state at all.
  • Optional: the claude CLI on your PATH, or an ANTHROPIC_API_KEY. Without either, ctx still works in raw mode.

Try it without installing

bun install
bun src/index.ts status --no-distill

That prints the board from your existing transcripts and touches nothing outside the repo.

Install

bun install
bun src/index.ts install

install builds a compiled binary to ~/.local/bin/ctx, merges Claude Code hook entries into ~/.claude/settings.json (with a one-time backup), and registers ctx as an MCP server via claude mcp add if the claude CLI is on your PATH. Make sure ~/.local/bin is on your shell PATH.

Hooks are installed at user scope, so they run for every Claude Code session on the machine, not just in this project.

Commands

ctx [project]                 interactive TUI (the default command), optionally scoped
ctx status [project] [--no-distill] [--all]
                              board of worktrees, optionally scoped to one project
ctx recap [worktree|project|.] [--no-distill]
                              full recap for one worktree (project name works when unambiguous)
ctx inject [--cwd <dir>]      SessionStart hook target (prints compact recap)
ctx checkpoint --event <e>    hook target (stop|precompact|end|note)
ctx ui [project]              interactive TUI, optionally scoped to one project
ctx mcp                       stdio MCP server
ctx install                   install hooks + MCP config
ctx --version                 print the installed version

ctx status is the board view: one row per worktree with repo/branch, session status, last-active time, a distilled one-line task, and git facts (dirty, ahead, behind). Pass a project name to scope the board, e.g. ctx status myrepo shows only that repo's worktrees. At most 5 worktrees are distilled per run; the rest are picked up on the next refresh. ctx recap prints the fuller recap (done, decisions, next, blockers) for a single worktree. ctx inject is wired to the SessionStart hook so a resumed or new agent session gets prior context injected without asking for it. ctx checkpoint is wired to Stop, PreCompact, and SessionEnd hooks to record session lifecycle events. ctx ui is an Ink-based TUI that polls the same state for a live board. ctx mcp exposes the same data as MCP tools (get_my_context, get_sibling_status, ...) so an agent can query context directly instead of re-exploring.

Reading the board

  • ● green means a Claude session wrote to its transcript in the last 5 minutes; ○ means idle or ended.
  • ◐ yellow means that worktree is being distilled right now; ✗ red means the distill produced nothing (check ~/.ctx/log, usually a claude auth issue).
  • The time column is last session activity, not when the row was distilled.
  • (raw) in the task column means the worktree has never been distilled.
  • The repo's main checkout counts as a worktree too; git itself calls it the main worktree, and agent sessions run there like anywhere else.
  • In the TUI, r re-distills every visible worktree serially and each row updates as its summary lands.

Distiller auth chain

Turning a heuristic extract (a few KB, never the raw transcript) into a one-line task and structured recap requires an LLM call. ctx never requires an API key and tries, in order:

  1. claude -p --model haiku subprocess - used first if the claude CLI is on PATH. This reuses your existing Claude Code login, so no extra credentials are needed.
  2. ANTHROPIC_API_KEY + @anthropic-ai/sdk - used as a fallback if the CLI is unavailable or fails, calling claude-haiku-4-5 directly.
  3. Raw mode - if neither is available, ctx falls back to the heuristic extract alone (no LLM summary). The board marks these worktrees as (raw) and the tools remain fully usable, just less distilled.

Distillation only runs when the transcript has changed since it was last distilled (tracked via a content hash), so repeated ctx status calls are cheap.

Design notes

The interesting problems in this codebase are mostly about untrusted input and concurrency.

Transcript content is untrusted, and it travels. A transcript records whatever an agent read: a repo's README, a fetched page, a tool result. That text is summarized by a model, stored, and then injected into other agents' sessions, including summaries of sibling worktrees. So a poisoned transcript in one worktree has a path into every sibling agent's context. Fields are collapsed to a single line before rendering, because an embedded newline can forge a line and impersonate the tool's own output; the injected block is wrapped in a delimiter with a random per-invocation suffix, because a fixed delimiter can simply be closed by the content inside it; and the model's output is length- and item-capped in code rather than trusted to obey the prompt.

Git executes what a repository's config tells it to. core.fsmonitor, filter.*.clean, and friends are commands run straight out of .git/config, and the worktree paths here come from transcripts rather than from user input. ctx enumerates a repository's resolved config and neutralizes every command-executing key via GIT_CONFIG_KEY_n environment entries rather than -c key=, because -c splits its argument at the first = and a config subsection name may legally contain one. Only repo-controlled scopes are neutralized, so a user's global git-lfs setup keeps working. --ignore-submodules=dirty stops git descending into submodules, whose own config the superproject's enumeration cannot see.

State is written by several processes at once. Hooks fire on Stop, PreCompact, and SessionEnd while the TUI polls and a distill may be mid-flight for up to a minute. Writes go through a compare-and-swap under a cross-process mkdir lock whose staleness is decided by probing the recorded pid, with an absolute age backstop so a recycled pid cannot wedge a worktree permanently.

Transcripts get large. Reading a multi-hundred-megabyte transcript whole costs gigabytes of RSS, and this runs on the TUI's event loop every 30 seconds, so both the scanner and the extractor read bounded regions and grow the window only until it contains a complete entry.

Testing

bun test        # 126 tests
bun run typecheck

The suite is mutation-verified: seeded defects (removing the state lock, dropping event validation, un-sorting the transcript scan, reverting the sanitizer) are each confirmed to fail it. That check exists because an earlier version of the suite stayed green with the entire locking apparatus deleted.

Environment variables

  • CTX_DIR - overrides the state directory (default ~/.ctx). State lives at $CTX_DIR/worktrees/*.json, and errors are logged to $CTX_DIR/log.
  • CLAUDE_PROJECTS_DIR - overrides the transcript root (default ~/.claude/projects).

Both are primarily useful for tests and for pointing ctx at a non-default Claude Code install.

Hooks always exit 0

ctx checkpoint and ctx inject are invoked as Claude Code hooks and always exit 0, even on internal failure. A hook that breaks the agent session is worse than one that silently no-ops, so every error path is caught, logged to $CTX_DIR/log, and swallowed. No LLM calls happen inside hook execution, so hooks stay fast.

State

Truth lives in your Claude Code transcripts and git; ~/.ctx/worktrees/*.json is a disposable cache, one file per worktree, written via temp-file-plus-atomic-rename. Delete the whole ~/.ctx directory at any time and it will be rebuilt on the next ctx status.

License

MIT - see LICENSE.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选