From 01e42b6367d17fbb52dc439f474695a51409c63e Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 19 Oct 2026 10:33:47 -0700 Subject: [PATCH 1/3] docs(quest): plan per-project forks and the decision paper trail Co-Authored-By: Claude Opus 5.5 --- quest/m0/kix/README.md | 2 ++ quest/m0/kix/forks.md | 38 +++++++++++++++++++++++++++++++++++++ quest/m0/kix/paper-trail.md | 33 ++++++++++++++++++++++++++++++++ 3 files changed, 73 insertions(+) create mode 100644 quest/m0/kix/forks.md create mode 100644 quest/m0/kix/paper-trail.md diff --git a/quest/m0/kix/README.md b/quest/m0/kix/README.md index 26c20eb6..302f43cf 100644 --- a/quest/m0/kix/README.md +++ b/quest/m0/kix/README.md @@ -92,6 +92,7 @@ operator-paid-hosting decisions: - [Local harness](/quest/m0/kix/harness.md) - the Worker served locally with seeded data and mocked GitHub for browser checks - [Deploy kix.quest](/quest/m0/kix/deploy.md) - the operator registers the App and deploys the Worker with GitHub sign-in at kix.quest - [Operator setup](/quest/m0/kix/operator-setup.md) - fork namespace, pilot installations, and a verified test PR +- [Per-project forks](/quest/m0/kix/forks.md) - each project publishes through its own fork, recorded by repository ID - [Runner](/quest/m0/kix/runner.md) - `quest runner` on Linux and macOS with Nix devShells, accounts, and the Claude Code adapter - [Job sandbox](/quest/m0/kix/sandbox.md) - OS-sandboxed commands, with untrusted PR devShells built in a VM on Linux runners - [opencode adapter](/quest/m0/kix/opencode.md) - OpenCode Go, ChatGPT plans, and API-key providers through opencode @@ -100,6 +101,7 @@ operator-paid-hosting decisions: - [Inbox merge](/quest/m0/kix/merge.md) - PR items merge the reviewed head through GitHub's rules - [Co-maintainer inbox](/quest/m0/kix/members.md) - every current maintainer sees enrolled projects in their inbox - [Answer flow](/quest/m0/kix/answer-flow.md) - move to the next decision after an answer, with neutral refusals +- [Decision paper trail](/quest/m0/kix/paper-trail.md) - planning PRs carry the recorded questions and answers, rendered by the service - [Agent activity](/quest/m0/kix/activity.md) - agent cards and map highlights built from checkpoint summaries - [Mobile web app](/quest/m0/kix/mobile.md) - an installable PWA with Web Push for decisions - [Web planning](/quest/m0/kix/planning.md) - issue-to-quest interviews produce draft planning PRs diff --git a/quest/m0/kix/forks.md b/quest/m0/kix/forks.md new file mode 100644 index 00000000..89637681 --- /dev/null +++ b/quest/m0/kix/forks.md @@ -0,0 +1,38 @@ +# [S] Record each project's service fork by repository ID + +## Goal + +Two enrolled upstreams with the same repository name, such as `alice/app` and +`bob/app`, each publish through their own service fork. Publication finds a +project's fork by its stored GitHub repository ID, not by +`GITHUB_FORK_OWNER/`, so names can never collide or be +mistaken for one another. + +## Plan + +Decided 2026-10-19 as a follow-up of bot publication (#145), which looks the +fork up by the upstream's name: + +- The operator keeps creating each fork by hand in the `GITHUB_FORK_OWNER` + namespace, under any name (for example `bob-app`). The App gains no + repository-creation permission. +- kix records the fork's repository ID per project when it first finds it, + after verifying that the fork's parent is that project's upstream. Later + publications use the ID and refuse a fork whose identity or parent has + changed. +- How kix first finds a fork under a non-default name (an operator-entered + name at enrollment, or a scan of the namespace for a fork whose parent is + the upstream) is an implementation choice; prefer the one with fewer + GitHub calls and no new permissions. +- A project with no recorded or discoverable fork keeps today's "provision + the service fork first" refusal, naming what the operator must create. +- Disconnecting a project clears its recorded fork. Update the fork steps in + `cloudflare/GITHUB.md`. +- Land this in m0 before launch: kix.quest is public in m0, so any enrolled + repository could collide. +- Test two same-named upstreams, a fork with a changed parent, and a missing + fork. + +## Required + +- [Operator setup](/quest/m0/kix/operator-setup.md) - the fork namespace and live fork behavior this builds on diff --git a/quest/m0/kix/paper-trail.md b/quest/m0/kix/paper-trail.md new file mode 100644 index 00000000..57a4ac40 --- /dev/null +++ b/quest/m0/kix/paper-trail.md @@ -0,0 +1,33 @@ +# [S] Render planning decisions into PRs from recorded answers + +## Goal + +A planning PR published by kix carries a decision section that the service +writes from the job's recorded questions and answers, with ✅ on each chosen +option and any free-text answer. The agent no longer writes its own paper +trail, so the record cannot be paraphrased or drift from what the maintainer +actually chose. + +## Plan + +Decided 2026-10-19 as a follow-up of bot publication (#145), which takes the +paper trail from the agent's quest files and PR body: + +- The service renders the section from the job's stored questions and + answers (the decision inbox's prompt contract) when it creates or updates + the planning PR. Prompts and answers are untrusted text: escape them as + Markdown so they cannot inject links, mentions, or closing keywords. +- Replace, don't append: the agent's PR body keeps its summary, and the + service owns the decision section. Re-rendering on later deliveries + updates the same section in place rather than duplicating it. +- Quest files still record each settled decision and its reason in their + Plan, as the guide requires; this changes only the PR's paper trail. +- Tell agents in kix planning jobs, through the job's own instructions + rather than the shared skills, not to write the trail. Local agents running + the skills without kix keep writing their own. +- Test multi-round interviews, free-text answers, hostile Markdown in a + prompt, and a re-delivery that updates the section. + +## Required + +- [Decision inbox](/quest/m0/kix/prompts.md) - the recorded prompt and answer format this renders From 44a8b19d6d844b0ba12860aaef40ef2371ff9346 Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 19 Oct 2026 10:38:26 -0700 Subject: [PATCH 2/3] docs(quest): neutralize GitHub references and filter operational prompts in the paper trail Co-Authored-By: Claude Opus 5.5 --- quest/m0/kix/paper-trail.md | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/quest/m0/kix/paper-trail.md b/quest/m0/kix/paper-trail.md index 57a4ac40..558daec2 100644 --- a/quest/m0/kix/paper-trail.md +++ b/quest/m0/kix/paper-trail.md @@ -15,8 +15,15 @@ paper trail from the agent's quest files and PR body: - The service renders the section from the job's stored questions and answers (the decision inbox's prompt contract) when it creates or updates - the planning PR. Prompts and answers are untrusted text: escape them as - Markdown so they cannot inject links, mentions, or closing keywords. + the planning PR. Include only `decision` questions. Operational kinds such + as `account` and `publication` stay out, since they can name runners and + accounts in a public PR. +- Prompts and answers are untrusted text. Escaping Markdown is not enough: + also neutralize GitHub's own semantics, so no `@` mention notifies anyone, + no `#N`, `owner/repo#N`, or commit reference autolinks, no bare URL links, + and no closing keyword (`Closes #N`, `Fixes`, `Resolves`) links or closes + an issue. For example, render all prompt text in code spans or break each + pattern with a zero-width character. - Replace, don't append: the agent's PR body keeps its summary, and the service owns the decision section. Re-rendering on later deliveries updates the same section in place rather than duplicating it. @@ -25,8 +32,11 @@ paper trail from the agent's quest files and PR body: - Tell agents in kix planning jobs, through the job's own instructions rather than the shared skills, not to write the trail. Local agents running the skills without kix keep writing their own. -- Test multi-round interviews, free-text answers, hostile Markdown in a - prompt, and a re-delivery that updates the section. +- Test multi-round interviews, free-text answers, a re-delivery that + updates the section, and a planning job that hit an account limit, whose + account question must not appear. Cover hostile prompts with Markdown, + `@user` and `@org/team` mentions, bare URLs, issue and cross-repository + references, and closing keywords. ## Required From 2996ab3b421dc82077d610988861b0f9305edb1d Mon Sep 17 00:00:00 2001 From: Luke Curley Date: Mon, 19 Oct 2026 10:42:27 -0700 Subject: [PATCH 3/3] docs(quest): filter the paper trail to agent decision prompts Co-Authored-By: Claude Opus 5.5 --- quest/m0/kix/paper-trail.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/quest/m0/kix/paper-trail.md b/quest/m0/kix/paper-trail.md index 558daec2..09a1672e 100644 --- a/quest/m0/kix/paper-trail.md +++ b/quest/m0/kix/paper-trail.md @@ -15,8 +15,9 @@ paper trail from the agent's quest files and PR body: - The service renders the section from the job's stored questions and answers (the decision inbox's prompt contract) when it creates or updates - the planning PR. Include only `decision` questions. Operational kinds such - as `account` and `publication` stay out, since they can name runners and + the planning PR. Include only answered `agent` questions whose prompt is a + `decision`, not a `permission` request. Operational question kinds such as + `account` and `publication` stay out, since they can name runners and accounts in a public PR. - Prompts and answers are untrusted text. Escaping Markdown is not enough: also neutralize GitHub's own semantics, so no `@` mention notifies anyone,