Skip to content
Automation
Skill

/agent-activity

Streams what the agent is doing into the room, as rows the desktop client renders in an **events drawer** above the composer (collapsed: avatar, pulsing dots, the newest line rolling in; expanded: the live rows of the task in progress) and in the console dock's **Events** panel

From plugin
sutando
40179 skills18 hooks

Claude Code

$ npx -y skills add sonichi/sutando --skill agent-activity --agent claude-code

SKILL.md

agent-activity.SKILL.md

agent-activity

Streams what the agent is doing into the room, as rows the desktop client renders in an **events drawer** above the composer (collapsed: avatar, pulsing dots, the newest line rolling in; expanded: the live rows of the task in progress) and in the console dock's **Events** panel (the full history). Client side: ag2-space/cinny-webclient #888.

Rows

One JSON object per line at `<workspace>/state/agent-activity.jsonl`, served to the client by the loopback media route as `/media/state/agent-activity.jsonl`:

| field | meaning | |--------|---------| | `ts` | epoch seconds | | `room` | room id the row belongs to; the drawer in that room shows it. Absent → dock only for ordinary activity; only a roomless `wedge` is global | | `kind` | `processing` (picked the message up) · `thinking` (narration while deciding) · `working` (the tool in use, one line) · `notice` (PR heartbeats and the like) · `wedge` (**stopped: the owner has to act** — always written roomless, and it shows through a drawer the owner dismissed, because a blocker is not activity, it is why activity stopped) · `done` | | `line` | the text, plain | | `task` | `{id, from, text}` — the user message this row belongs to (`from` an mxid, `text` ≤160 chars) | | `done` | `true` closes the task: all of its rows leave the drawer (the dock keeps them) | | `task.event` | event id of the user message (`source_message_id`); the client mounts the per-message card under it | | `task.into` | on a consolidated `done`: event id of the message whose reply answered this one too | | `agent` | mxid of the agent the task is answered as, on a task a named lane queued (a pool worker's own agent, a secondary homeserver's); absent on every other row, which is the engine's own agent's | | `queue` | on the `queued` row only: `{depth, position}` — how many tasks are pending and this one's 1-based place in the order the core takes them (`src/task_queue.py`) |

A `notice` row reading `queued` is written by the task watcher when the file lands, before any turn has it (the activity bus's QUEUED transition; `activity.py queued --task-file …` is the same row by hand, only for files that name a room and a message). With at least one task ahead the line reads `queued · N ahead` and carries `queue`.

`python3 $S/activity.py queue --task-file <workspace>/tasks/task-….txt` prints that task's `{"depth": N, "position": K}` now. When more than one task is pending, the first line to the task's own conversation names the position ("Got it, right after the one I'm on." for one ahead, "Got it, N in line before this one." for more); nothing else narrates the queue. When `tasks/` cannot be read it prints nothing, says why on stderr and exits 1: the position is unknown then, not zero.

A task's rows are **live** until its `done` row; a task-less row is live 15 minutes. The drawer shows only live rows and hides itself when none is live. Rows are flat: the client marks the first row of each task with a square dot, never folds.

Writing rows

S=skills/agent-activity/scripts
python3 $S/activity.py append "picked up your message" --kind processing \
    --task-id task-… --from '@owner:server' --text "<their message>" [--room '!room:server']
python3 $S/activity.py append "PR #123 CI green" --kind notice
python3 $S/activity.py done "the drawer is one rolling line" --task-id task-…

Prefer `--task-file <workspace>/tasks/task-….txt`: it fills the task id, `from`, `text` and the room from the task's own headers, so a row is always tagged with the room the message came from. Without it, `--room` defaults to the room of the owner's latest s.space message (`state/last-owner-activity.json`). With the hook installed, `processing` and `done` are written for you (see below); hand-written rows are for anything extra the owner asks to see.

Working and Thinking rows, automatically (hooks)

The skill declares Claude Code hooks in `manifest.json` (`./hooks/activity-hook.py` on `PreToolUse`, `PostToolUse`, `Stop`, `UserPromptSubmit` and `PermissionRequest`); `bash src/install-claude-hooks.sh` registers them like every other skill hook. The hook never depends on the agent remembering anything:

  • **Processing, automatically.** The first `PreToolUse` in a session whose input names a task file

(`tasks/task-….txt`, a Read or a shell command) binds that task to the hook's own `session_id` in `state/agent-activity.sessions.json` and writes its `processing` row from the task's headers (room, sender, text). The agent's own `activity.py append --kind processing` still binds, for hand-written rows.

  • **Done, automatically.** A `PostToolUse` whose input wrote `results/task-….txt` (Write, or a shell

redirect) writes the task's `done` row, only from the session the task is bound to and only if the result file exists once the tool has run: a denied or failed write closes nothing.

  • **Working.** Every later `PreToolUse` in that session writes at most one `working` row for the open

task bound to it, in the task's room (the client shows a room's newest working row):

  • a call with a `description` writes its first sentence (100 characters), and never a phase; the step

line wins;

  • a call without one writes its rules phase word (`scripts/phase_line.py`, e.g. "Running tests"), when

the room does not show that phase already.

The phase model's refinement feeds the published task status only, never a room row.

  • **Thinking.** `Stop` reads the last assistant text of *this session's* `transcript_path`

(complete lines only, so a row mid-write is never split) and writes it as `thinking`.

  • **Turns.** Every event also folds into `state/agent-activity.turns.json`, keyed by the turn's

`prompt_id`: the tasks its prompt named (the watcher's `TASK_FILE:` lines), the dialog it is parked on (`PermissionRequest`), and its end (`Stop`). The hook stamps its tmux pane with the open turn (`@sutando_turn`), cleared by that turn's own `Stop`.

  • **Stop interrupt** (`SUTA
Read more
@sonichi
Ships withsutando

My AI Stand — Realtime by Day, Rewriting Itself by Night. Summon my AI superpower. Voice, vision, screen, meetings, calls when I'm engaged. Learns my patterns, ships its own code when I'm not. Runs across my Macs, interacts with people & their Stands.

Stars on GitHub

Momentum

stars in total
401
Star history of sonichi/sutando on GitHub, a chart by star-history.com

Other skills on sutando.

ag2space-voice

ag2space-voice

s.space voice surface — binds the room the s.space client announces to the voice session's origin, so work delegated by voice in…

@sonichi@sonichiInstall Skill
agent-registry

agent-registry

Local Agent Registry — a standalone, dependency-free service that tracks running Claude Code (and other) agent instances. Agents…

@sonichi@sonichiInstall Skill
agent-room-ops

agent-room-ops

For an all-room analysis sweep, use the tested window collector and coverage contract in…

@sonichi@sonichiInstall Skill
answer-format

answer-format

Deterministic final-answer normalizer — a last-step pass for any task that ends in a *precise* answer (a number, a short string,…

@sonichi@sonichiInstall Skill
audio-transcribe

audio-transcribe

Transcribes audio files and voice notes to text via Gemini 2.5-flash. Integrates with Slack, Discord, and Telegram bridges so…

@sonichi@sonichiInstall Skill
bee-actions

bee-actions

Act back on the owner's Bee wearable — the TOOL half of the Bee integration (channels-vs-tools split). The Bee CHANNEL…

@sonichi@sonichiInstall Skill

More skills from other plugins.

agent-builder

agent-builder

Load immediately after an Agent intent, before the first agent_builder_* call. Governs how you create, configure, test, and…

n8n12d209k
@n8n-io@n8n-ioInstall Skill
browser-use

browser-use

Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…

@browser-use@browser-useInstall Skill
agent-browser

agent-browser

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…

@vercel-labs-2@vercel-labs-2Install Skill
add-anydoc

add-anydoc

Add local office-document-to-Markdown conversion to NanoClaw agent containers with the pinned Firecrawl AnyDoc CLI. Use when…

@nanocoai@nanocoaiInstall Skill

Questions about agent-activity.

Which coding agents can use agent-activity?
agent-activity installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.