Skip to content

Activity Detection

Kangentic monitors each agent’s activity in real-time, so you always know what your agents are doing without opening their terminals. All eleven supported agents (Claude Code, Codex CLI, Gemini CLI, Qwen Code, Kimi Code, OpenCode, Factory Droid, Cursor CLI, GitHub Copilot CLI, Aider, and Warp/Oz CLI) feed into a single activity state machine that drives the card indicators, but each uses a different underlying strategy because each CLI exposes activity differently.

The Kanban board shows each agent’s current state with visual indicators. These update in real-time, giving you an at-a-glance view of your entire agent fleet.

StateDescription
Thinking (pulsing animation)Agent is processing, running tools, or generating a response
Idle (static icon)Agent has stopped, hit a permission prompt, or is asking a question
Queued (label)Waiting for a concurrent session slot to open

Kangentic tracks these events from each agent session. They feed into both the card indicators and the Activity Tab in the bottom panel.

EventKeyEffect on IndicatorDescription
Tool starttool_startThinkingAgent began using a tool (Read, Edit, Bash, etc.)
Tool endtool_end(no change)Tool execution completed
PromptpromptThinkingUser submitted a message or the agent resumed after approval
IdleidleIdleAgent stopped, hit a permission wall, or asked a question
InterruptedinterruptedIdleUser interrupted the agent (Escape or interrupt signal)

These events are logged but don’t directly change the card indicator - they support subagent tracking, context management, and system-level operations. Not every agent emits every event (see per-agent strategies below).

EventKeyEffect on IndicatorEmitted byDescription
Session startsession_start(no change)AllSession was created or resumed
Session endsession_end(no change)AllSession exited
Notificationnotification(no change)Claude, GeminiInformational message from the agent (e.g., “context getting full”)
CompactcompactThinkingClaude, GeminiContext compaction occurred
Subagent startsubagent_startThinkingClaudeA subagent was spawned (increases depth counter)
Subagent stopsubagent_stop(no change)ClaudeA subagent finished (decreases depth counter)
Teammate idleteammate_idle(no change)KangenticAnother agent in the same project went idle
Task completedtask_completed(no change)KangenticA task was marked complete
Config changeconfig_change(no change)KangenticA configuration setting was modified
Worktree createworktree_createThinkingKangenticA git worktree was created
Worktree removeworktree_remove(no change)KangenticA git worktree was removed
Background shell startbackground_shell_startThinkingClaudeAgent launched a backgrounded Bash tool. Kangentic tracks the detached child so the session isn’t falsely flagged idle while it’s still running.
Background shell endbackground_shell_end(no change)ClaudeA tracked background shell exited. Releases a deferred idle when the last background child finishes.

Kangentic uses a different detection strategy for each agent because each CLI exposes activity differently. All eleven strategies feed into the same unified state machine, so card indicators behave identically regardless of which agent is running.

AgentStrategy
Claude CodeHooks only
Codex CLIPTY silence timer
Gemini CLIHooks primary, PTY fallback
Qwen CodeHooks (BeforeModel / AfterModel / BeforeToolSelection) primary, PTY fallback
Kimi CodeWire-protocol JSONL primary, PTY fallback
OpenCodePlugin events primary (tool.execute.before/after, session.idle), PTY fallback
Factory DroidPTY silence timer + cursor-hide first-output marker
Cursor CLIPTY silence timer + stream-JSON init event for session ID
GitHub Copilot CLIHooks primary, PTY fallback
AiderPTY prompt regex
Warp (Oz CLI)PTY silence timer

Claude Code’s native hooks system is the sole source of truth. Kangentic injects an event-bridge.js shim into the session that fires on Claude Code hook events and writes them to a structured log file that Kangentic watches incrementally.

Claude Code hookEffect
PreToolUseAgent is about to use a tool > thinking state
PostToolUseTool finished (no state change)
UserPromptSubmitUser sent a message > thinking state
StopAgent stopped naturally > idle state
PermissionRequestAgent needs approval > idle state
SubagentStart / SubagentStopTrack subagent nesting depth
Notification / PreCompactLogged as internal events
SessionStart / SessionEndLogged as internal events

Hook injection is automatic - no manual setup. All Kangentic artifacts stay in the .kangentic/ directory; nothing is written to your .claude/settings.local.json. Claude is the only agent Kangentic parses a status.json file for (context window percentage, token counts, cost, rate limits).

Codex’s Rust CLI (0.118+) does not read .codex/hooks.json at runtime, so Kangentic falls back to a pure PTY strategy: after each burst of terminal output, a 3-second silence timer marks the session idle. Content deduplication filters repeated TUI frames automatically so resize redraws don’t look like activity.

Codex’s prompt character stays visible even during tool execution, so a prompt regex can’t be used - the silence timer is the only reliable signal. Kangentic writes hook files anyway for structural compatibility, but the user-facing idle detection is the PTY timer.

Gemini CLI, hooks primary with PTY fallback

Section titled “Gemini CLI, hooks primary with PTY fallback”

Gemini supports hook injection via .gemini/settings.json (reference-counted so concurrent sessions don’t clobber each other). Hooks fire on BeforeAgent, AfterAgent, BeforeTool, AfterTool, SessionStart, SessionEnd, Notification, and PreCompress events.

If hooks don’t fire (e.g., early in startup or during a hang), a PTY-based fallback kicks in: Kangentic watches for Gemini’s closed-box TUI border (╰────╯) or the “I’m ready.” message to detect idle, backed by the same 3-second silence timer as Codex. Once hooks start firing, the PTY fallback defers to them.

Cursor’s terminal agent (agent) has no hooks and no status file. Activity detection is a PTY silence timer, same 3-second threshold as Codex and Warp. Kangentic spawns Cursor in non-interactive mode (agent -p ... --output-format stream-json) by default so the first line of NDJSON output is an init event containing the model and session ID. That event lets ContextBar resolve the model pill immediately and lets --resume=<id> work reliably across restarts. There is no subagent tracking and no compaction event.

GitHub Copilot CLI, hooks primary with PTY fallback

Section titled “GitHub Copilot CLI, hooks primary with PTY fallback”

Copilot (v1.0+) supports inline hooks written to a per-session config.json in the copilot-config/ directory beside the Kangentic events file. Kangentic wires preToolUse, postToolUse, agentStop, and preCompact hooks; these are the primary activity signal. A PTY silence timer backs them up because Copilot’s statusLine is best-effort (empirically it doesn’t always fire in ConPTY). Stream-output parsing picks up the model label either from the NDJSON stream when invoked with --output-format json or from the interactive TUI’s status bar.

Aider doesn’t support hook injection, so detection is pure PTY. Kangentic strips ANSI escapes from the output stream and matches a prompt regex at the end of the buffer:

/(?:^|\n)\s*(?:aider|architect)?>\s*$/

Any terminal output flips the session to thinking; a prompt match flips it back to idle. There is no subagent tracking, no status.json, and no compaction event. This is consistent with Aider’s edit-first, fire-and-forget design.

Warp’s oz CLI is the simplest adapter: no hooks, no status file, no structured event output, no trust mechanism, and no caller-specified session IDs. Activity detection is a PTY silence timer only. Unlike Codex and Cursor, there is no prompt regex, so the silence timer is the sole idle signal.

Qwen Code, hooks primary with PTY fallback

Section titled “Qwen Code, hooks primary with PTY fallback”

Qwen Code is a soft fork of Gemini CLI, so it inherits Gemini’s hook system in .qwen/settings.json. Hooks fire on BeforeModel, AfterModel, BeforeToolSelection, BeforeAgent, AfterAgent, SessionStart, and SessionEnd events - that’s a richer set than upstream Gemini, since Qwen distinguishes the model-call boundary from tool selection. Hook files are reference-counted across concurrent sessions in the same project. The PTY fallback is the same closed-box-TUI border + 3-second silence timer as Gemini.

Kimi Code, wire-protocol JSONL with PTY fallback

Section titled “Kimi Code, wire-protocol JSONL with PTY fallback”

Kimi emits a structured wire-protocol JSONL stream to ~/.kimi/sessions/<work_dir_hash>/<id>/wire.jsonl on every spawn. Kangentic watches the file incrementally for tool events, model start/end, plan markdown content, hook requests, and subagent lifecycle markers. The same stream feeds the ContextBar’s context-window percentage, token counts, and cost. PTY silence timer backs it up if the wire file is slow to flush.

OpenCode loads plugins from a project-shared .opencode/plugins/ directory at TUI startup. Kangentic copies an activity-stream plugin into that directory at spawn (refcounted across concurrent same-project sessions) so its tool.execute.before, tool.execute.after, event (for session.created / session.idle / session.error) callbacks fire and stream activity back to Kangentic. The plugin captures the native session ID (ses_<id>) from event.properties.info.id. A PTY silence timer covers the gap between plugin idle events.

Factory Droid, PTY silence + cursor-hide first-output

Section titled “Factory Droid, PTY silence + cursor-hide first-output”

Droid 0.109 ignores hooks injected through --settings, so Kangentic uses pure PTY detection: a 3-second silence timer for idle plus the \x1b[?25l cursor-hide marker for first usable output. Session UUIDs are captured from ~/.factory/sessions/<cwd-slug>/<id>.jsonl rather than stdout.

Droid does not stream live telemetry to Kangentic - /cost and /context are post-hoc TUI commands and the OTEL endpoint is out-of-band. The context bar shows a “Telemetry: TUI only” affordance instead of spinning forever; run those commands inside the Droid TUI to see model, token, and cost details.

The card indicators are designed to avoid false signals:

  • Tool end doesn’t set idle. Between consecutive tool calls there’s a brief gap - showing idle here would cause the spinner to flicker. For agents that emit explicit events (Claude, Gemini), only Stop or PermissionRequest sets idle.
  • Tool failure doesn’t set idle. The agent continues processing after a failure and may retry.
  • Notifications don’t change state. Informational notifications (like “context getting full”) fire unpredictably and shouldn’t flip the indicator.
  • Frame redraws don’t wake a session. For PTY-based agents, content-deduplication filters resize redraws so they don’t look like real activity.

Claude Code’s Agent tool lets a main agent spawn subagents to delegate work. Kangentic tracks the subagent depth from Claude’s SubagentStart / SubagentStop hook events so the card indicator stays accurate during nested operations:

  • If the main agent is idle but a subagent is still running tools, the card correctly stays idle - subagent tool events don’t override the main agent’s state
  • When all subagents finish and the main agent resumes, the card correctly shows thinking
  • Main-agent Stop is deferred until any running subagent finishes, so a pending user decision isn’t hidden
  • User prompts and interrupts always take effect immediately regardless of subagent state

The other agents either don’t expose subagents (Codex, Gemini, Cursor, Copilot, Aider, Warp, OpenCode, Droid) or surface them through their own JSONL stream (Kimi Code, via SubagentEvent envelopes in the wire protocol).

Background Shell Tracking (Claude Code only)

Section titled “Background Shell Tracking (Claude Code only)”

When Claude Code launches a backgrounded Bash tool (e.g., npm run dev &), the agent’s main loop returns to idle while the child process keeps running. Without tracking, Kangentic would flag the session idle the moment Bash returned even though work is still happening. The bg-shell watcher tracks each backgrounded child PID until it exits, deferring the idle transition until the last tracked child finishes. Two new event types - background_shell_start and background_shell_end - record this in the Activity Log.

For Claude Code, Codex, Gemini, Qwen Code, Kimi Code, OpenCode, and Factory Droid, Kangentic reads each agent’s own native session history file (in addition to the hook/PTY activity stream) to produce higher-fidelity telemetry: token-accurate context percentages, tool call transcripts, and the full conversation record used as the handoff context payload when a task moves between agents. Kangentic watches these files incrementally so the Activity Tab and context bar stay in sync without polling the CLI:

AgentNative history path
Claude Code~/.claude/projects/<sanitized-cwd>/<session-id>.jsonl
Codex CLI~/.codex/sessions/.../rollout-*.jsonl
Gemini CLI~/.gemini/tmp/<cwd>/chats/session-*.json
Qwen Code~/.qwen/tmp/<cwd>/chats/session-*.json
Kimi Code~/.kimi/sessions/<work_dir_hash>/<id>/wire.jsonl
OpenCode~/.local/share/opencode/storage/messages/<session-id>/...
Factory Droid~/.factory/sessions/<cwd-slug>/<session-id>.jsonl (parsed for the Transcript tab; no live telemetry)

Cursor, Copilot, Aider, and Warp don’t expose a file Kangentic can parse, so their context bar falls back to PTY-derived heuristics and handoff context is unavailable for those agents.

For agents that ship their own OAuth/credential flow, Kangentic probes the credentials directory at detection time and surfaces an amber warning when a fresh spawn would die at the auth wall. This shows up next to the agent’s entry in the Welcome screen and in the column / settings agent picker.

AgentProbe pathResolve by running
Kimi Code~/.kimi/credentials/kimi login
OpenCode~/.local/share/opencode/auth.jsonopencode auth login

The combination of activity detection and the Kanban layout gives you a dashboard view of all agent work:

  • See which agents are actively working vs. waiting for input
  • Identify stuck or idle agents that may need intervention
  • Monitor overall project progress at a glance
  • Know when agents finish without watching their terminals

When an agent goes idle, Kangentic can also notify you via desktop notifications and idle badges. See Notifications for details.

Next: Notifications & Monitoring - desktop alerts and idle badges driven by activity state.

See also: