Files
Worktrunk Bot a6f26e5c6a docs(agents): document the activity-marker contract for agent CLIs without a plugin (#3848)
## Problem

#3847 asks for a documented "generic agent" integration: worktrunk ships
plugins for Claude Code, Codex, OpenCode, and Gemini, so users of any
other agent CLI have no documented way to get the 🤖/💬 activity markers
in `wt list`. The mechanism is already agent-agnostic — the plugins just
call `wt config state marker` on their host's session events — but the
docs only present manual markers as a personal-workflow convenience, so
users reverse-engineer the integration from that section. #3571 (pi /
oh-my-pi) is the same gap from a different host.

## Solution

A new **Agent CLIs without a plugin** subsection under Activity tracking
in
[`docs/content/claude-code.md`](https://github.com/max-sixty/worktrunk/blob/main/docs/content/claude-code.md),
stating the three-call contract (set 🤖 on session start, set 💬 on turn
end, clear on session end) plus the three things that actually bite:

- the command resolves the branch from its working directory, so the
hook must run inside the worktree (`--branch` where the host pins cwd
elsewhere);
- `marker set` exits non-zero outside a repository, and hosts differ on
what a non-zero hook does — guard it;
- pair every set with a clear, and expect a stale marker if the process
is killed first.

Docs-only. The skill and plugin-skill mirrors are regenerated by the
sync test.

## Testing

`cargo test --test integration test_docs_are_in_sync` passes (it
regenerated both mirrors, committed here).

Each claim in the section was verified against a scratch repo with a
linked worktree rather than taken from the existing prose:

<details><summary>Verification</summary>

```
$ wt config state marker set "🤖"          # from /tmp/mrepo.feature-x
✓ Set marker for feature-x to 🤖
$ git config --get worktrunk.state.feature-x.marker
{"marker":"🤖","set_at":1787044121}
```

- Works from a subdirectory of the worktree (branch still resolves to
`feature-x`).
- Outside a repository: `✗ git rev-parse --git-common-dir failed (exit
128)`, exit code 1 — the basis for the "guard it" bullet.
- `marker clear` with no marker set exits 0 (`○ No marker set for
main`), so a session-end hook is safe to run unconditionally.
- `wt list` renders the marker in the Status column as documented.

</details>

## Scope

Deliberately host-agnostic. The reporter's second ask — a native `wt
config plugins copilot` target — is a maintainer call and isn't
attempted here: GitHub Copilot CLI does expose the needed events
(`sessionStart` / `agentStop` / `sessionEnd`, user-level hooks under
`~/.copilot/hooks/`, per the [hooks
reference](https://docs.github.com/en/copilot/reference/hooks-reference)),
but nothing in CI can drive a Copilot session to verify a generated hook
file end to end. A concrete Copilot config is posted on the issue for
the reporter to confirm; if it works, adding it here as a worked example
is a natural follow-up. #3594 (native `pi` target) is the adjacent
in-flight work and doesn't overlap with this.

---
Refs #3847 — automated triage

---------

Co-authored-by: worktrunk-bot <254187624+worktrunk-bot@users.noreply.github.com>
2026-08-18 08:52:15 -07:00

8.3 KiB
Raw Permalink Blame History

+++ title = "Agent Integration" description = "Worktrunk plugins for Claude Code, Codex, OpenCode, and Gemini CLI: a configuration skill, wt list activity tracking, and Claude-only worktree isolation." weight = 23

[extra] group = "Reference" +++

Worktrunk ships a plugin for each supported agent CLI. What a plugin provides depends on the hooks that CLI exposes:

Capability Claude Code Codex OpenCode Gemini CLI
Configuration skill ✓ ✓ ✓
Activity tracking (🤖/💬 in wt list) ✓ ✓ ✓ ✓
Worktree isolation ✓
/wt-switch-create command ✓

The configuration skill is documentation the agent reads to help set up LLM commits, hooks, and troubleshooting. Activity tracking shows which worktrees have running sessions. Worktree isolation needs worktree-lifecycle hooks and /wt-switch-create needs session working-directory switching — both Claude Code-only, so Codex, OpenCode, and Gemini users invoke wt switch --create and wt remove directly. Codex tracks activity through its own Stop and SessionEnd hooks.

Installation

Claude Code

{{ terminal(cmd="wt config plugins claude install") }}

Manual equivalent:

{{ terminal(cmd="claude plugin marketplace add max-sixty/worktrunk|||claude plugin install worktrunk@worktrunk") }}

Codex

{{ terminal(cmd="wt config plugins codex install") }}

This configures the Worktrunk marketplace in Codex. Then run /plugins in Codex and install Worktrunk from the marketplace. Manual equivalent:

{{ terminal(cmd="codex plugin marketplace add max-sixty/worktrunk") }}

To remove the marketplace entry, run wt config plugins codex uninstall. Already-installed plugins are left unchanged.

OpenCode

{{ terminal(cmd="wt config plugins opencode install") }}

This writes the activity-tracking plugin to OpenCode's global plugins directory, ~/.config/opencode/plugins/worktrunk.ts (honoring $OPENCODE_CONFIG_DIR and $XDG_CONFIG_HOME). wt config plugins opencode uninstall removes it.

Gemini CLI

{{ terminal(cmd="gemini extensions install https://github.com/max-sixty/worktrunk") }}

Gemini loads the extension natively from the repository, so there is no wt wrapper. gemini extensions uninstall worktrunk removes it.

Configuration skill

With the /worktrunk skill, the agent can help with:

  • Setting up LLM-generated commit messages
  • Adding project hooks (pre-start, pre-merge, pre-commit)
  • Configuring worktree path templates
  • Fixing shell integration issues

Claude Code is designed to load the skill automatically when it detects worktrunk-related questions.

Activity tracking

The Claude Code, Codex, OpenCode, and Gemini plugins track agent sessions with status markers in wt list:

{% terminal(cmd="wt list") %} wt list Branch Status HEAD± main↕ main…± Remote⇅ Path Commit Age Message @ main ^⇡ ⇡1 . 33323bc 1d Initial commit

  • feature-api ↑ 🤖 ↑1 +1 ../repo.feature-api 70343f0 1d Add REST API endpoints
  • review-ui ? ↑ 💬 ↑1 +1 ../repo.review-ui a585d6e 1d Add dashboard component
  • wip-docs ? – ../repo.wip-docs 33323bc 1d Initial commit

○ Showing 4 worktrees, 2 with changes, 2 ahead {% end %}

  • 🤖 — agent is working
  • 💬 — agent is waiting or idle

All four plugins clear the marker when a session ends. A stale marker can remain if the agent process is killed before its session-end hook runs. In every case, wt config state marker clear removes a marker manually.

Manual status markers

Set status markers manually for any workflow:

{% terminal() %} wt config state marker set "🚧" # Current branch wt config state marker set "✅" --branch feature # Specific branch git config worktrunk.state.feature.marker '{"marker":"💬","set_at":0}' # Direct {% end %}

Agent CLIs without a plugin

Activity tracking is not plugin-specific. The plugins above only call wt on their host's session events, and the marker itself is plain git config — so any CLI that can run a command on session lifecycle events drives the same 🤖/💬 markers with no worktrunk plugin:

Host event Command
Session starts, or the agent resumes work wt config state marker set "🤖"
Agent finishes a turn and waits for input wt config state marker set "💬"
Session ends wt config state marker clear

Three things to get right:

  • Run the command inside the worktree. Each one resolves the branch from its working directory, so a hook that runs elsewhere marks the wrong branch, and one that runs outside a repository fails. Where the host pins the working directory elsewhere, pass the global -C <worktree>, which moves both the repository lookup and the branch resolution; --branch <branch> names the branch but still needs the working directory to be inside the repository.
  • Don't let a failed marker call fail the session. Both set and clear exit non-zero outside a repository, and hosts differ on what a non-zero hook does. Append || true (or the host's equivalent) to every call unless you want that surfaced.
  • Clear on exit. A marker set on session start persists until something clears it, so pair every set with a clear on the host's session-end event — and expect the same stale marker as above if the process is killed first.

Worktree isolation (Claude Code only)

Claude Code agents can run in isolated worktrees (isolation: "worktree"). By default, Claude Code creates these with git worktree add. The plugin's WorktreeCreate and WorktreeRemove hooks route this through wt switch --create and wt remove instead, so worktrees created by agents get worktrunk's naming conventions, hooks, and lifecycle management.

/wt-switch-create command (Claude Code only)

/wt-switch-create [<branch>] [<repo>] [-- <task>] starts a task in a fresh worktree without leaving the session: it creates the worktree, switches into it, and runs the task (all arguments optional). The worktree shows up in wt list; merge or remove it with wt merge / wt remove.

Statusline (Claude Code only)

wt list statusline --format=claude-code outputs a single-line status for the Claude Code statusline. Claude Code runs it in the background, which is what makes the occasional 1–2 second CI fetch invisible.

~/w/myproject.feature-auth !🤖 @+42 -8 ↑3 ⇡1 #3035 Opus 🌔 65% 1.4×(10am–3pm)

Worktree state comes from the same cells wt list renders; Claude Code's stdin JSON adds the model, the 🌔 65% context gauge, and the rate-limit pace notice. wt list statusline documents every segment, how the links behave, and the JSON fields behind them.

Claude Code statusline demo

Add to ~/.claude/settings.json:

{
  "statusLine": {
    "type": "command",
    "command": "wt list statusline --format=claude-code"
  }
}