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
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ Self-hosted autonomous AI agent platform for a single owner, with a sandboxed wo

AgentStudio provides a streaming chat interface where the assistant can call tools such as web search and sandboxed code execution. The filesystem toolset supports ranged file reads, full writes, unified-diff patch apply, deterministic string replace, recursive directory listing, search, move/rename, delete, and file metadata lookups. Chat supports editing and branching, interleaved tool and thinking blocks, per-message performance and cost metrics, model selection, and per-prompt reasoning effort selection.

Shell commands render as a small terminal: the command, its output in a fixed-width font with colour codes cleaned out, the last 20 lines first with a control to show the rest, a copy button, and a badge for how it ended (such as `exit 2`). A command the agent runs in the background (a dev server, a long build) streams its output into that card while the turn runs, shows as a header chip with a stop button, and ends when the reply does; the card and the agent both say so. Deleting a conversation stops its running turn and those commands first. See [docs/chat/spec.md](docs/chat/spec.md#command-output).

Editing a message or regenerating a reply cuts the conversation back so the model sees only what was kept plus the message it is answering. In a project (or an agent with a persistent workspace) the agent's file changes are checkpointed every turn, and Edit and Regenerate offer to restore the files the dropped replies changed — showing the files and line counts first, and asking again before overwriting uncommitted changes in an imported repository. **Compact Conversation** runs the SDK's own `/compact`. See [docs/chat/chat.md](docs/chat/chat.md).

When the agent needs a decision it asks with the Agent SDK's own AskUserQuestion, shown as a question card: a header chip, option cards with a recommended badge, a sandboxed HTML preview of each option where one helps, multi-select, and a free-text "Other". It can be answered in the chat, from the composer, or from the /review inbox, and never answers itself. See [docs/chat/spec.md](docs/chat/spec.md#questions-from-the-agent).
Expand Down
42 changes: 41 additions & 1 deletion docs/chat/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,46 @@ Some questions say **Choose any that apply**: tick as many options as you like.

Transcripts from before the change keep their `ask_user` blocks, and those still show each question with its answer.

### Command output

When the agent runs a shell command, the reply shows it as a small terminal instead of a generic tool card. It looks the same while the turn runs and after a reload.

- The first line is the command. Below it is what the command printed, in a fixed-width font with its line breaks kept. Normal output and error output are shown separately; error output is red.
- Colour codes, terminal links, window titles and redrawn progress bars are cleaned out, so the text reads as plain text. A progress bar that redraws itself on one line shows only its last state (`100%`, not `10% 50% 100%`).
- Long output opens on its **last 20 lines**, because that is where a command says how it went. **Show all N lines** opens the rest and **Show last 20 lines** folds it back. **Copy output** always copies everything.
- The card opens on its own when there is output, when the command failed, or when it ran in the background.
- One badge says how it ended: `exit 2` for a command that failed with an exit code, `failed`, `interrupted`, `timed out`, or no badge for a command that succeeded. Claude Code only reports an exit code for a failed command and for a finished background command, so a successful ordinary command shows no badge rather than `exit 0`.
- Some commands use an exit code to mean something other than failure (for example, `grep` returns 1 when it finds nothing). When Claude Code explains the code ("No matches found"), the card shows the explanation.
- Each stream keeps its last 16,000 characters. When earlier output was cut, the card says so, and leaves out the first line of what is left: the cut lands mid-line, and can land in the middle of a colour code, which would otherwise show up as stray text like `[31m`.

### Background commands

The agent can start a command in the background, such as a dev server, a watcher or a long build, and keep working while it runs.

1. The command's card opens straight away with a **live** badge. What the command prints appears in the card about once a second. The card follows the newest line, unless you have scrolled up to read something.
2. A chip in the header shows each running background command, with a button to stop it.
3. When the command finishes, the badge changes to how it ended: its exit code (`exit 0`, `exit 2`), or `finished`, `failed` or `stopped`. A notice in the transcript says it finished.
4. **Background commands end with the turn.** When the agent finishes its reply, every command it started is stopped, because the Claude Code process that ran them is closed after each turn. A command still running at that point is marked **ended with turn**, its card says "Stopped when the turn ended", and one notice in the transcript lists the commands that were stopped. The header chips clear at the same moment.
5. The agent is told this in its instructions. It should finish any work that needs the command in the same reply, and never tell you a server is still running after it has answered. It is also told that it cannot open the command's output file itself (the file is outside its workspace), and to copy output into its workspace, for example with `tee`, when it needs to read it.

**Reloading or reconnecting mid-turn.** A page that is reloaded while the turn runs, or that reconnects after a dropped connection (a phone tab brought back to the front, a network blip), gets only what the server saved. So the server also saves the command's new output every five seconds or so while it keeps changing. A reloaded card catches up to what the command had printed a few seconds earlier, then keeps updating every few seconds instead of every second, and its **live** badge stays true. When the command ends, the card shows the final output that was saved with the reply. If some output never reached the page at all, the card says earlier output is missing rather than passing a fragment off as the whole thing.

**Deleting a conversation stops it first.** If a turn is still running when a conversation is deleted, that turn is stopped, and every background command it started goes with it. Then the conversation is deleted. Before, the conversation disappeared but its turn and commands kept running, with nothing left in the app that could stop them.

Rules:

- The live output is read by the server from the file Claude Code writes the command's output to. The server only reads that file if Claude Code's own message named it, it sits exactly where Claude Code keeps this session's output for this command (`…/<session id>/tasks/<task id>.output`), and it is a plain file rather than a link to somewhere else. A path the agent or the command wrote is never read. If anything about the file looks wrong, the card shows no live output, but it still shows how the command ended.
- The once-a-second pieces of output are not saved one by one. What is saved is what arrived since the last save, at most every five seconds and only when there is something new, plus the card's final output (its last 16,000 characters) and how the command ended. A quiet dev server costs a few small saves; a chatty build costs at most one 16,000-character save every five seconds.
- A command that ends almost at once (a typo, a quick `ls`) can finish before Claude Code reports that it started. Its card opens already settled, with its output and exit code, instead of running until the turn ends.
- Reading a command's output can never hold up the end of a turn: a last read that has not come back within two seconds is abandoned, and the turn ends normally. A file replaced by something that is not a plain file (for example a named pipe) is refused as soon as it is opened.
- Background commands started by a subagent are not followed. They belong to the subagent and end with its answer.
- When the agent stops one of its own background commands (Claude Code's `TaskStop` tool), the rule that makes every command ask first on a machine without the shell sandbox does not apply: `TaskStop` can only stop a command this session started, and it names no file. The conversation's permission mode and the per-tool approval settings still apply to it, as to any other tool (plan mode, for example, refuses it).

What this relies on, checked against the installed Agent SDK (0.3.278, bundled Claude Code 2.1.278):

- From the SDK's published types: `task_notification` reports a finished task with its task id, the id of the call that started it, `completed` / `failed` / `stopped`, a one-line summary and the output file's path. `background_tasks_changed` is the whole set of running tasks each time, and is not to be paired with the finish notices. There is no output for a running ordinary command (`tool_progress` carries elapsed seconds only). The old `BashOutput` / `TaskOutput` polling tools were removed; `BashOutput` is now only the name of the `Bash` result's shape. Without the `perTaskStopAffordance` option, which AgentStudio does not set, stopping a turn also kills its background tasks.
- Seen in Claude Code itself, not promised by the types, so a future update could change it: the "Output is being written to: …" sentence in a backgrounded command's result, the `<session id>/tasks/<task id>.output` file layout, `KillShell` and `KillBash` as old names for `TaskStop`, and a failed command's result starting with `Exit code N`. Claude Code sends a finish notice the moment a task ends, so for a command that exits at once the notice could come before the command's own result; that order was read from Claude Code's code rather than seen happen, and both orders are handled. Claude Code also adds a last line such as `[exited with code 0]` or `[killed]` to the output file, so a finished card usually ends with it. If any of these change, the cost is quiet cards (no live output, no exit code), never a failed turn.

### Diff and artifact preview

When a coding run changes files or saves artifacts, the workbench can show:
Expand Down Expand Up @@ -332,7 +372,7 @@ How the controls that exist today behave:
- **Answering a question.** When the agent asks a question (see [Questions from the agent](#questions-from-the-agent)), the answer only counts once the server has recorded it. If the question is no longer waiting (it timed out, was answered in another tab, or its turn ended), the page says so and shows the conversation as the server has it, rather than closing the question as if the answer had gone through. An answered question shows the answer under it straight away, and again after a reload. It no longer keeps a live Submit button that does nothing.
- **Switching conversations mid-turn.** Opening another conversation while a reply is streaming shows only the other conversation. Nothing from the first one comes along: not its reply, its tool cards, its Stop button, its error message or its Retry. Leaving is not a Stop. The first turn keeps running, saves its own reply, and shows again with Stop when you go back to it.
- **A turn that ends in an error.** Some turns end in an error after the reply was already saved, for example when the agent reaches its maximum number of steps or the model provider is overloaded. The page shows the error and keeps the one saved reply. It used to save a second, partial copy of the same reply.
- **Background tasks.** A command the agent starts in the background (a dev server, a watcher) shows as a chip in the header while the turn runs, with a button to stop it. The chips go away when the turn's stream ends, because ending a turn also ends the commands it started. If a stop does not work, a short message under the header says why — for example that the turn had already ended.
- **Background tasks.** A command the agent starts in the background (a dev server, a watcher) shows as a chip in the header while the turn runs, with a button to stop it, and streams its output into its card (see [Background commands](#background-commands)). The chips go away when the turn ends, because ending a turn also ends the commands it started. If a stop does not work, a short message under the header says why — for example that the turn had already ended.
- **Pinned checklist.** The panel above the composer shows the main agent's latest plan. When the agent hands a step to a subagent, the subagent's own checklist does not replace it.

### Context meter
Expand Down
6 changes: 3 additions & 3 deletions docs/structure/claude-desktop-parity.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,14 @@ This is the Cowork comparison, and it is the one I got wrong in the first draft:
| Diff rendering | **far behind** (#16) | raw JSON in a tool card | inline diffs with per-hunk accept/reject |
| Checkpoints and rewind | **behind** (#24 landed) | auto-checkpoint per turn in a project or persistent workspace; Edit and Regenerate cut the SDK session back to the kept history and offer to restore the files the dropped turns changed, with a dry-run preview and an explicit confirmation over uncommitted changes in an imported repo | auto-checkpoint per turn, Esc-Esc or `/rewind`, restore code / conversation / both — including a code-only restore we do not offer yet |
| Todo list | **absent** (#21) | nothing consumes it | pinned, updated in place |
| Terminal / command output | **far behind** (#26) | JSON-escaped blob in a card, nothing streams | streamed terminal output |
| Terminal / command output | **behind**, narrowly (#26, #35 landed) | a terminal card: the command, its output with colour codes cleaned out, the last 20 lines first with Show all, copy, and an exit-code badge. A background command streams its output into the card while the turn runs; an ordinary command shows elapsed seconds only, because the SDK sends no output until it finishes | streamed terminal output |
| Git worktrees | **absent** | one working directory per project | worktree-per-agent with cleanup safety |
| Repo import and clone | **win** | first-class: import creates a project, clones into a sandbox, sidecar repo row | you point it at a directory |
| Commit / push / PR | **even** | approval-gated tools, PR recorded and surfaced in `/review` | same, plus richer GitHub triggers |
| Code review of a PR | **absent** | — | `/ultrareview`, merge-aware follow-up reviews |
| CI watch and fix | **even** (#20 landed) | an opened PR's checks are watched (webhook, or polling every few minutes) for up to 14 days; a red check opens a review item and a notification, and **Fix it** hands the failure back to the conversation that wrote the code — a button, not an automatic run | cloud sessions react to CI |
| Hooks | **even** | `/settings/hooks`, event bus, skill hooks, per-agent bindings. Until the September 2026 audit the bus was never called on the chat engine path, so bindings and the built-in activity hooks only fired for automations; chats now raise run, tool, approval and question events too ([hooks.md](../hooks/hooks.md)) | same idea, dialog-managed |
| Background tasks | **behind** (#35) | the job queue backgrounds automations and research; inside a chat turn a long command blocks the turn | background bash that survives turns, with a completion notice |
| Background tasks | **behind** (#35 landed, turn-scoped) | the job queue backgrounds automations and research. Inside a chat turn the agent can background a command: a header chip with a stop button, live output in its card, a completion notice with the exit code. Commands end with the turn (the engine closes Claude Code after each reply); the card, a transcript notice and the agent's instructions all say so, and deleting a conversation stops its turn and commands first. Keeping one alive between messages needs a conversation-long session, not built | background bash that survives turns, with a completion notice |
| Session cost accounting | **win** | per-run rows, `/runs/[id]`, a ledger row per tool call, and the `/activity` usage strip (#38). Built-in calls write $0 call-count rows again since the ledger fix; tool calls made through the older loop (agent-attached automations, monitors, PR fix) are still not counted | session cost in a dialog |

## Chat
Expand Down Expand Up @@ -137,7 +137,7 @@ Ordered for how this box is used — NAS host, repeating jobs, files rarely open

**Wave 3 — the session surface.**

[#29](https://github.com/derekhearst/AgentStudio/issues/29) preview pane · [#19](https://github.com/derekhearst/AgentStudio/issues/19) permission modes · [#24](https://github.com/derekhearst/AgentStudio/issues/24) filesystem checkpoints · [#21](https://github.com/derekhearst/AgentStudio/issues/21) todo list · [#16](https://github.com/derekhearst/AgentStudio/issues/16) diff view · [#26](https://github.com/derekhearst/AgentStudio/issues/26) terminal output · [#35](https://github.com/derekhearst/AgentStudio/issues/35) background work in a turn
[#29](https://github.com/derekhearst/AgentStudio/issues/29) preview pane · [#19](https://github.com/derekhearst/AgentStudio/issues/19) permission modes · [#24](https://github.com/derekhearst/AgentStudio/issues/24) filesystem checkpoints · [#21](https://github.com/derekhearst/AgentStudio/issues/21) todo list · [#16](https://github.com/derekhearst/AgentStudio/issues/16) diff view · [#26](https://github.com/derekhearst/AgentStudio/issues/26) terminal output (landed) · [#35](https://github.com/derekhearst/AgentStudio/issues/35) background work in a turn (landed, turn-scoped)

**Wave 4 — the long tail.**

Expand Down
Loading
Loading