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 3fc2eb9
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>
"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