Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ concurrency:

jobs:
test:
runs-on: ubuntu-latest
# ubuntu-latest moved to 26.04, which has no Python 3.9 build.
runs-on: ubuntu-24.04
strategy:
matrix:
python-version: ["3.9", "3.11"]
Expand Down
68 changes: 68 additions & 0 deletions README.org
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,74 @@ default: it reads the pane's child process, not
call every working agent dead. =--fast= skips it and says so.
Read-only throughout --- nothing submits, cancels or writes.

*** Which sessions need you

=sucoder sessions= says whether an agent process is running; it cannot
say whether the agent is working or sitting at a permission prompt.
With

#+begin_src yaml
attention:
hooks: true
#+end_src

each SuCoder-launched Claude session gets hooks (=claude --settings=,
added to your own) that write a small status record to
=~/.sucoder/attention/<mirror>--<target>.rec= wherever the agent runs, on
every prompt, tool call, finished turn, permission request and idle
prompt. A launch whose command already passes =--settings= is left
alone.

Codex launches get the same records from Codex's own hooks, passed as
=-c hooks.<Event>=...= overrides; the key travels in
=SUCODER_ATTENTION_KEY=. Codex runs such hooks only once trusted: the
first hooked Codex launch on each account (vantage's agent account, your
Savio account) opens a "Hooks need review" screen; choose "Trust all and
continue". The trust lasts until a SuCoder release changes the hooks.
Codex has no idle notification, so a Codex turn idle for a minute is
reported as waiting (kind =idle=), as Claude reports itself. Other
harnesses are not covered.

#+begin_src sh
sucoder attention # list: waiting first, longest-waiting first
sucoder attention --cached # the watcher's last pass; never connects
sucoder attention --local-only # this host's agent account only
sucoder attention --watch 30 # dashboard; refreshes the cache, notifies
sucoder attention --tmux # one line from the cache, for status-right
#+end_src

A session with no record (launched before =attention.hooks= was on, or
by a harness without hooks) is still listed, as =untracked=: running,
state unknown. Local ones are found in the process table, cluster ones
by =squeue= in the same round trip as the records. Restart such a
session through SuCoder to track it.

=--watch= uses warm connections only and never prompts, so it can run
unattended in a tmux window beside the tunnel keeper. It writes
=~/.sucoder/attention.json=, which =--tmux= reads without loading any
configuration:

#+begin_src conf
set -g status-interval 10
set -g status-right '#(sucoder attention --tmux)'
#+end_src

=attention.notify_command= (a command string or argv list) runs once
for each request a session starts waiting on, with the session described
in =SUCODER_ATTENTION_KEY=, =_MIRROR=, =_TARGET=, =_HOST=, =_STATE=,
=_KIND=, =_AGE= and =_MESSAGE=, for example to post to an ntfy topic on
your phone. A request's kind is =permission=, =question=, =idle= (the
turn finished a minute ago) or =other=; =attention.notify_kinds= picks
which notify (default all) and =attention.notify_after_minutes= how long
one must wait first (default 0). =examples/coordinator/attention-notify=
is a ready notifier for ntfy and for a coordinator session.

On the agent account, with =session_relay=, =attention= and =--cached=
run as the relay's user (=sucoder relay attention=), like =sessions=;
=--watch= and =--cache= are refused there. A coordinator agent that
triages waiting sessions and suggests replies: =examples/coordinator/=.
Design and open items: [[file:docs/attention.org][docs/attention.org]].

*** Listing and retiring WIP snapshots

=sucoder snapshots= lists every WIP snapshot ref on every configured
Expand Down
15 changes: 15 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,21 @@ system_prompt: /home/<your-username>/.sucoder/system_prompt.org
# user: <your-username>
# command: /usr/local/bin/sucoder

# Attention (optional; off by default): SuCoder-launched Claude and Codex
# sessions write a status record (~/.sucoder/attention/<mirror>--<target>.rec
# where the agent runs) on every turn, permission request and idle prompt;
# `sucoder attention` lists the sessions waiting on you first. Codex asks once per account to
# trust the hooks ("Hooks need review": trust all). `notify_command` runs under
# `sucoder attention --watch` when a session starts waiting, with the session in
# SUCODER_ATTENTION_* environment variables. notify_kinds (default all of
# permission, question, idle, other) and notify_after_minutes (default 0) limit
# which requests notify. README: Which sessions need you.
# attention:
# hooks: true
# notify_kinds: [permission, question]
# notify_after_minutes: 2
# notify_command: ["sh", "-c", 'curl -fsS -d "$SUCODER_ATTENTION_MIRROR: $SUCODER_ATTENTION_MESSAGE" https://ntfy.sh/<private-topic>']

# Codex remote control (optional; ordinary terminal launch by default).
# Applies when Codex is selected, including --agent codex / --harness codex.
# Per-mirror agent_launcher.codex_remote_control overrides this default.
Expand Down
Loading
Loading