Monitor coding agents, spin up git worktrees, jump between them, all from one place.
cogitator is a TUI dashboard for your harnesses. It gives you a live view of sessions and allows you to manage your worktrees:
- See status at a glance: discovers running instances, flagging which sessions need you (permission requests, pending questions, errors).
- Create git worktrees: spin up a new worktree for a branch, or fetch, pull, and delete existing ones, straight from the roster.
- Navigate into them: jump to a running agent or resume a stopped one in a tmux session (or window) with a single keystroke.
- Works across harnesses: opencode, Claude Code, Codex, and omp, with an optional Taskwarrior pane for your task list.
- Getting started
- Key bindings
- Configuration
- Taskwarrior integration
- Live attention reference
- CLI reference
- Logging
- Architecture overview
- Status mode
- Notes for macOS unsigned binaries
- Development
- Roadmap
- Automated — paste a prompt into the agent itself and let it do the setup.
- Manual — do the setup yourself, step by step.
| OS | Support |
|---|---|
| macOS | Supported |
| Linux | Supported |
| Windows | Not supported |
Go install:
go install github.com/guilhermehto/cogitator/cmd/cogitator@latestHomebrew:
brew install guilhermehto/tap/cogitatorcogitatoror from source:
go run ./cmd/cogitatorPick the harness you use below. You only need to do this once.
opencode advertises itself over mDNS and cogitator discovers it automatically. The only
setup is launching opencode with the --mdns flag, which could be added to your opencode alias.
Automated — paste this to your agent:
Add a shell alias named `ocm` to my shell startup file (~/.zshrc, ~/.bashrc, or whichever
my shell actually uses), defined as:
alias ocm='opencode --mdns'
Preserve the rest of the file. Then tell me to reload my shell (or open a new terminal)
and start opencode with `ocm` from now on so cogitator can see it.
Manual:
Launch opencode with --mdns so it advertises on _http._tcp.local.:
opencode --mdns # default port (random)
opencode serve --mdns --port 7777 # headless, fixed portYou can launch as many as you like; cogitator discovers them automatically.
cogitator displays live attention signals for Claude Code
sessions using Claude Code's lifecycle hooks. Monitoring auto-enables when
~/.claude/projects exists — no environment variable needed.
Automated — paste this to Claude Code:
Set up cogitator live-attention monitoring for Claude Code on this machine.
1. Run `which cogitator` to find the absolute path to the cogitator binary. If it is not
found, stop and tell me to install cogitator first.
2. Open ~/.claude/settings.json, creating it if it does not exist. Preserve every existing
top-level key.
3. Merge the hooks below into the `hooks` object. Replace the bare command `cogitator`
with the absolute path you found in step 1 (the hook runner may not inherit my
interactive PATH):
{
"hooks": {
"SessionStart": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"PreToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"PostToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"Stop": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"Notification": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ],
"SessionEnd": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ]
}
}
4. Save the file and tell me to restart Claude Code so the hooks take effect.
Manual:
-
Confirm
~/.claude/projectsexists (it does once you've run Claude Code at least once). -
Wire the hooks in
~/.claude/settings.json— cogitator does not write this file, so paste the block yourself:{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "PreToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "PostToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "Notification": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ], "SessionEnd": [ { "hooks": [ { "type": "command", "command": "cogitator claude-hook" } ] } ] } } -
Restart Claude Code. Hooks take effect on the next session.
PATH note: the hook runner may not inherit your interactive shell PATH. If
cogitatoris not found, replace"cogitator claude-hook"with its absolute path — e.g."/Users/you/go/bin/cogitator claude-hook"(usewhich cogitatorto find it).
See Live attention reference → Claude Code for how it behaves.
cogitator displays live attention signals for Codex sessions
using Codex's lifecycle hooks. Monitoring auto-enables when ~/.codex exists — no
environment variable needed.
Automated — paste this to Codex:
Set up cogitator live-attention monitoring for Codex on this machine.
1. Run `which cogitator` to find the absolute path to the cogitator binary. If it is not
found, stop and tell me to install cogitator first.
2. Open ~/.codex/hooks.json, creating it if it does not exist. Preserve any existing keys.
3. Merge the hooks below into the `hooks` object. Replace the bare command `cogitator`
with the absolute path you found in step 1:
{
"hooks": {
"SessionStart": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ],
"UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ],
"PreToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ],
"PostToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ],
"PermissionRequest": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ],
"Stop": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ]
}
}
4. Save the file, then remind me to start `codex`, run `/hooks`, and confirm trust for
`cogitator codex-hook` — Codex skips untrusted hooks silently.
Manual:
-
Confirm
~/.codexexists (it does once Codex is installed). -
Wire the hooks in
~/.codex/hooks.json:{ "hooks": { "SessionStart": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ], "UserPromptSubmit": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ], "PreToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ], "PostToolUse": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ], "PermissionRequest": [ { "matcher": "*", "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ], "Stop": [ { "hooks": [ { "type": "command", "command": "cogitator codex-hook" } ] } ] } } -
Trust the hook: start
codex, run/hooks, and confirm trust forcogitator codex-hook. Until trusted, Codex skips the hook silently.
See docs/codex.md for the full setup guide (inline TOML alternative,
minimal hook variant, and CODEX_HOME override), and
Live attention reference → Codex for how it behaves.
cogitator displays live attention signals for Oh My Pi (omp)
sessions. Monitoring auto-enables when the omp agent directory (~/.omp/agent,
or $PI_CODING_AGENT_DIR / $PI_CONFIG_DIR/agent) exists — no environment variable
needed. omp sessions then appear in the Sessions pane from a filesystem poll alone.
omp has no external command-hook like Codex/Claude (its hooks are in-process TypeScript modules), so live attention is wired through a small extension cogitator ships (embedded in the binary). Install it with one command:
cogitator omp-hook installThis writes ~/.omp/agent/extensions/cogitator.ts with the absolute cogitator
binary path baked in, so it works even when cogitator is not on the omp process
PATH. Restart omp afterward.
Automated — paste this to omp:
Set up cogitator live-attention monitoring for omp on this machine.
1. Run `which cogitator` to confirm cogitator is installed. If it is not found, stop
and tell me to install cogitator first.
2. Run `cogitator omp-hook install` — it writes the live-attention extension into
~/.omp/agent/extensions/ with the cogitator binary path baked in.
3. Tell me to restart omp so the extension loads.
Manual (repo checkout): copy internal/omp/cogitator.ts to
~/.omp/agent/extensions/cogitator.ts (user-level) or <repo>/.omp/extensions/cogitator.ts
(project-level). With a manual copy the extension spawns cogitator by name, so ensure
which cogitator resolves in the shell that launches omp; the installer avoids this by
baking in the absolute path.
See docs/omp.md for the full setup guide and the event→attention mapping, and Live attention reference → omp for how it behaves.
| Key | Context | Action |
|---|---|---|
T |
anywhere (outside a prompt) | show or hide the Tasks pane |
ctrl+P |
anywhere (outside a prompt) | open the session switcher: fuzzy-find a repo/branch and jump to it (cmd+P is not supported — terminals don't forward it to TUI apps) |
Tab |
anywhere (outside a prompt) | swap focus between Sessions and Tasks panes when Tasks is shown |
j / k |
Tasks pane focused | move cursor down / up |
a |
Tasks pane focused | open inline prompt to add a new task |
e |
Tasks pane focused | open inline prompt to edit the selected task |
s |
Tasks pane focused | start the selected task, or stop it if already running |
d |
Tasks pane focused | mark the selected task done |
D |
Tasks pane focused | prompt to delete the selected task (confirm with y) |
U |
Tasks pane focused | undo the last Taskwarrior mutation |
a |
Sessions pane focused | toggle collapsed/expanded recent sessions |
P |
Sessions pane focused | pull latest into the highlighted worktree's branch (git pull --ff-only --no-tags origin <branch>); handy for refreshing a base branch before branching off it |
Esc |
inside add/edit prompt | cancel the prompt without quitting |
Enter |
inside add/edit prompt | submit the prompt |
Note:
Tabinside the inline add/edit prompt is consumed by the text input widget (cursor movement / suggestion acceptance is disabled, so Tab does nothing there). UseEscto cancel the prompt without quitting.
cogitator persists durable settings as JSON at $XDG_CONFIG_HOME/cogitator/config.json
(or ~/.config/cogitator/config.json when $XDG_CONFIG_HOME is unset). The file is
created on first use and is safe to edit by hand. launchMode and defaultHarness have
no in-app setter, so editing this file is the only way to change them.
{
"repos": [
"/Users/you/src/cogitator",
"/Users/you/src/another-project"
],
"defaultHarness": "opencode",
"launchMode": "session"
}| Field | Type | Default | Description |
|---|---|---|---|
repos |
string array | [] |
Absolute paths to the git repositories cogitator tracks for worktree launching. Normally managed from the UI — press A in the Sessions pane to fuzzy-find and add a repo — so entries usually appear here without hand-editing. Paths are canonicalized; a configured repo missing from disk is still listed but its worktree actions are disabled. |
defaultHarness |
string | opencode |
Harness pre-selected when you create a new worktree (n). One of opencode, claude-code, codex, omp. Empty falls back to opencode. |
launchMode |
string | session |
How a worktree opens in tmux: window or session. Empty or any unrecognized value falls back to session. |
launchMode controls how launching or jumping to a worktree places it in tmux:
session(default) — opens each worktree as its own new tmux session. Each worktree is isolated with its own window list; switch with tmux's session switcher (prefix+s) or cogitator's own switcher (ctrl+P). Best when you prefer one session per task or branch.window— opens each worktree as a new window in your current tmux session. Worktrees stay grouped under one session; move between them with your usual tmux window keys (prefix+ number /n/p). Best when you run cogitator inside an existing tmux session and want everything in one place.
Either way, cogitator reuses an existing window/session for a worktree when one is already
open instead of creating a duplicate. Edits to launchMode take effect on the next launch —
no restart needed.
cogitator displays a live Tasks pane alongside the Sessions pane when a
task binary is found on the cogitator process's $PATH.
Requirements:
- A
task(Taskwarrior) binary must be reachable on the$PATHof the process that runs cogitator. No configuration flag is needed.
Auto-detection:
- cogitator checks for
taskat startup. If the binary is present the Tasks pane is shown by default; if not, the pane is hidden and no error is surfaced. - Press
Tto hide or show the Tasks pane while cogitator is running. There is no--no-tasksflag.
Visual indicators:
- The
STcolumn shows a priority glyph (high / medium / low) for idle tasks. - A running task (one started via
sortask <id> start) is rendered bold green with a play glyph () in theSTcolumn, replacing the priority glyph for that row. Presssagain to stop it. The legend at the bottom of the TUI lists each glyph.
Environment variables:
cogitator inherits the full environment of the process that launched it. Taskwarrior respects the following variables from that environment:
| Variable | Effect |
|---|---|
$PATH |
must include the directory containing the task binary |
$TASKDATA |
overrides the Taskwarrior data directory (~/.task by default) |
$TASKRC |
overrides the Taskwarrior config file (~/.taskrc by default) |
Setup for each harness lives in Getting started → Connect your coding agent. This section explains how live attention behaves once it's wired up.
cogitator subscribes to Claude Code's lifecycle hooks to track each session's attention
state. Monitoring is auto-enabled when ~/.claude/projects exists.
If cogitator is not running when a hook fires, cogitator claude-hook exits 0 silently —
Claude Code shows no failure and never blocks your tool calls.
cogitator subscribes to Codex's lifecycle hooks. Each event maps to an attention state:
| Event | Attention state |
|---|---|
SessionStart |
active |
UserPromptSubmit |
active |
PreToolUse / PostToolUse |
active |
PermissionRequest |
permission-pending |
Stop |
idle / awaiting |
Hooks are enabled by default in Codex (codex features list | grep hooks). PreToolUse
and PostToolUse fire on every tool call; for less process churn, wire only
SessionStart, PermissionRequest, and Stop (see the minimal variant in
docs/codex.md). If cogitator is not running when a hook fires,
cogitator codex-hook exits 0 silently — Codex shows no failure and never blocks your
tool calls.
cogitator polls ~/.omp/agent/sessions/**/*.jsonl so omp sessions appear with a
recency-derived liveness label without any setup. The shipped extension
(extensions/cogitator.ts) adds real-time attention by forwarding lifecycle events
over cogitator omp-hook:
| omp event | Attention state |
|---|---|
session_start / turn_start / agent_start |
active |
tool_call (tool ask) |
question-pending |
tool_result (error) |
errored |
turn_end / agent_end / session_shutdown |
idle / awaiting |
omp does not expose a permission-request hook event, so there is no distinct
permission-pending state for omp — the ask tool surfaces as question-pending. If
cogitator is not running, the extension's spawn fails silently and cogitator omp-hook
exits 0 — omp shows no failure and never blocks your turns.
--bell: ring the terminal bell when a session transitions into an attention state.--status: print a one-shot icons-only status line and exit.--demo: launch the TUI with a curated synthetic snapshot (mixed session states, tasks, a running task). No mDNS, notaskshell-outs; intended for screenshots and walkthroughs.--debug: show diagnostic UI elements that are noisy during normal use (e.g. the unreachable-instance footer).--log-level: set log verbosity (debug|info|warn|error). Default isinfo.--version: print module version, commit, and build date.
Logs are written with log/slog text formatting.
- If
$XDG_STATE_HOMEis set:$XDG_STATE_HOME/cogitator/cogitator.log - Otherwise:
/tmp/cogitator.log
internal/discovery: mDNS browsing and add/remove events for opencode instances.internal/supervisor: per-instance lifecycle (permissions poll, recency poll, SSE loop, reconnect backoff).internal/oc: HTTP + SSE API access and generated OpenAPI-derived core types.internal/state: in-memory aggregation and dedupe across instances, attention classification, unreachable-instance tracking.internal/ui: Bubble Tea model, rendering, status mode, and footer warnings.internal/config: single source of timing/threshold defaults.
--status runs discovery/supervision without opening the TUI and prints a compact status line.
It exits when either:
- a non-empty snapshot arrives, or
- the status deadline is reached (default: 3s).
Current releases are unsigned. If Gatekeeper blocks first launch, either use Finder "Open" once, or clear quarantine:
xattr -d com.apple.quarantine cogitatorCommon local targets:
make vet
make lint
make test
make ciOpenAPI workflow:
make capture-schema
make generate- macOS code signing + notarization (blocked on Apple Developer Program enrolment).
- OpenAPI-derived SSE event payload types (blocked on opencode publishing the event-stream schema).
