You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 9c7be04
Browse filesBrowse the repository at this point in the historyBrowse files
Atom++ AI: background command execution (M5, first slice)
run_command now accepts background:true — it still goes through the Approve
card but returns immediately ("Started in the background as id …") so the agent
keeps working instead of blocking on a dev server / watcher. A new
read_command_output {id, lines} tool polls a background process's recent output
+ status ([running on :3000] / [exited 0] / [stopped]), with port/readiness
sniffed from the logs (verify.js sniffPort/looksReady, unit-tested) and a
"no new output since last read" delta to save context.
- bgRuns registry (extension.js, module-scoped) holds {command,status,ring,
port,…} per background run; only background commands are tracked (foreground
one-shots keep old behavior + don't accumulate).
- Reuses the existing approval card, termRun/termOutput/termExit streaming, and
process-group Stop. The card shows "running in background…".
- Background runs ignore commandTimeout (meant to run long); reaped on New Chat
+ extension unload so servers don't orphan their ports (the design flagged
omitting this as a real footgun).
- SYSTEM prompt teaches the model to use background:true for non-exiting
commands and poll read_command_output for readiness before testing.
Syntax-checked + sniffer unit tests pass; loaded cleanly in dev. Live
end-to-end test pending. Deferred to slice 2: auto-background safety net, port
badge, atompp.ai.agent.background.* settings, max-concurrent cap.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: PLAN.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -129,7 +129,7 @@ M0→M4 is where you stop wanting to switch editors. These milestones are what m
129
129
130
130
**M5 — Close the loop & earn hands-off trust.**
131
131
- **● Diagnostics-driven auto-verify loop** *(M)* — ✅ **DONE.** After edits land and the model goes to finish, Atom++ verifies its own work before handing back: pulls `vscode.languages.getDiagnostics` for the files it touched this run (NEW errors only — diffed against a pre-run baseline keyed by severity+message, so pre-existing/unrelated problems and line-shifts don't trigger a chase) and, if a verify command is configured, runs it through the live-terminal plumbing; failures are injected back as a synthetic turn so the agent self-corrects, bounded by `atompp.ai.verify.maxRounds` (re-entries) **and** `maxSteps`, abort-safe, shown as a live ⛨ verify card. A command that can't even run (missing npm script / not found / exit 127) is classified as a config problem — it warns the user and never loops the agent on it. New `verify.js` (pure, unit-tested: 24 + 8 + 13 cases) + settings `atompp.ai.verify.{enabled,command,maxRounds,includeWarnings}`. *The capability every 2026 source calls the defining trait of autonomous agents — turns the agent from "writes code" into "ships working code."*
132
-
-**Background command execution***(M)* — detect long-running commands (dev servers, watchers, `tail -f`) and run them **detached in the background** instead of blocking the agent loop: the agent gets an immediate "started on :3000 (running in background)" and continues, while the live terminal card keeps streaming and a Stop button stays available; the agent can read recent output on demand. *Today an approved server **blocks** the agent until you Stop it or the backstop timeout fires — the live-terminal + process-group kill (M4+) made stopping reliable, but the agent still can't proceed while a server runs. This is how Cursor/Windsurf handle servers, and it pairs with the diagnostics→fix loop (start server → run tests against it → fix → repeat).*
132
+
- **Background command execution** *(M)* — ✅ **first slice shipped.** `run_command` now takes `background:true`: the command still goes through the Approve card but returns immediately (`Started in the background as id …`) so the agent keeps working while the live terminal card keeps streaming and Stop stays available. A new `read_command_output {id, lines}` tool lets the agent poll a background process's recent output + status (`[running on :3000] …`), with port/readiness sniffed from the logs (`verify.js` `sniffPort`/`looksReady`, unit-tested) and a "no new output since last read" delta. Background runs ignore `commandTimeout`; a `bgRuns` registry (extension.js) is reaped on New Chat + extension unload so servers don't orphan their ports. *Deferred to slice 2:* the auto-background safety net (a foreground command still running after ~12s auto-detaches so a forgetful model never hangs), a port badge on the card, the `atompp.ai.agent.background.*` settings, and a max-concurrent cap. *This pairs with the auto-verify loop: start server → test against it → fix → repeat.*
133
133
-**● Workspace checkpoints / restore timeline***(M)* — snapshot touched files per agent step, with one-click "Restore to here." *Cursor's checkpoints are explicitly "what makes people comfortable letting the agent make sweeping changes"; `reviewSession.js` already snapshots from disk, so this is mostly promoting it to a per-step stack.*
134
134
-**Prompt transparency + editable system prompts***(S)* — view and override the real `SYSTEM` prompts and see the exact context sent. *A stated PLAN pillar (§4, from Void), still unbuilt; a privacy/trust wedge against closed tools.*
135
135
-**Real token + cost accounting***(S)* — ✅ *context-usage shipped, Claude-Code-style*: `providers.js` captures real Anthropic `usage` (input/output + cache tokens); the footer now shows a **donut ring** that fills + recolors by pressure (accent → amber → red), and **clicking it opens a breakdown popover** (segmented bar + Messages / System prompt / Tools / Free-space rows with tokens + %), live-updating as the agent runs. *Remaining:* running $ spend + replace `lmProvider`'s length/4 estimate. *Cost opacity is the #1 criticism of BOTH Cursor and Windsurf — a no-backend editor showing exact per-message usage flips their biggest weakness into ours.*
"You are Atom++'s built-in autonomous coding agent. You accomplish the user's goal in their",
@@ -25,6 +25,7 @@ const SYSTEM = [
25
25
'- To change an EXISTING file, use edit_file with an exact, unique snippet (old_str) and its replacement (new_str). This is preferred — small and reliable. Read the file first so old_str matches exactly. Prefer SEVERAL small edit_file calls over one huge one (smaller edits are faster and easier to review).',
26
26
'- Use write_file ONLY to create a new file (or fully rewrite a short one); it needs the COMPLETE content. Do not rewrite large files — use edit_file repeatedly instead.',
27
27
'- Your file edits are APPLIED IMMEDIATELY and the user reviews them afterward in the editor with Keep/Undo — do NOT wait for approval, and do NOT re-edit a file you just edited. Only run_command still needs approval; if the user skips a command, adapt or stop.',
28
+
'- Commands that do NOT exit on their own (dev servers, file watchers, tail -f) MUST be run with run_command background:true — it returns immediately so you keep working instead of hanging. After starting one, call read_command_output with the returned id to watch for a readiness/port line (e.g. "listening on :3000") before you test against it. Use a normal foreground run_command for things that finish (builds, installs, tests, git, curl). This pairs with verification: bring the app up in the background, confirm it serves, fix, repeat.',
28
29
'- Paths are relative to the workspace root.',
29
30
'- For a multi-step goal, call update_plan FIRST with a short checklist (3-8 short items, all "pending"), then call it again to set an item "in_progress" when you start it and "done" when finished. Skip the plan for trivial single-step goals.',
30
31
'- If the goal truly depends on a decision only the user can make (tech stack, scope, where to create files, must-have features), call ask_user ONCE with concise multiple-choice questions (a short header + 2-4 concrete options each) INSTEAD of writing the questions as prose. Then act on their answers and do not ask again. Do NOT ask about things you can reasonably decide yourself — prefer a sensible default and proceed.',
@@ -39,7 +40,8 @@ const TOOLS = [
39
40
{name: 'update_plan',description: 'Declare or update your task checklist for a multi-step goal. Pass the FULL list each time, each item with a status. Call it once up front (all pending), then again to mark an item in_progress when you start it and done when finished. Skip for trivial single-step goals.',input_schema: {type: 'object',properties: {todos: {type: 'array',items: {type: 'object',properties: {title: {type: 'string'},status: {type: 'string',enum: ['pending','in_progress','done']}},required: ['title','status']}}},required: ['todos']}},
40
41
{name: 'edit_file',description: 'Make a targeted edit to an EXISTING file: replace an exact, unique snippet (old_str) with new_str. Applied immediately; the user reviews it with Keep/Undo. old_str must appear exactly once — include enough surrounding context to be unique.',input_schema: {type: 'object',properties: {path: {type: 'string'},old_str: {type: 'string'},new_str: {type: 'string'}},required: ['path','old_str','new_str']}},
41
42
{name: 'write_file',description: 'Create a new file (or fully overwrite a short one) with the COMPLETE content. For edits to existing files, prefer edit_file. Applied immediately; the user reviews it with Keep/Undo.',input_schema: {type: 'object',properties: {path: {type: 'string'},content: {type: 'string'}},required: ['path','content']}},
42
-
{name: 'run_command',description: 'Run a shell command in the workspace root. Requires approval.',input_schema: {type: 'object',properties: {command: {type: 'string'},explanation: {type: 'string'}},required: ['command']}},
43
+
{name: 'run_command',description: 'Run a shell command in the workspace root. Requires approval. Pass background:true for commands that do not exit on their own (servers, watchers) so the agent is not blocked — it returns immediately and you read progress later with read_command_output.',input_schema: {type: 'object',properties: {command: {type: 'string'},explanation: {type: 'string'},background: {type: 'boolean',description: 'true = start it and keep working without waiting (dev servers, watchers, tail -f). Returns immediately with an id; poll read_command_output for its output/status.'}},required: ['command']}},
44
+
{name: 'read_command_output',description: 'Read recent output + status of a command started with run_command background:true. Returns a status header ([running on :3000] / [exited 0] / [stopped]) followed by the latest output lines. Poll this to wait for a server to become ready before testing against it.',input_schema: {type: 'object',properties: {id: {type: 'string',description: 'the id returned by a background run_command'},lines: {type: 'number',description: 'max recent output lines to return (default 80, max 400)'}},required: ['id']}},
43
45
{name: 'ask_user',description: 'Ask the user one or more multiple-choice questions when the goal genuinely depends on a decision only they can make (tech stack, scope, where to put files, must-have features). The user picks by CLICKING — do NOT write questions as prose. Ask ONCE up front with all your questions, then proceed with the answers and never re-ask. Prefer sensible defaults over asking; only ask when a wrong guess would waste real work.',input_schema: {type: 'object',properties: {questions: {type: 'array',items: {type: 'object',properties: {header: {type: 'string',description: 'a 1-3 word tag for the question'},question: {type: 'string'},multiSelect: {type: 'boolean',description: 'true if several options can be picked at once'},options: {type: 'array',items: {type: 'object',properties: {label: {type: 'string'},description: {type: 'string'}},required: ['label']}}},required: ['question','options']}}},required: ['questions']}}
44
46
];
45
47
@@ -276,16 +278,56 @@ async function runTool(tu, ctx) {
return'Started in the background as id "'+runId+'" — it keeps running while you continue. Use read_command_output with this id to watch its output; wait for a readiness/port line before testing against it. Do not start it again.';
if(!entry){return'ERROR: no command with id "'+id+'" (it may never have started, or was cleared by New Chat). Start it with run_command background:true first.';}
0 commit comments