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 status and git 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 VimEnter and FocusGained, 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-files force-opens the sidebar otherwise. The BufWinEnter hook 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.
  • :WsxContext forces 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:

  1. Run wsx context write on the editor's start and focus events (and when its chat panel opens), guarded against overlap.
  2. Ignore a non-zero exit; that is the "not a wsx worktree" signal.
  3. 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.
  4. 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.