From 989c9c8ed465dcde2bcbd0ead6df9e1ecaa7778c Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 23:03:41 -0700 Subject: [PATCH 1/3] chore(quest): claim quest/m0/worktree-agents.md Quest-Claim: 69b9f00ee6208908 From 40ad24714a77580353e6485a2beac0e0d1357531 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Fri, 23 Oct 2026 23:19:34 -0700 Subject: [PATCH 2/3] docs(guide): gate expensive commands and checkpoint at handoffs The guide now routes expensive builds and tests through `quest gate`, keeps read-only discovery out of new checkouts, reuses owned ones, and asks for a pushed checkpoint (with unresolved work and check results) before a blocking decision or handoff. The spawn and complete skills no longer cap agents by core count. The quest keeps the harness integration: Claude and Codex lifecycle hooks that release finished and suspended agents' checkouts. Co-Authored-By: Claude Opus 5.5 --- assets/AGENTS.md | 6 ++++ assets/skills/complete.md | 1 - assets/skills/spawn.md | 1 - quest/m0/helpers/README.md | 2 +- quest/m0/helpers/headless-agents.md | 7 ++-- quest/m0/worktree-agents.md | 52 +++++++++++++++++++---------- 6 files changed, 44 insertions(+), 25 deletions(-) diff --git a/assets/AGENTS.md b/assets/AGENTS.md index 7ce72285..8db17c59 100644 --- a/assets/AGENTS.md +++ b/assets/AGENTS.md @@ -138,7 +138,13 @@ The PR that finishes a quest deletes its file and every link to it. A PR that leaves work rewrites the quest to what remains, rather than noting it only in the PR body. `quest check --base ` flags a quest branch whose diff does neither. +Do read-only discovery from context you already have, or a checkout you already own, rather than allocating a new one. +Reuse a suitable checkout you own for active work. +Run expensive builds and test suites through `quest gate `, which waits until the host has room for them; never poll the load average or cap agents by core count yourself. + Run the repository's checks locally while the PR is a draft; CI may run only on PRs ready for review. +Before ending with a blocking decision or a finished handoff, commit and push a checkpoint of the meaningful source changes, and record in the PR body what remains unresolved and which checks passed or were not run. +Leave disposable scratch, such as logs, build output, and helper scripts, out of checkpoints, and preserve source changes when work is cancelled. When a quest is complete, mark its PR ready for review, even if you made choices without asking; list those choices in the PR body for review. Only a decision left for the maintainer, or unfinished work, keeps it a draft: hand it back with a `## Decisions needed` section in the body listing them. Tools read only whether that heading is present; a draft without it still belongs to its starter. diff --git a/assets/skills/complete.md b/assets/skills/complete.md index 4bc4a60c..5697a981 100644 --- a/assets/skills/complete.md +++ b/assets/skills/complete.md @@ -30,7 +30,6 @@ Run each `/quest-ready`, `/quest-merge`, or `/quest-iterate` in its own sub-agen Each sub-agent blocks on its own waits and reports back only when done or blocked. For GitHub CI, review, or merge activity, it uses one `quest wait` and resumes with the returned cursor as described by `quest skill merge`, rather than polling GitHub. -Limit the number of active agents to the CPU core count. Tell each merge sub-agent that you watch its merge queue, so it reports once auto-merge is enabled. Wait on each such PR with `quest wait`, as `quest skill merge` diff --git a/assets/skills/spawn.md b/assets/skills/spawn.md index cb74c50d..98bb15bc 100644 --- a/assets/skills/spawn.md +++ b/assets/skills/spawn.md @@ -28,7 +28,6 @@ Present those one at a time: a short paragraph explaining the problem, the quest Start each quest in a background sub-agent with its own isolated worktree, since agents cannot write to a worktree their parent created. Each agent reports back only when done or blocked. -Limit the number of active agents to the physical CPU core count. When done, each agent's claim PR holds its work, still a draft if decisions or unfinished work remain. Its report lists every open decision with a recommendation. diff --git a/quest/m0/helpers/README.md b/quest/m0/helpers/README.md index 05e577f1..7ab22499 100644 --- a/quest/m0/helpers/README.md +++ b/quest/m0/helpers/README.md @@ -66,4 +66,4 @@ commands from Sep-Oct. Session counts in each child come from that window. ## Related -- [Agent lifecycle integration](/quest/m0/worktree-agents.md) - removes the agent-level load-average rules +- [Agent lifecycle integration](/quest/m0/worktree-agents.md) - reclaims finished and suspended agent checkouts through their harness diff --git a/quest/m0/helpers/headless-agents.md b/quest/m0/helpers/headless-agents.md index b2d44a46..e6d3d12b 100644 --- a/quest/m0/helpers/headless-agents.md +++ b/quest/m0/helpers/headless-agents.md @@ -40,10 +40,9 @@ every user would have to add it. supply its own `claude.exe` and receive the key), and launch npm `.cmd` shims, which `spawn` cannot run without a shell. Then run the fake-CLI tests on the native Windows jobs. -- The command does no load or CPU admission. The skill keeps holding launches - as it does for sub-agents, until agent lifecycle integration removes those - rules. +- The command does no load or CPU admission, and the skill no longer caps + agents: the guide routes their expensive commands through `quest gate`. ## Related -- [Agent lifecycle integration](/quest/m0/worktree-agents.md) - removes the skill's load-average launch rules, so neither the skill nor the command polls load +- [Agent lifecycle integration](/quest/m0/worktree-agents.md) - reclaims the checkouts of finished and suspended agents, including headless ones diff --git a/quest/m0/worktree-agents.md b/quest/m0/worktree-agents.md index a568f8ff..12b00002 100644 --- a/quest/m0/worktree-agents.md +++ b/quest/m0/worktree-agents.md @@ -10,33 +10,49 @@ merge. ## Plan - Decided 2026-10-15: use `quest worktree` for checkout lifetime and `quest gate` - for expensive phases. Remove the skill's physical-core agent-count and load - average admission rules once command admission is integrated. Disk capacity - gates checkout allocation, not the number of reasoning agents. + for expensive phases. Disk capacity gates checkout allocation, not the number + of reasoning agents. - Landed: `quest worktree run` supervises a job and releases its scratch, `remove` deletes a finished checkout without losing work (a squash-merged head counts only with exact PR-head evidence), and `stop` ends a crashed - supervisor's leftover processes. -- A 2026-10-19 transcript audit counted 1,731 load-average polling commands - in moq-dev/moq and moq-dev/moq.pro sessions since Oct 14, so the remaining - agent-level load rules still cost tokens until this lands. + supervisor's leftover processes. The guide routes expensive commands through + `quest gate`, asks for a checkpoint before a blocking decision or handoff, + and keeps read-only discovery out of new checkouts; the spawn and complete + skills no longer cap agents by core count. +- Measured 2026-10-23: this repository's main checkout held 65 Claude subagent + worktrees under `.claude/worktrees/`, 8.2 GB in all, the oldest from + 2026-10-07, so finished workers are not reclaimed today. - A foreground CLI wrapper only owns its child commands. Native agent tools need explicit ownership and suspend/resume integration; a helper that exits after creating a directory cannot infer when such an agent has finished. - Reuse native worktree/archive APIs where they preserve the required state. Test actual completion, not merely an accepted or queued archive request. Recover failed archives and stale ownership without bypassing active locks. -- Do read-only discovery without allocating a new checkout when existing - context suffices. Reuse suitable owned checkouts for active work. -- Update shared workflow guidance to checkpoint meaningful source before a - blocking decision or completed handoff, recording unresolved work and check - results. Exclude disposable scratch and preserve source on cancellation. -- Exercise both harnesses with a finished worker under a still-live parent, - a suspended decision, a crash, and a restored session. Reconcile existing - cleanup mechanisms instead of adding an unrelated competing sweeper. -- Current Claude docs exclude hook-created subagent worktrees from automatic - removal and its retention sweep. Codex can archive recoverably but refuses - unsupported nested repositories. Integrate their actual supported lifecycle. +- Claude: a `WorktreeCreate` hook replaces every worktree Claude creates in the + repository (`--worktree`, `EnterWorktree`, subagent isolation, background and + remote-control sessions) and prints the path; `.worktreeinclude` is then not + processed. Claude never removes a hook-created subagent or workflow worktree + and never runs `WorktreeRemove` for one; it runs `WorktreeRemove` only for + session exits, `ExitWorktree`, background-session deletes, and remote-control + cleanup. `SubagentStop` fires when a subagent finishes responding, which + covers both completion and a suspended decision, and `SubagentStart` fires on + resume; their `cwd` follows the agent, but whether it is the subagent's + worktree must be confirmed live. Without a hook, Claude removes a clean + subagent worktree only when it finishes with no changes and otherwise leaves + it to the `cleanupPeriodDays` sweep. +- Codex can archive recoverably but refuses unsupported nested repositories, + and keeps its 15 most recent managed worktrees by default. Integrate its + actual supported lifecycle. Sources: [Claude worktrees](https://code.claude.com/docs/en/worktrees), [Claude removal hooks](https://code.claude.com/docs/en/hooks#worktreeremove), [Codex worktrees](https://learn.chatgpt.com/docs/environments/git-worktrees). +- Open: whether `quest init` installs the Claude hooks into the repository's + settings or the user installs them; how a hook-created checkout learns its + reservation and scratch paths; and what an unset capacity admits, since + `quest worktree create` refuses everything until `capacity` is set. +- Exercise both harnesses with a finished worker under a still-live parent, + a suspended decision, a crash, and a restored session. Reconcile existing + cleanup mechanisms instead of adding an unrelated competing sweeper. Run + these from a session that is not itself worktree-isolated: Claude's + isolation checks refuse git in any other repository, including a scratch + test repository. From a577b931523798b19eddaa32eed6f6f315167b0d Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 26 Oct 2026 10:56:42 -0700 Subject: [PATCH 3/3] quest: record the agent lifecycle decisions The user settled the PR's five decisions on 2026-10-26: Claude hooks backed by quest worktree, static hook entries in .claude/settings.json written by quest init, derived checkout defaults, Codex through quest agent inside quest worktree run, and only the harness's agent cap. The quest now lists the remaining implementation, and m0's vendoring bullet allows quest init to install static hook stubs. Co-Authored-By: Claude Opus 5.5 --- quest/m0/README.md | 10 +++-- quest/m0/worktree-agents.md | 74 +++++++++++++++++++++++++++---------- 2 files changed, 62 insertions(+), 22 deletions(-) diff --git a/quest/m0/README.md b/quest/m0/README.md index 3f8be31e..d6093cbc 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -21,9 +21,13 @@ product without changing the core's independence. Decided while planning m0 (2026-09-26), replacing the earlier copied-files and ownership-manifest design: -- Nothing is vendored. The binary carries the skills and the quest contract; - a repository gets static one-line skill stubs and one reference line in its - root instructions. Upgrading never rewrites repository files. +- The binary carries the skills, the quest contract, and all hook logic. + `quest init` installs only static stubs into a repository: one-line skill + stubs, one reference line in its root instructions, one `.gitattributes` + line, and Claude hook entries in `.claude/settings.json` that only call a + `quest` subcommand. Upgrading never rewrites repository files. (Amended + 2026-10-26 (user), replacing "Nothing is vendored", so `quest init` can + install the agent lifecycle hooks.) - The repository's own tool manager pins the version: mise (release binaries) or a nix flake input (any rev, built from source). Quest ships no launcher and no pin file; an install outside either is simply unpinned. diff --git a/quest/m0/worktree-agents.md b/quest/m0/worktree-agents.md index 50e88987..023c18d2 100644 --- a/quest/m0/worktree-agents.md +++ b/quest/m0/worktree-agents.md @@ -1,4 +1,4 @@ -# [M] Release agent checkouts at handoffs and completion +# [L] Release agent checkouts at handoffs and completion ## Goal @@ -9,9 +9,61 @@ merge. ## Plan +Remaining work: + +- Claude hooks: a `quest` subcommand (for example `quest worktree hook + `) handles `WorktreeCreate` and `WorktreeRemove` through `quest + worktree create` and `remove`, releases the stopped subagent's checkout on + `SubagentStop`, and restores it on `SubagentStart`. `/quest-spawn` cleanup + calls `quest worktree remove`, since Claude never removes a hook-created + subagent worktree. +- `quest init` adds the static hook entries to `.claude/settings.json`, + merging into an existing file, and `quest uninstall` removes exactly those + entries. +- Derived defaults for a checkout the hook creates, which gets only a `name`. +- Codex through `quest agent` running the harness inside `quest worktree run`. +- Exercise both harnesses with a finished worker under a still-live parent, + a suspended decision, a crash, and a restored session. Confirm live that + `SubagentStop`'s `cwd` is the subagent's worktree, and that a hook-created + worktree passes Claude's isolation identity check. Reconcile existing + cleanup mechanisms instead of adding an unrelated competing sweeper. Run + these from a session that is not itself worktree-isolated: Claude's + isolation checks refuse git in any other repository, including a scratch + test repository. + +Decisions: + - Decided 2026-10-15: use `quest worktree` for checkout lifetime and `quest gate` for expensive phases. Disk capacity gates checkout allocation, not the number of reasoning agents. +- Decided 2026-10-26 (user): Claude integrates through a + `WorktreeCreate`/`WorktreeRemove` hook pair backed by `quest worktree`, with + `SubagentStop` releasing and `SubagentStart` restoring. It matches the + ownership model, and native cleanup does not reclaim finished workers. The + accepted cost: the hook replaces every Claude worktree in the repository. + Rejected: pruning build output in place on `SubagentStop`, and prose alone. +- Decided 2026-10-26 (user): the hooks live in the repository's + `.claude/settings.json`, written by `quest init`, not in user settings. The + entries are static stubs that only call a `quest` subcommand, with all logic + in the binary like the skill stubs, so upgrades never rewrite them. The m0 + Plan's vendoring bullet was amended to allow this. +- Decided 2026-10-26 (user): a hook-created checkout derives its defaults. + Scratch is the main checkout's top-level ignored entries, excluding + `.worktrees/`, `.claude/worktrees/`, and nested repositories. The reserve is + the main checkout's disk usage. An unset `capacity` admits whatever the + free-space check admits, instead of refusing everything. +- Decided 2026-10-26 (user): Codex, which documents no worktree hooks, is + covered by `quest agent` running it inside `quest worktree run`, which + releases on exit and restores on resume. Codex app threads stay on Codex's + native archive. +- Decided 2026-10-26 (user): agents are capped only at the harness's + concurrent sub-agent limit, stated once in the guide; the core-count cap is + gone, since `quest gate` holds expensive commands. The 2026-10-15 decision + stands over [kixelated/quest#227](https://github.com/kixelated/quest/pull/227)'s + wording, which kept the core count only incidentally. + +Context: + - Landed: `quest worktree run` supervises a job and releases its scratch, `remove` deletes a finished checkout without losing work (a squash-merged head counts only with exact PR-head evidence), and `stop` ends a crashed @@ -38,27 +90,11 @@ merge. session exits, `ExitWorktree`, background-session deletes, and remote-control cleanup. `SubagentStop` fires when a subagent finishes responding, which covers both completion and a suspended decision, and `SubagentStart` fires on - resume; their `cwd` follows the agent, but whether it is the subagent's - worktree must be confirmed live. Without a hook, Claude removes a clean + resume; their `cwd` follows the agent. Without a hook, Claude removes a clean subagent worktree only when it finishes with no changes and otherwise leaves it to the `cleanupPeriodDays` sweep. - Codex can archive recoverably but refuses unsupported nested repositories, - and keeps its 15 most recent managed worktrees by default. Integrate its - actual supported lifecycle. + and keeps its 15 most recent managed worktrees by default. Sources: [Claude worktrees](https://code.claude.com/docs/en/worktrees), [Claude removal hooks](https://code.claude.com/docs/en/hooks#worktreeremove), [Codex worktrees](https://learn.chatgpt.com/docs/environments/git-worktrees). -- Open: whether Claude integrates through `WorktreeCreate`/`WorktreeRemove` - and `SubagentStop`/`SubagentStart` hooks, an in-place prune on - `SubagentStop`, or prose alone; whether `quest init` installs the hooks into - the repository's settings or the user installs them; how a hook-created - checkout learns its reservation and scratch paths, and what an unset - capacity admits, since `quest worktree create` refuses everything until - `capacity` is set; and whether Codex is covered through `quest agent` - running inside `quest worktree run`. -- Exercise both harnesses with a finished worker under a still-live parent, - a suspended decision, a crash, and a restored session. Reconcile existing - cleanup mechanisms instead of adding an unrelated competing sweeper. Run - these from a session that is not itself worktree-isolated: Claude's - isolation checks refuse git in any other repository, including a scratch - test repository.