Skip to content

Track agent busy vs command-prompt idle for gjc project status #24

Description

@Cheol-H-Jeong

Desired UX

For a project running an agent in the main pane:

  • while the agent is coding / executing / waiting on subagents or tools: show the running spinner next to the project name,
  • when the agent returns to the command input prompt and is no longer working: show the green checkmark (done) until the user acknowledges it by visiting the window,
  • after acknowledgement, clear back to idle.

Concrete current case:

  • Project: nomadamas-code
  • Window: nmux-linux:3
  • Main pane: %277, title π: nomadamas-code
  • Main pane process tree contains:
gjc --resume 019f4e18-3b38-7000-87e7-e18fccd4570a

During inspection the pane was not at a finished command prompt; it was actively waiting on an architect subagent:

Await Architect pass-2 review.

A 3-second sample showed the gjc process burning CPU:

gjc delta after 3s: 93 ticks

So this should be classified as running, not idle.

Why it does not work today

There are two separate problems.

1. gjc is not registered as an agent binary

The watcher status pipeline is gated by AGENT_BINS:

const AGENT_BINS = new Set(['claude', 'codex', 'omx', 'gemini', 'aider', 'continue', 'cursor']);

Because gjc is absent, the watcher sees the main pane process tree but classifies it as having no agent:

PANE %277 root 3565692 title π: nomadamas-code detected_agents []
 gjc_desc [('1302720', 'gjc --resume 019f4e18-3b38-7000-87e7-e18fccd4570a')]

Once agents=[], the watcher does not sample gjc CPU as agent work and also skips PTY/output activity attribution, because the PTY path is guarded by if (agents.length).

Result: @nmuxlinux_status=running is never refreshed for gjc, and the sidebar shows idle.

This overlaps with issue #23, but it is only the first layer.

2. The current state machine detects activity, not "returned to command prompt"

Even after adding gjc to AGENT_BINS, the current watcher cannot reliably implement the desired UX because it does not know whether the agent has returned to its command prompt.

Current watcher semantics are heuristic:

// active if CPU delta on any known agent pid >= CPU_ACTIVE_THRESHOLD
// OR pane PTY mtime advanced this tick
const CPU_ACTIVE_THRESHOLD = 60;
const QUIET_TICKS_TO_DONE = 4; // about 12 seconds

Then:

if (active) {
  setWindowStatus(target, 'running', ...);
} else if (curStatus === 'running' && quietTicks >= QUIET_TICKS_TO_DONE) {
  setWindowStatus(target, 'done', ...);
}

That means done currently means "the watcher saw no attributed CPU/output for about 12 seconds after a previous running state." It does not mean "the agent returned to the command input prompt."

This distinction matters:

  • A long model call can be genuinely running but produce no PTY output for more than 12 seconds.
  • A tool/subagent await can be genuinely running with intermittent output or CPU.
  • A daemon-like agent can stay alive after returning to prompt.
  • A process can be quiet for reasons unrelated to completion.
  • If the row is already idle because the agent was never recognized, the quiet path does not promote it to done; it only transitions running -> done.

So the desired transition is prompt-state based, but the implementation is silence/activity based.

Hook/integration gap

nmux-linux has a hook-based path for some tools:

nmux-linux notify-current --status running|done|failed|need-input

The Claude hook installer currently wires:

UserPromptSubmit -> running
Notification     -> need-input
SubagentStop     -> done
Stop             -> done

But there is no equivalent gjc integration that emits:

  • work started / prompt submitted -> running,
  • command finished and prompt is back -> done,
  • user input needed -> need-input,
  • failure -> failed.

Without either native gjc hooks or a prompt-state detector, nmux-linux can only infer status from CPU and PTY quietness.

Expected behavior

For gjc in the main pane:

  1. When the user submits a prompt or gjc starts executing work, project status becomes running.
  2. While gjc is actively working, awaiting a subagent, awaiting a tool, or streaming output, status stays running.
  3. When gjc returns to its command input prompt (Type your message...) and no work is in flight, status becomes done.
  4. Visiting the project window acknowledges the checkmark and clears status back to idle.
  5. Sub panes do not need to drive this indicator.

Suggested implementation direction

Implement this as a real agent-state integration, not only as a process-existence check.

Minimum fixes:

  1. Add gjc to the shared agent binary registry so watcher attribution works:
const AGENT_BINS = new Set(['gjc', 'claude', 'codex', 'omx', 'gemini', 'aider', 'continue', 'cursor']);
  1. Add a gjc-specific completion signal or prompt-state detector. Possible approaches:
  • preferred: wire gjc lifecycle hooks, if available, to call nmux-linux notify-current,
  • alternatively: detect the main pane prompt state from pane content, e.g. visible Type your message... with no active task/subagent markers,
  • alternatively: support an explicit gjc status file/socket/event stream if GJC exposes one.
  1. Keep CPU/PTY watcher as a fallback, but do not treat quietness as equivalent to prompt-ready completion when a stronger agent signal exists.

Acceptance criteria

  • Main-pane gjc / gjc --resume <id> is recognized as an agent.
  • While gjc is awaiting subagents/tools or otherwise executing, sidebar shows the running spinner.
  • When gjc returns to command input prompt, sidebar shows done / green checkmark.
  • Visiting the window clears the checkmark back to idle.
  • A long silent model call does not falsely become done merely because there was no PTY output for 12 seconds.
  • Sub panes do not drive this status.
  • Existing stale-running protection remains intact for crashed watcher / abandoned tmux options.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions