Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions quest/m0/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
47 changes: 47 additions & 0 deletions quest/m0/helpers/README.md
Original file line number Diff line number Diff line change
@@ -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 <name>` 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
24 changes: 24 additions & 0 deletions quest/m0/helpers/afk.md
Original file line number Diff line number Diff line change
@@ -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`.
35 changes: 35 additions & 0 deletions quest/m0/helpers/claim.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# [S] Claim and release quests with quest claim

## Goal

`quest claim <quest>` 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/<branch>:refs/heads/<branch>`, never forcing. A rejected push
means someone else holds the claim, which makes the push the atomic check.
Comment thread
kixelated marked this conversation as resolved.
Resolved
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 <quest>` 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.
33 changes: 33 additions & 0 deletions quest/m0/helpers/gate-lock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# [S] Serialize commands with quest gate --lock

## Goal

`quest gate --lock <name> <cmd>` 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
35 changes: 35 additions & 0 deletions quest/m0/helpers/move.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# [M] Move and delete quests with quest mv and quest rm

## Goal

`quest mv <from> <to>` and `quest rm <path>` 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.
Comment on lines +23 to +24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle prose links before deleting their target

When a deleted quest is referenced by an inline Markdown link in a Goal or Plan, rm only drops linked list items and this clause leaves the prose reference unchanged. Deleting the target then makes quest check report a dangling link, contradicting the command’s promise to avoid creating broken links; update or remove these links, or refuse the deletion before staging it, rather than merely reporting them.

AGENTS.md reference: assets/AGENTS.md:L137-L140

Useful? React with 👍 / 👎.

- 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, and refusing to move a claimed quest.
33 changes: 33 additions & 0 deletions quest/m0/helpers/status.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# [M] Report a PR's state with quest status

## Goal

`quest status <pr>` 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.
31 changes: 31 additions & 0 deletions quest/m0/helpers/wait-checks.md
Original file line number Diff line number Diff line change
@@ -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.
3 changes: 3 additions & 0 deletions quest/m0/worktree-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading