Skip to content

Run the Planner as a full Atomic session with questions routed to Decisions - #215

Open
lavaman131 wants to merge 10 commits into
atomic-harnessfrom
atomic-full-planner
Open

lavaman131 wants to merge 10 commits into
atomic-harnessfrom
atomic-full-planner

Conversation

@lavaman131

Copy link
Copy Markdown
Collaborator

Summary

Closes #213.

Builds on and stacked on #210 (atomic-harness).

Makes HARNESS=atomic run the hosted Planner as a full Atomic session in both local and hosted configurations, with Chopin acting as the human-input host (HostInput) so every question routes to Decisions.

  1. Full Atomic Planner session:

    • HARNESS=atomic always runs Planner sessions as full Atomic sessions with Atomic builtins (workflows, subagents, MCP, web access, intercom), default coding tools, and operator Atomic resources (extensions, skills, prompt templates, context files).
    • Atomic background workers (document summary, research synthesis, structured output) remain isolated. The copilot-sdk and pi harnesses are unchanged.
    • Verified repository checkout support: an explicit checkout passed to invoke_planner is verified against the document repository's git origin, then remembered for that channel and reused on later browser- and agent-initiated turns. Without a verified checkout, the session runs in an isolated empty working directory with the same tools.
    • Documents the operator-level shell and filesystem trust boundary clearly in docs/self-hosting.md and docs/hosted-agent.md.
  2. Chopin as Atomic HostInput backed by Decisions:

    • Implements HostInput bound via extensionBindings.humanInput.
    • Maps questionnaire to Chopin's ask (Decisions) one-to-one; single-choice and multi-choice map cleanly; confirm and select become single-question questionnaires; input and editor become free-text cards.
    • Respects AbortSignal (withdraws the card) and handles timeouts: after a 30-minute timeout, the card resolves as expired with an inline notice in Decisions that nobody answered and the Planner will proceed on best judgement, while the callback returns "no answer".
    • Verbatim host questions and answers bypass restrictive per-field card limits while keeping aggregate document bounds.
    • Workflow requests are labeled with workflowRunId and workflowStageId. Unanchored batches append to the document end.
  3. invoke_planner MCP tool:

    • Registers invoke_planner({ id, instruction, checkout? }) across all harnesses.
    • Posts the instruction as a member message attributed to the caller under the channel's existing owner, or allows a caller's live browser login to claim ownership.
    • checkout verification applies to the atomic harness.
  4. MCP outputSchema specification compliance:

    • Declares top-level "type": "object" output schemas for rename_document, archive_document, and restore_document (wrapping oneOf unions), unblocking strict MCP clients such as Atomic's zod-validated MCP client.
    • Adds an invariant test ensuring every MCP tool in Chopin declares a top-level "type": "object" output schema.

Verification

Assistant-verification: bun test passed: 1746 pass, 2 PostgreSQL skips, 0 fail, 7619 assertions across 196 files
Assistant-verification: bun run types passed: all workspaces and E2E TypeScript checks
Assistant-verification: bun run ci passed: dprint, oxlint (0 errors, 1 existing warning), check-tokens, check-type-scale, and Impeccable design checks
Assistant-verification: bun run e2e passed: 236 passed, 0 failed in Chromium integration suite
Assistant-verification: worker isolation mutations passed: BUILTINS_OFF set true failed 17 of 34, isolated skill discovery failed 2, result tool on plain turns failed 11; all restored byte-for-byte
Assistant-verification: behaviour mutations passed: session registration, expiry withdrawal, expired record rejection on restore, and owner verification each failed their new tests; all restored byte-for-byte
Assistant-verification: documentation links passed: relative links and anchors in README.md, AGENTS.md, and docs resolve with exact casing

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
User-preference: No extra per-harness flags; HARNESS=atomic always runs the Planner as a full Atomic session, hosted included
User-preference: No extra per-harness env settings; the checkout comes from invoke_planner and the input timeout is a code constant
Co-authored-by: Alex Lavaee lavaman131@github.com

Opt in with ATOMIC_PLANNER=full only under local authentication and the Atomic
harness. Verify each Planner checkout's origin before enabling Atomic coding
tools, builtins, and operator resources. Unregistered worker sessions and
Planner sessions without a verified checkout retain the isolated boundary.

Bind Chopin's Decisions to Atomic HostInput rather than intercepting tools.
Map questionnaires and dialogs, preserve raw answers, label workflow requests,
and withdraw pending cards on abort or timeout after durable persistence.
Document the operator-level shell and filesystem trust change.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: bun test passed: 1706 pass, 2 PostgreSQL skips, 0 fail across 193 files
Assistant-verification: bun test apps/server/src/harness passed: 141 tests, including full Atomic SDK tools, resources, cwd, HostInput and isolated fallback
Assistant-verification: bun run types passed: all workspaces and E2E TypeScript checks
Assistant-verification: bun run fix passed: formatting inspected; no errors and one existing lint warning
Assistant-verification: bun run ci passed: formatting, lint, tokens, typography and design checks; no new design findings
Assistant-verification: isolation mutation checks passed: builtins on caused 16 failures, skill discovery caused 2, and plain-turn result tool caused 9; all mutations reverted byte-for-byte
Assistant-verification: relative documentation link check passed: 38 links and anchors resolved with exact casing
Assistant-verification: qlty smells passed: no duplication findings; complexity diagnostics match existing adapter closure patterns and are recorded in implementation notes
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Wrap the rename, archive and restore result unions in object schemas without changing their branches. Check every exported tool and the fully enabled MCP tools/list response.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: focused MCP tests passed: 81 tests, 450 assertions; the new invariant failed before the fix on rename_document
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix and bun run ci passed: formatting inspected, no errors and one existing lint warning
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Expose invoke_planner only for the full local Atomic mode. Resolve the
existing document and require a live browser login for the MCP caller's
GitHub identity; the bearer never supplies Planner ownership. Verify an
explicit checkout before posting, and retain it only for its own turn.

Persist the verbatim instruction as a member message before returning the
canonical document URL. Keep a server-opened room alive through the turn
and queue, without changing ordinary socket-only eviction. Document the
local shell and filesystem trust boundary and refusal codes.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: bun test passed: 1718 pass, 2 PostgreSQL skips, 0 fail, 7344 assertions across 196 files
Assistant-verification: focused MCP tests passed: 87 tests, including capability gating, input bounds, output schemas, session ownership and checkout verification
Assistant-verification: harness tests passed: 141 tests; full Atomic and default isolated behavior remain covered
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix and bun run ci passed: formatting inspected; no errors, one existing lint warning and no new design findings
Assistant-verification: relative documentation links passed: 26 targets and anchors resolved with exact casing
Assistant-verification: qlty smells completed: guard-return complexity and existing archive/restore duplication recorded in implementation notes
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Return a written answer as Atomic's custom kind only where its own dialog
accepts typed text, and as typed chat on multi-select or preview questions,
so Atomic's validator accepts every answer a member can give.

Hold verbatim host input only to aggregate bounds. Normalization and the
shared draft skip per-field counts and lengths for verbatim questions, the
dialect bounds questionnaire text by the source size, and an ask that would
take the document past 256 KiB fails before any card or record exists. The
Planner's ask tool keeps its per-field limits.

Read the Atomic checkout and timeout settings only in full mode, treating
empty values as unset.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: fail-before/pass-after passed: the 9 new tests failed with source changes stashed (InvalidHostInput, per-field QuestionErrors, config throw) and 93 of 93 passed after
Assistant-verification: bun test passed: 1727 pass, 2 PostgreSQL skips, 0 fail, 7393 assertions across 196 files
Assistant-verification: focused bun test passed: 294 tests in harness, question, dialect and config, including a full Atomic session answered through Decisions
Assistant-verification: aggregate-bound mutation check passed: disabling the document fit check made the oversize dialog test time out; source restored byte-for-byte
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix and bun run ci passed: formatting inspected; no errors, one existing lint warning and no new design findings
Assistant-verification: relative documentation links passed: 27 links and anchors resolved with exact casing
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Replacing a custom answer always deleted the current text first. On an
empty answer json-joy 17 binary-encodes that zero-length delete so the
server decodes garbage that swallows the following insert, yet still
acknowledges the edit. A paste, fill or one-character answer into the
empty box was lost, and a verbatim host question then saved "".

Delete only existing text, and skip the insert for an empty value, which
json-joy refuses: clearing a typed answer threw after its delete.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: fail-before/pass-after passed: with the unfixed change() the 5 new controller tests failed (the server-applied draft kept custom "" after one input for verbatim and ordinary questions and a host-only paste, and clearing threw EMPTY_STRING); 12 of 12 passed after
Assistant-verification: bun test passed: 1732 pass, 2 PostgreSQL skips, 0 fail, 7402 assertions across 196 files
Assistant-verification: bun test packages/question passed: 35 pass, 0 fail
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix passed: no change to tracked files; one existing lint warning
Assistant-verification: bun run ci failed: dprint flagged only three untracked .atomic/todos files; dprint check excluding .atomic, oxlint, token, type-scale and design checks then passed
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
The progressive custom answer test closes the resolved history, then
looked for the saved Scope card among outstanding decisions. On 115df25
and b52437b it passed 10 of 10 only because the filled answer never
reached the server: Save was rejected with "Scope requires a custom
answer" and the unsaved card stayed put. Since 6e1b405 saves it, the
card moves into the closed history, and the assertion passed in 4 of 10
runs, only when it polled before the plan update arrived.

Open the resolved history and check the saved answer and its resolver.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: original e2e test repeat-each 10 failed: 4/10 passed at 6e1b405, where Save succeeded; it passed 10/10 on 115df25 and b52437b only because WebSocket logs showed the server rejecting Save with "Scope requires a custom answer"
Assistant-verification: fail-before/pass-after passed: the corrected test failed 10/10 on b52437b ("2 resolved" never appeared; card showed the rejection alert) and passed 20/20 at 6e1b405 after a fresh client build
Assistant-verification: bun run e2e passed: 236 passed, 0 failed
Assistant-verification: bun test passed: 1732 pass, 2 PostgreSQL skips, 0 fail, 7402 assertions across 196 files
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix passed: no change to tracked files; one existing lint warning
Assistant-verification: bun run ci failed: dprint flagged only four untracked .atomic/todos files; dprint check excluding .atomic, oxlint, token, type-scale and design checks then passed
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
Co-authored-by: Alex Lavaee <lavaman131@github.com>
HARNESS=atomic is now the only switch. Every Planner session on that
harness, local or hosted, runs as a full Atomic session: builtins,
default coding tools, the operator's Atomic resources, and Chopin bound
as HostInput. The summary and research workers keep their isolated
sessions, and copilot-sdk and pi are unchanged. This supersedes the
local-only opt-in from c84fa4e. Its environment variables and
Config.atomicPlanner are gone, and nothing replaces them.

A checkout now comes only from invoke_planner. On the atomic harness it
is verified against the document's origin before anything is posted,
then remembered in memory for that channel. Every later Planner session
re-verifies it before use, whether it starts from the browser or MCP.
Without a remembered checkout, the session runs with the same tools in
an empty 0700 directory created for that channel alone and removed at
shutdown. The Planner's instructions say which case applies.

Host input expires after a fixed 30 minutes. The questionnaire record
and question:resolved now carry an "expired" status. The card stays in
the document with status="expired" and is listed among the resolved
Decisions, with a note that nobody answered and the Planner will use its
best judgement. Atomic receives no answer, and late submissions are
refused. An abort or member cancel still withdraws cards as before.

invoke_planner is offered for every harness and auth mode. The posted
message is attributed to the caller. The turn runs under the channel's
existing owner, or the caller's live browser login claims ownership, or
the call is refused before anything is posted. Other harnesses ignore
the checkout.

Assistant-model: Claude Opus 5.5
Assistant-workflow: goal (run 98acf681-3730-4957-b885-0d70e0e6b32a)
Assistant-verification: bun test passed: 1746 pass, 2 PostgreSQL skips, 0 fail, 7619 assertions across 196 files
Assistant-verification: focused bun test (harness, mcp, chat, config, question, protocol) passed: 390 pass, 0 fail, 1821 assertions across 38 files
Assistant-verification: worker isolation mutations passed: BUILTINS_OFF set true failed 17 of 34, isolated skill discovery failed 2, the result tool offered on plain turns failed 11; the adapter was restored byte-for-byte
Assistant-verification: behaviour mutations passed: never registering atomic sessions, withdrawing on expiry, rejecting expired records on restore, and refusing an owner other than the caller each failed their new tests; every file was restored byte-for-byte
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run fix passed: formatted changed files and one untracked .atomic todo, which was restored byte-for-byte; one existing lint warning
Assistant-verification: bun run ci failed: dprint flagged only one untracked .atomic/todos file; dprint check on the tracked and new files, oxlint, token, type-scale and design checks then passed
Assistant-verification: relative-link check passed: every relative link and anchor in README.md, AGENTS.md and docs resolves with exact casing
User-preference: "Atomic's SDK is the runtime and the host supplies human input; Chopin implements HostInput rather than intercepting tools"
User-preference: "In local mode the Planner may run as a full Atomic session so workflows run inside Chopin with questions in Decisions"
User-preference: No extra per-harness flags; HARNESS=atomic always runs the Planner as a full Atomic session, hosted included
User-preference: No extra per-harness env settings; the checkout comes from invoke_planner and the input timeout is a code constant
Co-authored-by: Alex Lavaee <lavaman131@github.com>
The full Planner kept the operator's settings in an in-memory manager
with no project scope, so packages a repository installs for itself
(`atomic install -l`, recorded in `.atomic/settings.json`) never loaded,
and their workflows and tools were missing from Planner turns run in that
checkout. Seed the in-memory project scope from the working directory's
`.atomic/settings.json` as trusted project settings, keep both files
unwritten, and reapply Chopin's compaction, summary, and cache overrides.

Assistant-model: Claude Opus 5.5
Assistant-workflow: inline
Assistant-verification: bun test passed: 1749 tests, 2 PostgreSQL skips, 0 fail, including a new full-Planner test that a checkout's project package contributes its tool and skill without writing either settings file
Assistant-verification: bun run types passed: all workspaces
Assistant-verification: bun run ci passed: dprint, oxlint, tokens, type scale, Impeccable baseline
Assistant-verification: local E2E failed before this fix: invoke_planner reached a full Planner whose tools lacked a package installed through the checkout's .atomic/settings.json
User-preference: HARNESS=atomic runs the Planner as a full Atomic session, so a checkout should behave like a local Atomic session in that repository
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Drop the full Atomic session framing and the tool inventory from the
Planner's workspace instructions; the system prompt already lists its
tools. Keep only what the model cannot infer: questions from
ask_user_question and workflows appear as Decisions, and an expired
question means proceeding on best judgement.

Assistant-model: Claude Opus 5.5
Assistant-workflow: inline
Assistant-duration: 12m converged, estimated 10m
Assistant-verification: bun test passed: apps/server/src/harness, chat and agent, 302 pass, 0 fail
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run ci passed: dprint, oxlint, tokens, type scale and design checks
User-preference: Planner prompts stay neutral; no "full Atomic session" meta framing, name tools only where it adds information the system prompt lacks
Co-authored-by: Alex Lavaee <lavaman131@github.com>
SDK-created sessions now register workflows provided by packages their
resource loader resolves and keep package-contributed MCP servers
(bastani-inc/atomic#3372), so a full Planner in a checkout can run the
workflows that checkout installs. The release ships the same five builtin
packages, so the isolated workers' BUILTINS_OFF still covers each one.
Also applies dprint's formatting to the Planner workspace instructions.

Assistant-model: Claude Opus 5.5
Assistant-workflow: inline
Assistant-verification: bun test passed: 1749 tests, 2 PostgreSQL skips, 0 fail
Assistant-verification: bun run types passed: all workspaces and E2E
Assistant-verification: bun run ci passed: dprint, oxlint, tokens, type scale, Impeccable baseline
Assistant-verification: source check passed: @bastani/atomic 0.9.25-alpha.2 dist/builtin lists intercom, mcp, subagents, web-access, workflows
Co-authored-by: Alex Lavaee <lavaman131@github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant