From f053efaeca13d53dd2961969dc9f146379111e17 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 19 Oct 2026 10:34:55 -0700 Subject: [PATCH 1/2] docs(quest): plan agent workflow helpers Co-Authored-By: Claude Opus 5.5 --- quest/m0/README.md | 1 + quest/m0/helpers/README.md | 47 +++++++++++++++++++++++++++++++++ quest/m0/helpers/afk.md | 24 +++++++++++++++++ quest/m0/helpers/claim.md | 33 +++++++++++++++++++++++ quest/m0/helpers/gate-lock.md | 33 +++++++++++++++++++++++ quest/m0/helpers/move.md | 32 ++++++++++++++++++++++ quest/m0/helpers/status.md | 33 +++++++++++++++++++++++ quest/m0/helpers/wait-checks.md | 31 ++++++++++++++++++++++ quest/m0/worktree-agents.md | 3 +++ 9 files changed, 237 insertions(+) create mode 100644 quest/m0/helpers/README.md create mode 100644 quest/m0/helpers/afk.md create mode 100644 quest/m0/helpers/claim.md create mode 100644 quest/m0/helpers/gate-lock.md create mode 100644 quest/m0/helpers/move.md create mode 100644 quest/m0/helpers/status.md create mode 100644 quest/m0/helpers/wait-checks.md diff --git a/quest/m0/README.md b/quest/m0/README.md index 0afb2c34..69bd032d 100644 --- a/quest/m0/README.md +++ b/quest/m0/README.md @@ -38,6 +38,7 @@ ownership-manifest design: - [Expensive command gate](/quest/m0/local-gate.md) - shared CPU admission across worktrees and repositories - [Recoverable worktrees](/quest/m0/worktree.md) - disk admission, checkpoints, release, and restore - [Agent lifecycle integration](/quest/m0/worktree-agents.md) - reclaim completed and suspended checkouts through their harness +- [Agent workflow helpers](/quest/m0/helpers/README.md) - CLI commands for CI waits, PR status, claims, quest moves, and serialized merges - [Kix decision UI](/quest/m0/kix/README.md) - planning and implementation through prompts and summaries, run on the maintainer's own runners - [Quest log theme](/quest/m0/theme/README.md) - an MMO-style identity, copy, board, landing page, and CLI output for the demo and launch diff --git a/quest/m0/helpers/README.md b/quest/m0/helpers/README.md new file mode 100644 index 00000000..909f5946 --- /dev/null +++ b/quest/m0/helpers/README.md @@ -0,0 +1,47 @@ +# Agent workflow helpers + +## Goal + +Agents stop hand-writing `gh`, `jq`, and `sed` loops for routine quest +workflow steps, because `quest` commands cover them and the skills point at +those commands: CI results while waiting, a one-shot PR status, claims, moving +and deleting quests, serialized check-then-merge, and unattended triage. + +Only generic helpers belong here. Non-goals: the kix.quest UI, a daemon, and +deciding whose review or which result counts; the agent still decides. + +## Plan + +Decided 2026-10-19 from an audit of Claude Code transcripts in moq-dev/moq and +moq-dev/moq.pro: 396 sessions from Oct 17-19, 2026, plus about 339k Bash +commands from Sep-Oct. Session counts in each child come from that window. + +- Decided (user): plan only the really generic helpers. Replying to and + resolving review threads (103 and 68 sessions) is dropped: its attribution + footer and wording are user and repository policy, and `gh api` already + does the call. Parsing open decisions from a PR body is dropped from + `quest status`, since that body format is a skill convention. +- GitHub calls live in `src/cli/` beside `quest wait`, outside the + forge-agnostic core. Pure tree edits, such as link rewriting, go in the + core. The first child to add a second GitHub caller extracts the client in + `src/cli/wait.ts` (auth, rate-limit retry, same-origin pagination) instead + of copying it. +- Decided (user): no separate documentation page. Each child updates + `--help`, README examples, and the skill prose it replaces; the user asked + for those skill edits through this plan. +- Decided (user): this epic ranks after the worktree and gate quests and + before the Kix decision UI. Children rank by sessions affected. + +## Required + +- [PR status](/quest/m0/helpers/status.md) - one call for head, checks, merge state, reviews by head, and unresolved threads +- [Move and delete quests](/quest/m0/helpers/move.md) - `quest mv` and `quest rm` keep every root-absolute link valid +- [CI checks in wait](/quest/m0/helpers/wait-checks.md) - `quest wait` wakes on required check results for the head +- [Claim quests](/quest/m0/helpers/claim.md) - `quest claim`, `--release`, and `quest unblocked --unclaimed` +- [Named gate lock](/quest/m0/helpers/gate-lock.md) - `quest gate --lock ` serializes check-then-merge +- [Unattended triage](/quest/m0/helpers/afk.md) - an `afk` argument that only asks about merges and deletes + +## Related + +- [Expensive command gate](/quest/m0/local-gate.md) - the gate the lock builds on +- [Agent lifecycle integration](/quest/m0/worktree-agents.md) - removes the agent-level load-average rules diff --git a/quest/m0/helpers/afk.md b/quest/m0/helpers/afk.md new file mode 100644 index 00000000..a8adb98a --- /dev/null +++ b/quest/m0/helpers/afk.md @@ -0,0 +1,24 @@ +# [XS] Triage unattended with an afk argument + +## Goal + +`/quest-complete afk` and `/quest-spawn afk` act on their recommendations +without asking, except merges and deletes. This replaces the prompt the +user keeps typing before stepping away: "skip/iterate any that you +recommend, and prompt for any that you recommend I merge... relatively +simple decisions only". + +## Plan + +- Decided 2026-10-19 (user): one shared `afk` argument for both skills, not + a new default and not limited to `/quest-complete`. +- In afk mode, dispatch recommended skip, `/quest-iterate`, and + `/quest-ready` picks without asking. Still ask about every merge and + delete, as one simple question each with the recommendation first. +- A decision that is not simple becomes a skip with a note in the summary + rather than a question. Suggested `/quest-plan` follow-ups wait for the + summary, since planning is an interview. +- The rest of the argument still filters the PRs or quests in scope, as + today. +- Edit `assets/skills/complete.md` and `assets/skills/spawn.md`, following + `PROMPTING.md`. diff --git a/quest/m0/helpers/claim.md b/quest/m0/helpers/claim.md new file mode 100644 index 00000000..d5749f02 --- /dev/null +++ b/quest/m0/helpers/claim.md @@ -0,0 +1,33 @@ +# [S] Claim and release quests with quest claim + +## Goal + +`quest claim ` claims a ready quest the way `quest guide` describes, +and `quest unblocked --unclaimed` lists ready quests nobody holds. Agents stop +running `git ls-remote origin 'refs/heads/quest/...'` and +`gh pr list --head/--search` by hand before starting or spawning (105 of 396 +sessions), since `quest ready` checks no claims. + +## Plan + +- Decided 2026-10-19 (user): one `claim` command plus an `--unclaimed` + filter, rather than a separate claims listing. +- `claim` refuses a blocked quest, checks for an open PR from the quest's + branch, then pushes an empty commit with the explicit refspec + `refs/heads/:refs/heads/`, never forcing. A rejected push + means someone else holds the claim, which makes the push the atomic check. + Distinct exit codes separate "taken" from a failure. +- Decided (user): `quest claim --release ` deletes the remote claim + branch only while its tip is still the empty claim commit and it has no + open PR, using a lease on that SHA; otherwise it refuses and says why. +- `quest unblocked --unclaimed` uses one `ls-remote` for `refs/heads/quest/*` + and one query for open PRs, and prints skipped claims on stderr with their + age and PR so stale claims can be offered for takeover. +- The branch check is plain git. Only the open-PR check is GitHub-specific; + with a non-GitHub origin it is skipped with a warning. kix.quest publishes + quest branches and PRs, so its jobs count as claims here too. +- Default the remote to origin, with `--remote` to override. +- Update `start` and `spawn` skill prose to use these commands. +- Test claiming free and taken quests, a race between two claimers, an open + PR without a branch claim, releasing a claim, refusing to release a branch + with work on it, and the filtered ranking. diff --git a/quest/m0/helpers/gate-lock.md b/quest/m0/helpers/gate-lock.md new file mode 100644 index 00000000..78d96f64 --- /dev/null +++ b/quest/m0/helpers/gate-lock.md @@ -0,0 +1,33 @@ +# [S] Serialize commands with quest gate --lock + +## Goal + +`quest gate --lock ` runs a command while holding a named +exclusive lock for one user on one host, so a local check-then-merge sequence +runs one at a time. It replaces the `~/.cache/moq-pro-merge.lock.d` mkdir +mutex that moq.pro agents invented (79 of 396 sessions). + +## Plan + +- Decided 2026-10-19 (user): a named exclusive lock rather than a general + named semaphore with a limit. +- Hold it until the command and its descendants exit, and release it when + the holder crashes, using an OS-held lock (or the Linux scope ownership + from the gate) rather than PID guesses. +- The lock takes no CPU slot, so gated recipes inside the command still get + normal admission instead of running as nested calls. +- While waiting, print the name and the holder's command and start time. + Names are short tokens; reject anything that could escape the lock + directory. +- Build on `src/cli/gate.ts` from [kixelated/quest#128](https://github.com/kixelated/quest/pull/128); + start after that PR merges. Switching moq.pro to the lock is a follow-up + in that repository. +- Data for the gate quests: the audit also counted 1,731 load-average + polling commands in moq and moq.pro sessions since Oct 14, which the gate + and the agent lifecycle quest remove. +- Test contention across processes, a crashed holder, cancellation while + waiting, exit status propagation, and a gated recipe inside the lock. + +## Related + +- [Expensive command gate](/quest/m0/local-gate.md) - CPU admission the lock sits beside diff --git a/quest/m0/helpers/move.md b/quest/m0/helpers/move.md new file mode 100644 index 00000000..635c848a --- /dev/null +++ b/quest/m0/helpers/move.md @@ -0,0 +1,32 @@ +# [M] Move and delete quests with quest mv and quest rm + +## Goal + +`quest mv ` and `quest rm ` move or delete a quest or epic +and keep every root-absolute link in the tree valid. Agents stop following +`git rm` and `git mv` with `grep -r` and `sed -i` over Required links (203 +sessions since Oct 14). `quest check` already finds the broken links; these +commands avoid making them. + +## Plan + +- Decided 2026-10-19 (user): run `git mv` and `git rm`, so the change is + staged. Fail outside a git work tree rather than falling back to plain + file operations. +- `mv` rewrites every link to the moved path under `quest/`; moving an epic + directory rewrites links under it as a prefix. Moving a quest into or out + of an epic changes its structural membership; `quest check` reports what + the epic's Required still needs rather than `mv` guessing. +- `rm` drops list items that link to the deleted path (or under a deleted + epic) and deletes a section left empty, as the guide requires for an empty + Required. Removing an epic with children requires `-r`, as with `git rm`. +- Both report prose mentions of the path and mentions outside `quest/` + without editing them, and run `quest check` on the result. +- Neither touches branches or PRs: a claimed quest's branch keeps its old + name, and renaming an open PR's head branch closes the PR. +- Put the link rewriting in the core as a pure edit of documents; the CLI + owns git. Update the `delete` and `audit` skills to use `quest rm` and + `quest mv`. +- Test moving a quest, moving an epic, deleting a quest listed under several + Required and Related sections, refusing a non-empty epic without `-r`, and + a destination that already exists. diff --git a/quest/m0/helpers/status.md b/quest/m0/helpers/status.md new file mode 100644 index 00000000..a675e13e --- /dev/null +++ b/quest/m0/helpers/status.md @@ -0,0 +1,33 @@ +# [M] Report a PR's state with quest status + +## Goal + +`quest status ` prints a pull request's current state in one call, plain +or `--json`, so agents stop chaining `gh api .../reviews|comments|reactions` +and `reviewThreads` GraphQL queries, often right after `quest wait` returns +(219 of 396 sessions). It reports facts; it never decides whether the PR is +ready to merge or whose review counts. + +## Plan + +- Decided 2026-10-19 (user): report the head SHA, draft and open state, + failing and pending checks with whether each is required, mergeability, + auto-merge, and merge-queue state. +- Decided (user): report each reviewer's latest review marked current or + stale against the head, and reactions on the PR and its reviews, as + `quest wait` reports them. +- Decided (user): report unresolved review threads with their node IDs, + path, line, last author, and URL, so an agent can reply to or resolve one + without another query. +- Accept the same PR argument as `quest wait`: a GitHub PR URL, or a number + in origin. Use one GraphQL query where it fits (`statusCheckRollup` with + `isRequired(pullRequestNumber:)`, `reviews`, `reviewThreads`, + `mergeQueueEntry`, `autoMergeRequest`), paginating long lists. +- Plain output is stable lines meant for agents; `--json` is a documented, + deterministic object. Exit 0 for any PR state; non-zero only when the + command fails, matching `quest ready`. +- Point `merge`, `iterate`, and `complete` skill prose at it for reading a + PR's state, especially after `quest wait` wakes. +- Test with recorded responses: stale and current reviews, a required and an + optional failing check, a queued PR, resolved and unresolved threads, and + pagination. diff --git a/quest/m0/helpers/wait-checks.md b/quest/m0/helpers/wait-checks.md new file mode 100644 index 00000000..2271ae05 --- /dev/null +++ b/quest/m0/helpers/wait-checks.md @@ -0,0 +1,31 @@ +# [M] Wake quest wait on required CI checks + +## Goal + +`quest wait` also reports the head's required CI results, so one blocking +wait covers reviews, merges, and CI. The `merge` skill drops its "own +blocking check watcher", which led 119 of 396 sessions to poll +`gh pr checks` or write their own `wait-ci.sh`. + +## Plan + +- Decided 2026-10-19 (user): add events to every wait rather than a separate + `--checks` mode. `checks:failed` fires at the head's first failing required + check; `checks:passed` fires once every required check on the head passes. + Each event names the check and links its details. +- Decided (user): only required checks wake the wait. Read requiredness from + GraphQL `isRequired(pullRequestNumber:)` on check runs and status contexts, + which needs only read access and covers branch protection and rulesets. A + repository with no required checks treats every check as required. + Neutral and skipped results pass. Non-required failures never wake; + `quest status` lists them. +- Report a check result reached after `--since`, so a wait started after CI + finished still reports it. A new push starts over for the new head. The + resume cursor records what was reported, so resuming never replays it. +- Read checks in the existing poll; keep its interval, rate-limit handling, + and exit codes. Drop "Check runs ... are not activity" from `--help`. +- Update the `merge` and `complete` skill prose: one `quest wait` covers + CI, so delete the separate check watcher. +- Test a required failure, an optional failure that does not wake, all + required passing, no required checks, a push mid-wait, and resuming from + a cursor after a reported result. diff --git a/quest/m0/worktree-agents.md b/quest/m0/worktree-agents.md index 0bee5235..57ac09c7 100644 --- a/quest/m0/worktree-agents.md +++ b/quest/m0/worktree-agents.md @@ -12,6 +12,9 @@ checkout without waiting for the parent chat to end or the PR to merge. 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. +- 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. - 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. From 8f3c0a27e2348360768d618d727fa4f6dbf35184 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 19 Oct 2026 10:39:35 -0700 Subject: [PATCH 2/2] docs(quest): keep moved claims discoverable and claim commits unique Co-Authored-By: Claude Opus 5.5 --- quest/m0/helpers/claim.md | 2 ++ quest/m0/helpers/move.md | 9 ++++++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/quest/m0/helpers/claim.md b/quest/m0/helpers/claim.md index d5749f02..1433d75b 100644 --- a/quest/m0/helpers/claim.md +++ b/quest/m0/helpers/claim.md @@ -16,6 +16,8 @@ sessions), since `quest ready` checks no claims. branch, then pushes an empty commit with the explicit refspec `refs/heads/:refs/heads/`, never forcing. A rejected push means someone else holds the claim, which makes the push the atomic check. + Give each claim commit a random nonce, so two claimers on the same base, + identity, and second never build the same commit and both see success. Distinct exit codes separate "taken" from a failure. - Decided (user): `quest claim --release ` deletes the remote claim branch only while its tip is still the empty claim commit and it has no diff --git a/quest/m0/helpers/move.md b/quest/m0/helpers/move.md index 635c848a..5b581cc6 100644 --- a/quest/m0/helpers/move.md +++ b/quest/m0/helpers/move.md @@ -22,11 +22,14 @@ commands avoid making them. Required. Removing an epic with children requires `-r`, as with `git rm`. - Both report prose mentions of the path and mentions outside `quest/` without editing them, and run `quest check` on the result. -- Neither touches branches or PRs: a claimed quest's branch keeps its old - name, and renaming an open PR's head branch closes the PR. +- Neither touches branches or PRs, since renaming an open PR's head branch + closes the PR. `mv` refuses while the quest, or any quest under a moved + epic, has a claim branch or open PR, because the old branch name would no + longer be recognized as its claim. Use the same lookup as `quest claim`, + so whichever lands second reuses it. - Put the link rewriting in the core as a pure edit of documents; the CLI owns git. Update the `delete` and `audit` skills to use `quest rm` and `quest mv`. - Test moving a quest, moving an epic, deleting a quest listed under several Required and Related sections, refusing a non-empty epic without `-r`, and - a destination that already exists. + a destination that already exists, and refusing to move a claimed quest.