When you open a workspace's worktree in your editor and use an AI agent that lives there (magenta.nvim, Cursor, a VS Code extension), that agent has no idea what wsx knows: the workspace's goal, the status its primary agent last reported, which peer agents exist, or what the primary agent was just doing.
wsx context closes that gap with one markdown file the editor can hand to
its agent as context. Nothing on the wsx side knows which editor is reading
it; the contract below is all an integration needs, and the
neovim section is one worked example of it.
The contract
An editor integration has four parts. wsx provides the first two; the editor provides the rest.
1. The command. Run wsx context write with the worktree as the
current directory. It prints one absolute path and exits 0. Outside a wsx
worktree it exits non-zero with an error on stderr, so an integration can
be installed globally and stay inert elsewhere. No flags, no environment
variables required.
wsx context show # print the digest to stdout
wsx context write # write it to $XDG_STATE_HOME/wsx/context/<repo>/<workspace>.md and print the path
Both resolve the workspace from the current directory (or WSX_WORKSPACE_ID
when set). write replaces the file atomically, so a reader never sees a
partial digest, and creates it with user-only permissions. The path is keyed
on the workspace name, so it changes after a workspace rename; the old file
is left in place.
2. The file. A markdown digest with a fixed section order (see What the digest contains) that ends with an External instructions block addressed to the agent. The block is the behavioural contract: what the agent may do in a shared worktree and how it reports back. The file can quote the primary agent's last message verbatim; do not commit or share it.
3. The refresh policy. The editor decides when to rerun the command. Sensible triggers are editor start, window focus, and the agent's chat panel opening. The command is cheap (a handful of sqlite reads, three git commands, one transcript scan) but is not free, so debounce or guard against overlapping runs on rapid focus events.
4. The context mechanism. How the file reaches the agent is the editor's concern. An agent that re-reads tracked files before each request (magenta.nvim does) needs the path added once. An agent that snapshots a file when it is added needs it re-added after each refresh, or a rules file that tells it to read the path itself.
Reporting back goes through wsx agent send <primary label> "<summary>"
run from the worktree. Because an editor shell carries no
WSX_AGENT_INSTANCE_ID, the message reaches the primary agent with a bare
[message] banner. wsx-spawned agents are told to expect this (see
The other direction).
What the digest contains
In order:
- repo/workspace name, branch and base ref, worktree path
- attached agents, primary marked
(primary) - the last pushed status (
working — "message" (source, 4m ago)) - the recap (goal / state / next)
git log --oneline <base>..HEAD(up to 20)- an uncommitted-changes line, which appears whenever git status could be read, even when there are no commits ahead of base
- the primary agent's last assistant message, from its session transcript (Claude Code, Pi, Hermes, Codex, and oh-my-pi are all supported), capped at 2000 characters. When several agents of the same kind share the worktree, the most recently active transcript of that kind is used; wsx does not record which session belongs to which instance.
- an External instructions block
Optional sections with no data are omitted; the agents and status lines
always render, showing - when empty. Git and transcript problems never
fail the command; only an unresolvable workspace, a database read error,
or an unwritable file does.
External instructions
The digest ends with this block, addressed to the editor-hosted agent:
You are an editor-hosted agent working inside a wsx-managed worktree. The agents listed above share this branch and this working tree with you, and one of them (the primary) owns this workspace's status and recap.
- Before editing, run
git statusandgit diff; the primary agent may have changed files since this digest was written.- Keep edits small and scoped. Do not create branches, rename the workspace, or run
wsx status set/wsx recap set; those belong to the primary agent.- When you finish a change, or when you need a decision the primary agent should make, report it with:
wsx agent send <primary label> "<one-paragraph summary>"Run it from this worktree; the workspace is resolved from cwd.- This file is regenerated by
wsx context write; do not edit it.
The other direction
wsx-spawned agents get a matching doctrine clause (see
Coding agents): an editor-hosted agent
may share the worktree, it reads this digest, and its messages arrive
unlabelled. They are told to re-check git status before assuming the tree
is theirs. The bundled wsx skill repeats the same guidance.
Editor integrations
neovim + magenta.nvim
magenta.nvim re-reads every context file before each request and ignores repeat additions of the same path, so a file that wsx keeps fresh is live context. Add this to your neovim config:
-- wsx: keep the workspace context digest fresh and hand it to magenta.nvim
local worktrees = vim.fn.expand("~/.local/state/wsx/worktrees/")
local added_path = nil
local in_flight = false
local function magenta_sidebar_visible()
for _, win in ipairs(vim.api.nvim_list_wins()) do
local name = vim.api.nvim_buf_get_name(vim.api.nvim_win_get_buf(win))
if name:find("Magenta Input", 1, true) then return true end
end
return false
end
local function wsx_context()
if in_flight then return end
if not vim.startswith(vim.fn.getcwd(), worktrees) then return end
in_flight = true
vim.system({ "wsx", "context", "write" }, { text = true }, function(out)
in_flight = false
if out.code ~= 0 then return end
local path = vim.trim(out.stdout)
if path == "" or path == added_path then return end
vim.schedule(function()
if magenta_sidebar_visible() then
vim.cmd("Magenta context-files " .. vim.fn.fnameescape(path))
added_path = path
end
end)
end)
end
vim.api.nvim_create_autocmd({ "VimEnter", "FocusGained" }, { callback = wsx_context })
-- Attach when magenta's input buffer appears in a window: covers opening the
-- sidebar and starting a new thread, so no manual :WsxContext is needed.
vim.api.nvim_create_autocmd("BufWinEnter", {
callback = function(ev)
if vim.api.nvim_buf_get_name(ev.buf):find("Magenta Input", 1, true) then
added_path = nil
wsx_context()
end
end,
})
vim.api.nvim_create_user_command("WsxContext", function()
added_path = nil
wsx_context()
end, {})
How it maps onto the contract:
- Refresh policy: the file is rewritten on every
VimEnterandFocusGained, with an in-flight guard so rapid focus events do not overlap. The cwd check keeps it inert outside wsx worktrees. - Context mechanism: the path is added to magenta once per path, and
only when the sidebar is already open, because
:Magenta context-filesforce-opens the sidebar otherwise. TheBufWinEnterhook fires when magenta's input buffer appears, so opening the sidebar or starting a new thread (magenta context is per thread) attaches the digest without a focus round-trip. A changed path (workspace rename) is re-added automatically. Later rewrites reach the agent on their own, since magenta diffs tracked files before each request. :WsxContextforces a rewrite and re-add as a manual fallback.
If $XDG_STATE_HOME is set, change the worktrees path to match.
Other editors
Any editor agent that can read a file on disk can use the digest. To add one:
- Run
wsx context writeon the editor's start and focus events (and when its chat panel opens), guarded against overlap. - Ignore a non-zero exit; that is the "not a wsx worktree" signal.
- Hand the printed path to the agent through whatever context mechanism the editor has: a context-file API, a rules file that instructs the agent to read the path, or re-adding the file after each refresh if the agent snapshots it.
- Leave the External instructions block to do the rest; it already tells the agent how to report back.
Nothing in the digest is editor-specific, and a second integration needs no change on the wsx side. Contributions of worked examples for other editors are welcome as sibling sections here.