From 1d51a2c670e3959943db7110ec19e771761fc202 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 22:33:51 +0000 Subject: [PATCH 01/24] Install LDD: LOGIC.md beside every source file and directory (in progress) Logic-Driven Development per the logic-driven-development skill: a LOGIC.md describing the business logic of each file and directory containing source code, written fresh from the code for the technical product manager. This commit carries the root and packages-level files and the first slices; the remaining slices follow on this branch. Co-Authored-By: Claude Fable 5.1 Claude-Session: https://claude.ai/code/session_01YcSwKgtQE6ndJYjdDitVFB --- LOGIC.md | 100 +++++++++ packages/LOGIC.md | 23 ++ packages/framework/src/agent.LOGIC.md | 212 ++++++++++++++++++ packages/framework/src/format-bytes.LOGIC.md | 1 + .../framework/src/format-bytes.test.LOGIC.md | 4 + packages/skill-tickets/src/holder.LOGIC.md | 48 ++++ .../skill-tickets/src/holder.test.LOGIC.md | 3 + 7 files changed, 391 insertions(+) create mode 100644 LOGIC.md create mode 100644 packages/LOGIC.md create mode 100644 packages/framework/src/agent.LOGIC.md create mode 100644 packages/framework/src/format-bytes.LOGIC.md create mode 100644 packages/framework/src/format-bytes.test.LOGIC.md create mode 100644 packages/skill-tickets/src/holder.LOGIC.md create mode 100644 packages/skill-tickets/src/holder.test.LOGIC.md diff --git a/LOGIC.md b/LOGIC.md new file mode 100644 index 000000000..0845a9702 --- /dev/null +++ b/LOGIC.md @@ -0,0 +1,100 @@ +The Framework: autonomous AI programming. The user registers repositories as projects in a browser dashboard and states what to build or fix; a coding agent — Claude Code or Codex, on the user's own subscription — works the task unattended in a checkout [3] of its own, stops only for decisions a human must make, and hands the result off as a pull request. While nobody is at the keyboard, the same daemon keeps the account's leftover quota productive: it works the agent queue [7], refills it by triaging and planning tickets, keeps the pull requests it opened green, and merges them once their checks pass — standing down before unattended work could eat into the quota a human will want. The product never calls a model itself, and the user's own checkout is never touched. + +## Context + +**User story**: +- A developer registers a repository, types what they want, and gets a reviewable pull request without babysitting: the agent [1] asks only when a real decision is needed and otherwise finishes on its own. +- A developer walks away. The daemon spends the week's remaining quota on the roadmap — draining the agent queue [7], triaging and planning tickets, fixing red CI on its own pull requests, merging them once green — and never starves work the developer asks for. +- Nothing The Framework removes on its own initiative is lost: it only removes what is already on the git remote. + +## Glossary + +[1] agent: the unit of work: one task worked by a coding agent under The Framework's control — in its own checkout, on its own branch, streaming events, handed off when it ends. Started from the dashboard by the user, or by the daemon. +[2] driver: a coding agent wrapped as a black box: start it in a directory, prompt it for one turn, stream what it does, resume it later. The user's driver choice is `claude` or `codex`; the driver implementations are `claude-code`, `codex`, `github-actions`, `claude-web` and `fake`. +[3] checkout: an agent's own working copy of the project: a git worktree under the project's `.branches/` directory, named as its branch. +[4] gate: a question with options at which an agent stops and waits for an answer: it emits the question in its turn's final message, the dashboard shows it as a card, and the answer re-prompts the agent. When nobody can answer, the recommended option is taken. +[5] handoff: what happens to an agent's work when the agent ends, as one ladder of four levels: `local` (keep the work in its checkout), `push` (push its branch), `pr` (also open a pull request — the default), `merge` (also merge it). +[6] the `agent-data` branch: the branch of a project's repository used as a file store for everything agents share: tickets, the agent queue, the runs, routine locks. Born as an orphan, written through one sync → commit → push cycle. +[7] the agent queue: `TODO_AGENTS.md` on the `agent-data` branch: every task agents will work next, in priority sections, worked top-down. +[8] skill: one of the four capabilities an agent is taught — `branches`, `tickets`, `queue`, `logs` — each a package with the instructions the agent reads (its `SKILL.md`, linked into the checkout where the coding agent's harness looks for skills), a command on the agent's PATH, and an API the product calls. +[9] location: where an agent's turns run: `local` (this machine), `actions` (a GitHub Actions runner), or `web` (a Claude Code cloud session). +[10] sweep: a background job the daemon runs on its clock: Auto PM, the CI watch, the notification watchers, the sweep that reclaims checkouts, the branch-links sweep, the cloud scratch sweep, cloud work adoption. +[11] quota boundary: the share of the quota week that may be spent by now, rising with the clock; unattended work stands down past it, work a human asked for never does. +[12] Auto PM: the daemon's unattended product management: drain the agent queue, and refill it by running the routines. +[13] routine: a preset the daemon fires on its own on a schedule — update tickets, triage quick, triage consensual, plan tickets, maintenance — each switchable off and runnable on demand. +[14] the Claude web bridge: the daemon's bridge endpoints plus the Chrome extension: carries the question a cloud session is parked on into the dashboard, and types the pick back into the session. +[15] hands-off: said of an agent whose work leaves this machine, so its first prompt is the whole agent: an agent whose location is `web`. +[16] session name: the name an agent gives its own work (`[a-z0-9-]+`); its branch is renamed to `agent-` and the dashboard labels the agent by it. +[17] ready for merge: the signal an agent emits when it believes its work is complete: it flips the agent's badge from building to ready and authorizes the handoff. +[18] run: the `logs` skill's record of one agent on the `agent-data` branch: a card (what was asked, the ticket, the branch, the pull request, how it ended, what it cost) and a diary (what the agent said). +[19] device: another machine's daemon the user saved by URL and token, to run agents on it from this dashboard. +[20] cloud anchor: an empty commit a web agent pushes before its task leaves this machine, unique to the agent: the branch the cloud session later pushes descends from it, which is how the daemon recognizes that branch as the agent's. + +## Business logic — TL;DR + +- **How the packages fit together** - one product package on top of six libraries it is built from, plus two companions; every user-facing behavior is the product's, the libraries are the seams it is built on. +- **From a prompt to a pull request** - the user starts an agent [1] from the dashboard; the daemon gives it a checkout [3], frames the coding agent, honors the gates [4] it stops at, and publishes the work per its handoff [5] level when it ends. +- **While nobody is at the keyboard** - on one shared clock the daemon drains and refills the agent queue [7] (Auto PM [12] and the routines [13]), keeps its pull requests green and merges them, notifies, and reclaims what is on the remote — every start gated by the quota boundary [11]. +- **Work that runs somewhere else** - an agent's location [9] can be a GitHub Actions runner, a Claude Code cloud session (with the Claude web bridge [14] carrying its questions home), or a device [19] running another daemon; each is followed from this dashboard like a local agent. + +## Business logic + +### How the packages fit together + +#### Context + +**Business logic story**: the product is one npm package, `framework`; what it is built from is published as libraries so the coding-agent side of it — driving a coding agent, keeping shared files on a branch, the four skills [8] — can stand on its own. + +#### Business logic + +- `packages/framework` — the product: the `the-framework` CLI (four options, no verbs), the daemon it runs in the foreground (Ctrl-C closes it and every agent [1] it is running), the agent lifecycle, the dashboard the daemon serves — the product's only user interface — and every prompt an agent is sent, as markdown. Depends on all six libraries below. +- `packages/agent-driver` — the driver [2] seam: one contract for driving a coding agent as a black box, with the Claude Code, Codex, GitHub Actions and fake implementations; the product adds its own cloud-session implementation behind the same contract. The Framework prompts one turn at a time, lets the coding agent's own loop run to completion, and learns everything from the turn's final message: it never gates on the agent's individual tool calls, holds no model key, and runs on the user's own subscription. +- `packages/agent-data` — a branch of the project's repository used as a file store: the `agent-data` branch [6], checked out under `.branches/`, written through one sync → commit → push cycle that re-applies when a push loses a race. A library, not a skill: read by code, never by an agent. Every skill depends on it; nothing else does. +- `packages/skill-branches`, `packages/skill-tickets`, `packages/skill-queue`, `packages/skill-logs` — the four skills [8]: an agent's own checkout [3] and branch; the tickets with their plans and claims; the agent queue [7]; the record of every run [18]. Tickets, queue, runs and routine locks live on the `agent-data` branch, never on a code branch, so the default branch stays code only. No skill depends on another. +- `packages/chrome-extension` — the far end of the Claude web bridge [14], a Chrome extension reading claude.ai in a signed-in browser; it talks to the daemon over HTTP only. +- `packages/the-framework.ai` — the marketing site at https://the-framework.ai; it presents the product and shares no code with it. +- `.github/workflows` — every push builds, type-checks and tests the monorepo; the website deploys itself from the default branch; and one workflow is the far end of the `github-actions` driver implementation, running one turn per workflow run. + +### From a prompt to a pull request + +#### Context + +See `## Context`. + +#### Business logic + +The user activates a project from the dashboard, picked in the OS folder picker behind a trust confirmation: any dirty state is committed first, a `.the-framework/` directory is created with its ignore file and layout marker, and the project is registered in the daemon's one user file. From the project's home the user types a prompt or picks a preset, choosing the driver [2], the model, the location [9] and the handoff [5] level if the defaults are not wanted. + +The daemon gives the agent [1] a fresh checkout [3] — a git worktree under `.branches/` on the branch `agent-`, its dependency directories linked from the project's checkout, the four skills [8] linked in where the coding agent's harness looks and their commands on the PATH — checks that the chosen driver's coding agent can actually start, and spawns one process for the agent with its whole configuration as one JSON file. That process frames the coding agent with the built-in system prompt (plus the project's `SYSTEM.md` and the signal protocols), renders the user's text into the prompt's user slot, and lets the driver run a turn. + +The coding agent names its work before its first change (the session name [16]; the branch is renamed to `agent-`), commits as it goes — nothing is ever committed on its behalf — and ends each turn with a final message The Framework parses. A question with options is a gate [4]: the dashboard shows it where it happened, the user's pick is written to the agent's control file and re-prompts the agent, an unattended agent takes the recommended option, and a pick marked to stop ends the agent. The message may also carry markdown views for the dashboard's right rail, an error the user must fix, the pull request's title and body, and the ready-for-merge signal [17]. + +Everything the agent does is appended as events to `.the-framework/events.jsonl` in its checkout; the daemon tails that file to the browser, so watching now and reading later show the same record. Once the opening work settles, a build agent works the agent queue [7] one entry per turn, and then takes the user's own messages, each continuing the same driver session; a settled agent reads as waiting for the user, not as finished. + +When the agent ends, the handoff [5] runs at the level in force — by default push the branch and open a pull request named and described by the agent, with the issue reference of the ticket it worked; a merge is armed by configuration but authorized only by the agent's ready-for-merge signal, and a withheld merge is reported with its reason. An agent that committed nothing publishes nothing and leaves no branch behind. The run [18] is recorded on the `agent-data` branch [6] the moment the agent ends, and its checkout is reclaimed by a later sweep [10] once its work is on the remote — never before. + +### While nobody is at the keyboard + +#### Context + +See `## Context`. + +#### Business logic + +The daemon runs its sweeps [10] on one shared clock. Auto PM [12], when the user turned it on, works each project's agent queue [7] down — one agent per pass on the first open entry, the linked ticket claimed for that agent before it starts — and, once the queue is empty, refills it by running the routines [13]: update tickets from GitHub, triage quick wins and consensual work onto the queue, plan the tickets without a plan (several agents at once, one ticket each), and a calendar-paced maintenance sweep. Each routine runs once across machines, guarded by a routine lock on the `agent-data` branch [6] that the daemon takes before starting and frees when the agent ends; a lock left by a dead machine expires after four hours. + +Every unattended start is refused, with its reason reported, when Auto PM is off, when the project's concurrency cap is reached (the agents holding the slots are named), when an agent was started for the project moments ago, when the queue or the quota cannot be read, or when the account is past the quota boundary [11]: the pro-rated share of the quota week that has elapsed, rising continuously with the clock and shifted by the user's spend offset. The chosen model's own week gates unattended work the same way. + +The CI watch polls the pull requests The Framework is waiting to land: it merges one once its checks pass, and when a check goes red it starts one unattended fix agent per failing head commit, at most two attempts per pull request; a pull request older than a week is a human's to land. The notification watchers announce what is new on two feeds — what needs a human (an open question, a pull request to review, unpushed commits) and plain activity (an agent started or finished) — to the browser and, when configured, to Discord. Other sweeps reclaim the checkouts whose work is on the remote, adopt the branches cloud sessions pushed, and expire dead cloud refs. + +### Work that runs somewhere else + +#### Context + +**User story**: the user wants an agent to run on a fresh GitHub Actions runner, in a Claude Code cloud session on claude.ai, or on another machine of theirs — and to follow it from this dashboard as if it were local. + +#### Business logic + +An agent's location [9] is chosen at start and never changes. On `actions`, every turn is one workflow run on a GitHub Actions runner, with continuity carried by the branch the previous run pushed; the agent is followed like a local one. On `web`, the agent is hands-off [15]: the driver pushes a cloud anchor [20], the Claude web bridge's [14] extension creates the cloud session through claude.ai's repository picker on the chosen model, and the local agent ends there, with a link to the session. The bridge then carries any question the session parks on into the dashboard's open questions and types the pick back; the daemon later recognizes the branch the session pushed by its ancestry from the cloud anchor, records it on the run [18], and opens the armed pull request itself when the session opened none. The bridge runs either in the user's own Chrome or in a Chrome for Testing the daemon downloads and drives itself. + +A device [19] is another machine's daemon the user saved by URL and token: the local daemon forwards the start to it, streams the agent's events back and forwards steering, so the agent renders like a local one; the token never leaves the two daemons and is never persisted with the agent. diff --git a/packages/LOGIC.md b/packages/LOGIC.md new file mode 100644 index 000000000..083eddd39 --- /dev/null +++ b/packages/LOGIC.md @@ -0,0 +1,23 @@ +The deliverables The Framework ships, one directory each. The product is the `framework` package; every other package is either a library the product is built from — the driver [2] seam, a branch used as a file store, and the four skills [3] — or a companion: the Chrome extension of the Claude web bridge, and the marketing website. + +## Glossary + +[1] agent: the unit of work: one task worked by a coding agent under The Framework's control — in its own checkout, on its own branch, streaming events, handed off when it ends. +[2] driver: a coding agent wrapped as a black box: start it in a directory, prompt it for one turn, stream what it does, resume it later. +[3] skill: one of the four capabilities an agent is taught — `branches`, `tickets`, `queue`, `logs` — each a package with the instructions the agent reads (its `SKILL.md`), a command on the agent's PATH, and an API the product calls. +[4] the `agent-data` branch: the branch of a project's repository used as a file store for everything agents share: tickets, the agent queue, the runs, routine locks. +[5] the Claude web bridge: the daemon's bridge endpoints plus the Chrome extension: carries the question a cloud session is parked on into the dashboard, and types the pick back into the session. + +## Business logic — TL;DR + +- **The product** (`framework/`) - the `framework` npm package: the `the-framework` CLI, the daemon, the agent [1] lifecycle, the dashboard it serves, and every prompt an agent is sent. Depends on all six packages below. +- **The driver seam** (`agent-driver/`) - the `agent-driver` npm package: one contract for driving a coding agent as a black box, with the Claude Code, Codex, GitHub Actions and fake driver [2] implementations. The product adds its own cloud-session implementation behind the same contract. Depends on nothing else here. +- **A branch used as a file store** (`agent-data/`) - the `@gemstack/agent-data` npm package: the `agent-data` branch [4] every skill keeps its files on, checked out under `.branches/`, written through one sync → commit → push cycle, plus the git runner and the git-exclude rule that machinery is built on. A library, not a skill: read by code, never by an agent. Every skill depends on it; it depends on nothing. +- **The `branches` skill** (`skill-branches/`) - the `@gemstack/skill-branches` npm package: one checkout per agent under `.branches/`, named as its branch, reclaimed once its work is on the remote; the `branches` command and the skill [3] every agent reads. Depends on `agent-data`. +- **The `tickets` skill** (`skill-tickets/`) - the `@gemstack/skill-tickets` npm package: the project's tickets with their plans and claims on the `agent-data` branch, the `tickets` command that reads, writes, claims and closes them, and the skill text. Depends on `agent-data`. +- **The `queue` skill** (`skill-queue/`) - the `@gemstack/skill-queue` npm package: the agent queue on the `agent-data` branch, the `queue` command that reads it, adds an entry at a priority and takes one off, and the skill text. Depends on `agent-data`. +- **The `logs` skill** (`skill-logs/`) - the `@gemstack/skill-logs` npm package: the record of every run agents made on a project, on the `agent-data` branch, and the read-only `logs` command; the product writes every run through it. Depends on `agent-data`. +- **The Claude web bridge's extension** (`chrome-extension/`) - a Chrome extension, not an npm package: the far end of the Claude web bridge [5], reading claude.ai in a signed-in browser. Talks to the product over HTTP only. +- **The website** (`the-framework.ai/`) - the marketing site at https://the-framework.ai. Presents the product; shares no code with it. + +No skill depends on another skill, and nothing but the product depends on a skill. diff --git a/packages/framework/src/agent.LOGIC.md b/packages/framework/src/agent.LOGIC.md new file mode 100644 index 000000000..cec0d2fe5 --- /dev/null +++ b/packages/framework/src/agent.LOGIC.md @@ -0,0 +1,212 @@ +Runs one agent [1] from its first prompt to its end event: frames the coding agent [2], opens one driver session [3] for the whole agent, sends the opening prompt, honors every gate [4] the coding agent stops at, works the agent queue [5] when the agent is a build agent [6], takes the user's live chat [7], and ends, while streaming every step onto the one event stream [8] the dashboard, the archive and the run are projections of. A hands-off [9] agent is the exception to the middle of that story: its opening turn [10] is the whole agent. + +## Context + +**User story**: the user starts an agent from the launcher [11], or the daemon starts one on its own. The user watches it in the agent view [12], answers the questions it stops at, chats with it from the composer [13] once its work has settled, and finds the work handed off when the agent ends. Or nobody watches: the agent takes the recommended option at every gate and ends when its work settles. + +**Business logic story**: the agent's own process (`cli.ts`) resolves the configuration, tails the control file [14], decides who can answer gates and whether live chat is wired, and then hands everything to this file. This file is the middle of an agent's life. What happens to the work afterwards, the handoff [15], is `cli.ts`'s; the system channel's text is composed by `system-prompt.ts`; the gate mechanics live in `await-gate.ts`; the agent queue loop in `todo-loop.ts`; the reading of turn signals [16] in `turn-gate.ts`; the usage accounting and the stop plumbing in `agent-telemetry.ts`. + +**Problem**: the coding agent is a black box that answers one turn at a time and never says on its own that it stopped to ask, that it named its work, or that it is done. Everything The Framework learns about a turn it reads off the turn's final message, and every decision about what to send next is taken here. + +## Glossary + +[1] agent: the unit of work: one task worked by a coding agent under The Framework's control — in its own checkout, on its own branch, streaming events, handed off when it ends. Started from the dashboard by the user, or by the daemon. +[2] coding agent: the CLI doing the actual work: Claude Code or Codex. +[3] driver session: the coding agent's own conversation for one agent, which the driver can resume by its session id. +[4] gate: a question with options at which an agent stops and waits for an answer: it emits the question in its turn's final message, the dashboard shows it as a card, and the answer re-prompts the agent. When nobody can answer, the recommended option is taken. +[5] the agent queue: `TODO_AGENTS.md` on the `agent-data` branch: every task agents will work next, in priority sections, worked top-down. An item on it is a queue entry. +[6] build agent / prompt agent: the two kinds of agent: a build works the agent queue after its opening exchange; a prompt agent runs one prompt and stops there. +[7] live chat: the user's own messages to a running agent, each continuing the same driver session. One of them is a message. +[8] event stream: everything an agent does, one event per line appended to `.the-framework/events.jsonl` in its checkout; every surface (dashboard, terminal, archive, run) is a projection of it. +[9] hands-off: said of an agent whose work leaves this machine, so its first prompt is the whole agent: an agent whose location is `web`. +[10] turn: one prompt sent to the driver; the coding agent's own loop runs to completion and answers with a final message. +[11] launcher: the Start form on a project's own page. +[12] agent view: one agent's page in the dashboard. +[13] composer: the prompt editor on a project's own page, also used for live chat. +[14] control file: `.the-framework/control.jsonl`: the file the daemon appends steering to (stops, picks, chat messages) and the agent's process tails. +[15] handoff: what happens to an agent's work when the agent ends, as one ladder of four levels: `local` (keep the work in its checkout), `push` (push its branch), `pr` (also open a pull request — the default), `merge` (also merge it). +[16] turn signals: what The Framework reads off a turn's final message: the ready-for-merge signal, the pull request title and body, markdown views, reported errors, and the gate it stops at. +[17] driver: a coding agent wrapped as a black box: start it in a directory, prompt it for one turn, stream what it does, resume it later. The driver implementations are `claude-code`, `codex`, `github-actions`, `claude-web` and `fake`. +[18] checkout: an agent's own working copy of the project: a git worktree under the project's `.branches/` directory, named as its branch. +[19] the built-in system prompt: the standing instructions every agent starts with (`prompts/system_prompt.md`); `SYSTEM.md` is the project's own instructions added on top. +[20] vanilla: an agent started without the built-in system prompt but with the signal protocols kept. +[21] transparent: an agent started with nothing of The Framework's — the raw coding agent. +[22] location: where an agent's turns run: `local` (this machine), `actions` (a GitHub Actions runner), or `web` (a Claude Code cloud session). +[23] pick: the answer to a gate: the option or options chosen, by the user or automatically. +[24] stop: ending an agent before it finishes: the Stop button, Ctrl-C, or a pick marked to stop. +[25] await limit: the cap on consecutive gates within one exchange; an agent still asking past it finishes with its latest turn. +[26] unattended: said of an agent nobody is watching: its gates take the recommended option and it ends when its work settles. The opposite is attended. +[27] backlog loop: after a build agent's opening work settles, the loop that works the agent queue one entry per turn until it is empty. +[28] settled: said of an agent whose work has stopped and which is waiting for the user: it is alive, takes messages, and does nothing until told. +[29] cloud session: a Claude Code cloud session on claude.ai, the far end of a `web` agent. +[30] view: a markdown document an agent pushes to the dashboard's right rail while it works. +[31] ready for merge: the signal an agent emits when it believes its work is complete: it flips the agent's badge from building to ready and authorizes the handoff. + +## Business logic — TL;DR + +- **The agent announces itself before its first turn** - three events open the stream in a fixed order: the session opening, the intent, and the full system channel; a surface that fails to consume an event never fails the agent. +- **Framing the coding agent** - the system channel is composed once from the built-in system prompt, `SYSTEM.md`, the in-context directories and the agent's situation (owned checkout, browser, hands-off), with vanilla and transparent as the two ways to leave it out. +- **One driver session for the whole agent** - every prompt of the agent goes into one driver session; a continuation resumes the stopped leg's conversation instead of starting a new one; the session is disposed however the agent ends. +- **The opening prompt** - the user's text rendered through the built-in system prompt's user-prompt slot, or verbatim for a continuation, a vanilla or a transparent agent. +- **The opening exchange** - the opening turn plus every gate it leads to, up to the await limit of five; nobody to answer means the recommended option; a pick marked stop ends the agent. +- **A stop is honored before any phase counts as a success** - after the opening exchange, and again after the backlog and chat, a stopped agent ends as stopped, never as done. +- **The backlog loop, and when it is skipped** - only a build agent that is not hands-off works the agent queue, and only when the loop is enabled, which it is by default for every driver but the fake demo one; a pick marked stop inside an entry ends the whole agent. +- **Live chat, and where it happens** - a prompt agent takes chat inside its opening exchange, a build agent after its backlog; by default the agent drains what has arrived and ends on an idle queue, and only a stay-open agent parks for the next message. +- **A hands-off agent ends at its first turn** - no backlog loop and no chat after it, an explicit "Handed off" line before the end, and the land-everything instruction in its system channel. +- **Every turn's signals are read** - each final message is parsed for views, reported errors, the ready-for-merge signal and the pull request text, with one deduplication span across the opening exchange and chat. +- **How the agent ends** - done with its final text and the backlog result; stopped when the user's Stop or a stop pick ended it, with "stopped by your answer" as the detail for a pick; failed on any other error; the error is passed on to the agent's process either way. + +## Business logic + +### The agent announces itself before its first turn + +#### Context + +**Problem**: a dashboard tab can open at any moment of an agent's life and must be able to tell what the agent is, what it was asked and what it was told without parsing a prompt. The store titles the agent from these events, and the dashboard shows the normally hidden system channel from them. + +#### Business logic + +Before anything is sent to the coding agent [2], three events open the event stream [8], in this order: + +- The session opening: which driver [17] runs the agent, the checkout [18] it works in, whether the driver is the fake demo driver, the model when one was chosen, and the session link when it is a literal URL. A link template that needs the driver session's id is resolved later, by `agent-telemetry.ts`. +- The intent: the prompt text exactly as the agent was given it, so every surface titles the agent by it. A continuation's intent is its continuation message. +- The system channel's full text, only when there is one. A transparent [21] agent has an empty channel and emits nothing here. + +Every event is also handed to the observer the agent's process wired (the journal that writes the event file). An observer that throws is logged and ignored: a broken surface never fails the agent [1] and never robs it of its end event. + +### Framing the coding agent + +#### Context + +**User story**: the user sees, in the agent view [12], the whole text the coding agent was framed with before its first turn, and can switch the framing off from Settings or the repo file: vanilla [20] to drop the built-in system prompt [19], transparent [21] to run the raw coding agent. + +#### Business logic + +The system channel is composed once, before the driver session [3] opens, and never changed afterwards. Its inputs are: whether the agent is vanilla or transparent; the project's `SYSTEM.md` text when the project has one; the in-context directories the user picked; whether the checkout is one The Framework created, in which case the agent has the `branches` skill in its checkout, while any other agent is told how to branch with git itself and how to reach the tickets, the queue and the logs; whether the agent has a browser; and whether it is hands-off [9], in which case it is told to land everything (commit and open its own pull request) because nothing on this machine follows it. Transparent empties the channel entirely and overrides every other input. The composition rules, and the order of the parts, are `system-prompt.ts`'s. + +Hands-off is decided here from the agent's location [22]: only `web` is hands-off; the default location is `local`. The model the user chose, when any, is passed to the driver [17] and recorded on the session opening. + +### One driver session for the whole agent + +#### Context + +**Business logic story**: the coding agent keeps its own conversation. Sending every prompt into the same driver session is what lets a gate answer, a queue entry and a chat message land with the full context of what the coding agent already did. + +#### Business logic + +The driver starts one driver session [3] bound to the agent's checkout [18], with the composed system channel, the chosen model, and the agent's stop signal. Every prompt of the agent goes into that session: the opening prompt, every gate [4] continuation, every queue entry, every chat message. + +A continuation names the driver session id of a stopped leg. The driver then resumes that conversation, so the coding agent [2] answers with its full prior context, and everything around the turn still runs: the gates, the backlog loop [27], live chat [7]. The flow resumes, not just the conversation. + +The driver session is disposed when the agent ends, whichever way it ends. + +### The opening prompt + +#### Context + +**Problem**: the built-in system prompt [19] ends with a user-prompt slot, which is the one place the user's text is framed. Framing it a second time, or framing it for an agent that has no built-in prompt, stacks a preamble the coding agent has no use for. + +#### Business logic + +The first thing the coding agent [2] is sent is the user's text rendered through the built-in system prompt's `# User prompt` slot, the same for a build agent and a prompt agent [6]. Three cases send the text verbatim instead: a continuation, because the resumed conversation already carries the framing; a transparent [21] agent and a vanilla [20] agent, because without the built-in prompt there is no slot to render into. + +### The opening exchange + +#### Context + +**User story**: the coding agent stops to ask ("Which data store?", "Approve the plan?"), the dashboard shows the question as a card, the user picks, and the agent continues from the pick. When nobody is watching, the agent takes the recommended option and never waits. + +#### Business logic + +The opening prompt is sent as one turn [10]. When the turn's final message ends on a gate [4], the gate is resolved and the coding agent is re-prompted with the pick [23], and so on until the coding agent stops asking. The rules of one round are `await-gate.ts`'s; what this file relies on: + +- Who answers: the pick is the user's when an answer handler is wired, which the agent's process does only for an attended agent. With no handler, or when the agent is stopped while a gate is parked, the recommended option is taken (for a checklist, its pre-checked set), and the agent never pauses. This is what makes an unattended [26] agent run through. +- The await limit [25] is five consecutive gates in one exchange. An agent still asking past it finishes with its latest turn, and the log says "Finishing the session (await limit reached)." That line is not written when chat followed the exchange, since the chat's own end is then the agent's reason for ending. +- A pick marked stop [24] ends the exchange at once: the coding agent is never told the answer, the log says "Stopped at your answer: