Skip to content

Agent Status

Documentation in progress

Some sections are still incomplete.

A Thread running a long task carries a live state, so you can tell at a glance which sessions need you without visiting each one. When a Thread you are not watching finishes, or starts waiting for a decision, a short sound plays.

The states are working, blocked (waiting on a user decision), and idle. A session ThinkTerm cannot classify is simply unmarked.

Detection is off by default and is enabled in settings.

How the state is decided

Three sources of evidence are consulted, strongest contract first.

1. The THINKTERM_AGENT variable. The program reports its own identity, session and state. This is the public protocol described below, and the only source that survives any redesign of the program's interface.

2. Screen rules. TOML manifests matched against the pane's visible output and its terminal title. The bundled rules come from the herdr project.

3. Native escape sequences. OSC 9;4 progress reports and the leading title-spinner marker. This is also all that is used when the feature is switched off.

Two arbitration rules matter, and they point in opposite directions on purpose:

  • A live process wins on identity. A foreground process that matches a manifest is the ground truth for what is running now. A reported variable is a message from the past and never overrides it — so a variable left behind by an exited program cannot mislabel whatever runs in that pane next.
  • The screen wins on state. Programs commonly miss the "user pressed Esc" and "prompt cancelled" transitions, and both end with the screen visibly idle. A matching screen rule therefore outranks a reported state.

Transitions inferred from the screen — out of blocked, and from working to idle — are debounced by roughly 450 ms, because a half-drawn frame must not replay a notification. States reported through the protocol skip the debounce: an explicit report is not a guess.

Reporting state from your own program

Write one escape sequence to your terminal whenever your state changes:

ESC ] 1337 ; SetUserVar=THINKTERM_AGENT=<base64(value)> BEL

From a shell:

sh
v="v1;agent=my-agent;state=working;session=$SESSION_ID;ts=$(date +%s)"
printf '\033]1337;SetUserVar=THINKTERM_AGENT=%s\007' \
  "$(printf %s "$v" | base64 | tr -d '\n')"

The sequence renders nothing and moves no cursor, so it is safe to interleave with full-screen output. It works over SSH and over ThinkTerm multiplexer domains — whichever terminal owns the pty parses it, and the value is mirrored across mux connections.

Value grammar, version 1

v1;agent=<id>;state=<working|idle|blocked>[;session=<id>][;pid=<n>][;ts=<unix-seconds>][;ended=1]
FieldMeaning
v1Grammar version. Unknown major versions are ignored entirely
agentRequired. A short stable identifier
stateRequired. working, idle or blocked. Anything else is treated as unknown and drives nothing
sessionYour own session id, reserved for session restore. May be empty
pidAccepted for forward compatibility; currently ignored
tsEmission time in unix seconds. See below
ended=1The session is over

Unknown keys are ignored, so the grammar can be extended without breaking older readers.

About ts. A non-idle report older than six hours stops counting as authoritative — panes on a server can outlive the sessions that wrote to them — and a timestamp more than five minutes in the future is treated the same way, so a fast clock cannot make a report permanently fresh. On panes where the process can never be observed (SSH, tmux and serial panes) that same six-hour window also retires the reported identity, since it is the only remaining signal that the program may have crashed without saying goodbye. If your session can legitimately sit non-idle for longer — an approval prompt left overnight — re-emit your current state periodically; any re-emission resets the window. Idle reports, and reports with no ts, are trusted indefinitely.

About ended=1. While your process is still the pane's foreground leader the flag is ignored: a live process outranks its own farewell. Once the process exits, the pane stops being classified.

When to send what. working when a turn starts, idle when you are ready for input, blocked the moment you display a prompt that needs an answer, and the appropriate state again when that prompt resolves — including when the user cancels or interrupts. A program that observes all of those transitions itself needs no screen rules at all.

Overriding a screen rule

A bundled manifest can be replaced by dropping your own into:

~/.config/thinkterm/agent-detection/

The id inside the file selects which bundled manifest it replaces; the filename is ignored. Reload the rules from the Agents panel afterwards.

One thing to know when writing rules: the title and progress regions see only what the program actually emitted. Both are empty until a title or progress report arrives, and they are cleared when the pane's program changes. Display fallbacks — a tab title derived from the process name, an assumed absence of progress — never reach the rules, so a rule like regex = ['\S'] on the title cannot match a pane whose program never spoke.

  • Command Linecli agent, and driving one pane from another