Monitor coding agents, spin up git worktrees, jump between them, all from one place.
▶︎ Watch the demo
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.
Table of contents
Getting started
- Automated — paste a prompt into the agent itself and let it do the setup.
- Manual — do the setup yourself, step by step.
1. Install
| OS |
Support |
| macOS |
Supported |
| Linux |
Supported |
| Windows |
Not supported |
Go install:
go install github.com/guilhermehto/cogitator/cmd/cogitator@latest
Homebrew:
brew install guilhermehto/tap/cogitator
2. Run cogitator
cogitator
or from source:
go run ./cmd/cogitator
3. Connect your coding agent
Pick the harness you use below. You only need to do this once.
opencode
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 port
You can launch as many as you like; cogitator discovers them automatically.
Claude Code
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/projects exists (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
cogitator is not found, replace "cogitator claude-hook" with its absolute path —
e.g. "/Users/you/go/bin/cogitator claude-hook" (use which cogitator to find it).
See Live attention reference → Claude Code for how it behaves.
Codex
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 ~/.codex exists (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 for
cogitator 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.
omp
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 install
This 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 bindings
| 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: Tab inside the inline add/edit prompt is consumed by the text
input widget (cursor movement / suggestion acceptance is disabled, so Tab
does nothing there). Use Esc to cancel the prompt without quitting.
Configuration
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. |
tmux window vs 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.
Taskwarrior integration
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 $PATH of the
process that runs cogitator. No configuration flag is needed.
Auto-detection:
- cogitator checks for
task at 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
T to hide or show the Tasks pane while cogitator is running. There is
no --no-tasks flag.
Visual indicators:
- The
ST column shows a priority glyph (high / medium / low) for idle tasks.
- A running task (one started via
s or task <id> start) is rendered bold
green with a play glyph () in the ST column, replacing the priority
glyph for that row. Press s again 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) |
Live attention reference
Setup for each harness lives in Getting started → Connect your coding agent.
This section explains how live attention behaves once it's wired up.
Claude Code
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.
Codex
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.
omp
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.
CLI reference
--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, no task shell-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 is info.
--version: print module version, commit, and build date.
Logging
Logs are written with log/slog text formatting.
- If
$XDG_STATE_HOME is set: $XDG_STATE_HOME/cogitator/cogitator.log
- Otherwise:
/tmp/cogitator.log
Architecture overview
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 mode
--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).
Notes for macOS unsigned binaries
Current releases are unsigned. If Gatekeeper blocks first launch, either use Finder "Open" once, or clear quarantine:
xattr -d com.apple.quarantine cogitator
Development
Common local targets:
make vet
make lint
make test
make ci
OpenAPI workflow:
make capture-schema
make generate
Roadmap
- macOS code signing + notarization (blocked on Apple Developer Program enrolment).
- OpenAPI-derived SSE event payload types (blocked on opencode publishing the event-stream schema).