@openora/create 0.4.1-canary.31 → 0.4.1-canary.310

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/generated/core-version.d.ts +1 -1
  3. package/dist/generated/core-version.d.ts.map +1 -1
  4. package/dist/generated/core-version.js +1 -1
  5. package/dist/generated/core-version.js.map +1 -1
  6. package/dist/index.js +47 -92
  7. package/dist/index.js.map +1 -1
  8. package/dist/render.d.ts +15 -0
  9. package/dist/render.d.ts.map +1 -0
  10. package/dist/render.js +125 -0
  11. package/dist/render.js.map +1 -0
  12. package/package.json +7 -5
  13. package/template/README.md.tpl +12 -7
  14. package/template/__dot__claude/settings.json.tpl +22 -12
  15. package/template/__dot__env.example +10 -0
  16. package/template/__dot__gitignore +6 -1
  17. package/template/__dot__rulesync/commands/adr.md +32 -0
  18. package/template/__dot__rulesync/commands/check.md +11 -10
  19. package/template/__dot__rulesync/commands/doctor.md.tpl +17 -0
  20. package/template/__dot__rulesync/commands/scaffold-module.md +3 -2
  21. package/template/__dot__rulesync/commands/scaffold-plugin.md +19 -3
  22. package/template/__dot__rulesync/commands/scaffold-route.md +1 -0
  23. package/template/__dot__rulesync/commands/start.md +2 -2
  24. package/template/__dot__rulesync/hooks/_shared.mjs +5 -0
  25. package/template/__dot__rulesync/hooks/guard-core.mjs.tpl +75 -26
  26. package/template/__dot__rulesync/hooks/guard-generated.mjs +12 -5
  27. package/template/__dot__rulesync/hooks/guard-mr.mjs +81 -0
  28. package/template/__dot__rulesync/hooks/guard-subagent.mjs +22 -6
  29. package/template/__dot__rulesync/hooks/post-edit.mjs.tpl +106 -0
  30. package/template/__dot__rulesync/hooks.json +27 -4
  31. package/template/__dot__rulesync/rules/conventions.md +114 -0
  32. package/template/__dot__rulesync/rules/db-conventions.md +6 -72
  33. package/template/__dot__rulesync/rules/e2e-conventions.md +52 -0
  34. package/template/__dot__rulesync/rules/frontend-conventions.md.tpl +35 -0
  35. package/template/__dot__rulesync/rules/oss-boundaries.md.tpl +78 -0
  36. package/template/__dot__rulesync/rules/overview.md +18 -73
  37. package/template/__dot__rulesync/skills/create-plugin/{SKILL.md → SKILL.md.tpl} +13 -24
  38. package/template/__dot__rulesync/skills/create-pr/SKILL.md.tpl +38 -0
  39. package/template/__dot__rulesync/skills/create-task/{SKILL.md → SKILL.md.tpl} +14 -22
  40. package/template/__dot__rulesync/skills/create-ui-module/SKILL.md.tpl +60 -0
  41. package/template/__dot__rulesync/skills/enhance-prompt/{SKILL.md → SKILL.md.tpl} +4 -4
  42. package/template/__dot__rulesync/skills/handoff/SKILL.md +95 -0
  43. package/template/__dot__rulesync/skills/review/SKILL.md.tpl +277 -0
  44. package/template/__dot__rulesync/skills/ship/SKILL.md.tpl +149 -0
  45. package/template/__dot__rulesync/skills/ship/handoff.md.tpl +48 -0
  46. package/template/__dot__rulesync/skills/ship/watch-pr.mjs +168 -0
  47. package/template/__dot__rulesync/subagents/builder.md.tpl +115 -0
  48. package/template/__dot__rulesync/subagents/compliance-reviewer.md +78 -0
  49. package/template/__dot__rulesync/subagents/debugger.md.tpl +86 -0
  50. package/template/__dot__rulesync/subagents/deployer.md.tpl +54 -0
  51. package/template/__dot__rulesync/subagents/expert.md +28 -34
  52. package/template/__dot__rulesync/subagents/planner.md.tpl +39 -0
  53. package/template/__dot__rulesync/subagents/quality-reviewer.md.tpl +112 -0
  54. package/template/__dot__rulesync/subagents/security-reviewer.md.tpl +85 -0
  55. package/template/__dot__rulesync/subagents/tester.md.tpl +88 -0
  56. package/template/__dot__rulesync/sync.json.tpl +26 -0
  57. package/template/apps/api/package.json.tpl +1 -2
  58. package/template/apps/api/src/extensions.config.ts.tpl +12 -0
  59. package/template/apps/api/src/main.ts.tpl +1 -4
  60. package/template/apps/api/src/seed.ts.tpl +8 -1
  61. package/template/docker-compose.yml +13 -0
  62. package/template/docs/agents/cross-repo.md.tpl +37 -0
  63. package/template/docs/agents/forge.md.tpl +54 -0
  64. package/template/docs/agents/issue-tracker.md.tpl +42 -0
  65. package/template/docs/standards/comments.md +16 -0
  66. package/template/docs/standards/database.md +77 -0
  67. package/template/docs/standards/enforcement.md +12 -0
  68. package/template/docs/standards/errors.md +26 -0
  69. package/template/docs/standards/frontend.md +60 -0
  70. package/template/docs/standards/functions.md +38 -0
  71. package/template/docs/standards/git-delivery.md +20 -0
  72. package/template/docs/standards/module-structure.md +37 -0
  73. package/template/docs/standards/testing.md +72 -0
  74. package/template/docs/standards/types.md +31 -0
  75. package/template/package.json.tpl +11 -5
  76. package/template/rulesync.jsonc +1 -1
  77. package/template/tools/oss-worktree.mjs.tpl +105 -0
  78. package/template/tools/review-precheck.mjs +531 -0
  79. package/template/tools/sync-agents.mjs +257 -0
  80. package/template/turbo/generators/config.ts +1 -1
  81. package/template/turbo.json +14 -2
  82. package/template/__dot__rulesync/hooks/post-edit.mjs +0 -57
  83. package/template/__dot__rulesync/skills/add-feature/SKILL.md +0 -113
  84. package/template/__dot__rulesync/skills/add-feature/handoff.md +0 -58
  85. package/template/__dot__rulesync/skills/code-review/SKILL.md +0 -111
  86. package/template/__dot__rulesync/skills/create-pr/SKILL.md +0 -55
  87. package/template/__dot__rulesync/subagents/builder.md +0 -93
  88. package/template/__dot__rulesync/subagents/debugger.md +0 -83
  89. package/template/__dot__rulesync/subagents/deployer.md +0 -66
  90. package/template/__dot__rulesync/subagents/qa.md +0 -88
  91. package/template/apps/api/src/migrate.ts.tpl +0 -46
@@ -0,0 +1,95 @@
1
+ ---
2
+ name: handoff
3
+ description: >
4
+ Package the current task into a self-contained prompt another agent (a
5
+ teammate, or a fresh Claude session in another repo) can execute without this
6
+ conversation. Gathers context from the chat so far plus live repo/environment
7
+ state, then emits a copy-pasteable handoff. Use on "hand this off", "prompt for
8
+ another agent", "write a handoff", when routing an OSS-core change into the
9
+ platform repo, or /handoff [what to hand off | target agent/repo]. Produces a
10
+ copy-pasteable prompt and may use any tool to gather context; the one hard line
11
+ is never force-push.
12
+ allowed-tools:
13
+ - Read
14
+ - Grep
15
+ - Glob
16
+ - Write
17
+ - Edit
18
+ - Bash
19
+ disallowed-tools:
20
+ - Bash(git push --force:*)
21
+ - Bash(git push -f:*)
22
+ - Bash(git push --force-with-lease:*)
23
+ - Bash(git push --force-with-lease)
24
+ - Bash(git push -f)
25
+ ---
26
+
27
+ # handoff - write a self-contained prompt for another agent
28
+
29
+ Turn "what we're doing" into a prompt a _stranger_ agent can act on with zero access to this
30
+ chat. The receiver has none of our context, so the prompt must carry all of it.
31
+
32
+ Common use here: an OSS-core change that should run in a separate session. Any paired change can
33
+ be made here, in an OSS worktree - see "Changing OSS core" in the `oss-boundaries` rule. When it
34
+ runs elsewhere, the receiver is a teammate or a new agent session rooted in the platform
35
+ checkout, and either way it needs a standalone brief.
36
+
37
+ Optional argument = what to hand off / who to (e.g. `the OSS core publish fix`, `to a teammate in
38
+ the platform repo`, a repo path, an issue/MR#). No argument -> hand off the current in-flight task.
39
+
40
+ ## Rules
41
+
42
+ - **One hard line: never force-push** (`git push --force` / `-f` / `--force-with-lease`), in any
43
+ repo, ever - it rewrites shared history. Every other tool is fair game. The skill's main output
44
+ is still the prompt; take further action (commit, push, spawn, launch) only on explicit confirmation.
45
+ - **Self-contained.** The receiver can't see this conversation. Inline every fact they need:
46
+ exact paths, branch/remote names, IDs (MR/PR/ticket), commands, versions, error strings.
47
+ No "as discussed", no "the file we changed", no unresolved pronouns.
48
+ - **Facts over memory.** Verify the moving parts against live state (git, files, CLIs) before
49
+ writing them - don't trust half-remembered branch names or versions.
50
+ - **No secrets.** Never inline tokens, passwords, or `.env` values. Reference the env var name.
51
+ - **Scope, don't dump.** Include what's load-bearing for the task; link/name the rest.
52
+
53
+ ## Step 1 - Resolve scope
54
+
55
+ From the argument + the conversation, state in one line: the goal, the target repo/dir, and (if
56
+ known) the agent type or persona best suited. If genuinely ambiguous, ask one clarifying question;
57
+ otherwise proceed with the obvious reading and note the assumption.
58
+
59
+ ## Step 2 - Gather live context
60
+
61
+ Pull only what the task touches (skip irrelevant ones):
62
+
63
+ - Repo/env: `pwd`; `git -C <dir> remote -v`; `git -C <dir> branch --show-current`;
64
+ `git -C <dir> status --short`; recent `git log --oneline -5`. Note default/target branch.
65
+ - Work state: relevant file paths (verify they exist), functions/symbols, versions/pins,
66
+ exact error messages or failing job names, IDs (MR/PR/ticket/pipeline).
67
+ - Conventions the receiver must follow: point at the repo's rules (`CLAUDE.md`,
68
+ `.rulesync/`, `AGENTS.md`) rather than restating them; call out any that bit us.
69
+ - What's already done vs. what remains (so they don't redo or undo work).
70
+
71
+ ## Step 3 - Emit the handoff
72
+
73
+ Output one fenced markdown block (so it copy-pastes cleanly), using these headings - drop any
74
+ that don't apply, never pad:
75
+
76
+ - **Task** - one imperative sentence: the outcome wanted.
77
+ - **Environment** - repo(s), absolute path(s), remote(s), current + target branch, sibling deps.
78
+ - **Background** - the why + current state + root cause/findings already established. This is
79
+ where prior investigation goes so it isn't repeated.
80
+ - **Do this** - ordered, concrete steps. Name files/symbols/commands. Mark decisions that need
81
+ a human ("report the plan first, don't push").
82
+ - **Verify** - the exact commands/gates that must pass, and the expected green result.
83
+ - **Constraints** - boundaries (read-only zones, "never push without explicit yes", conventional
84
+ commits, branch-off-target, don't touch X). Inherit the repo's rules; restate only the sharp edges.
85
+
86
+ After the block, in <=2 lines: state the key assumption you made, and offer to (a) tweak the
87
+ prompt, (b) save it to a file, or (c) launch it now (spawn a teammate with a suitable agent type,
88
+ or hand it to the operator to paste into a session rooted in the target repo). Only save or launch
89
+ on explicit confirmation.
90
+
91
+ ## Quality bar
92
+
93
+ A good handoff passes this test: **hand it to someone who has never seen this repo or chat, and
94
+ they can start in under a minute and finish without asking you anything.** If a step assumes
95
+ context the block doesn't contain, fix the block.
@@ -0,0 +1,277 @@
1
+ ---
2
+ name: review
3
+ targets: ['*']
4
+ description: Multi-agent code review of the working branch against this repo's conventions, OSS-core boundaries, frontend rules, security, and operator-domain fit. Fans out a configurable number of parallel reviewers, each grounded in the rule docs, then synthesizes one verdict. Use on "review this", "code review", "/review", optionally "--agents N", "--base <ref>", "--fix", "--post" (publish findings to the pull request as inline comments + a summary verdict), "--yes" (post without confirming), "--ci" (non-interactive, exit code from the verdict), a pull-request number, or paths.
5
+ ---
6
+
7
+ # review ({{name}})
8
+
9
+ You are the orchestrator: scope the diff, fan out N reviewers across dimensions, dedup findings, report ONE verdict. Report-only unless `--fix`.
10
+
11
+ Checklist - tick as you go:
12
+
13
+ ```
14
+ - [ ] 1. Parse args (--agents / --base / MR# / paths / --fix / --post / --yes / --ci)
15
+ - [ ] 2. Run the precheck: scope, mechanical facts, domain hits; if empty, ask (or APPROVED under --ci)
16
+ - [ ] 2a. Previous review? Go incremental from its SHA and carry its findings
17
+ - [ ] 3. Collect task context (ticket AC + MR discussion)
18
+ - [ ] 3a. Paired OSS change? Review the OSS diff by the OSS rules + cross-check the contract (§2c)
19
+ - [ ] 3c. Trace each changed entry point end to end + check the blast radius
20
+ - [ ] 4. Cover all seven dimensions; spawn the two-lens roster in ONE message, whatever the diff size
21
+ - [ ] 5. Dedup + apply the evidence gate
22
+ - [ ] 6. Report one DIMENSION line per dimension + one verdict (+ apply fixes only if --fix)
23
+ - [ ] 7. Post to the MR as inline comments + summary (only if --post)
24
+ ```
25
+
26
+ ## 1. Parse `$ARGUMENTS`
27
+
28
+ - `--agents N` - parallel reviewers (2-4); default 2 (§5).
29
+ - `--base <ref>` - diff base; default `{{mrTarget}}`.
30
+ - `--full` - ignore the previous review (§2a) and review the whole change.
31
+ - `<number>` - a pull request: read its patch and intent with the commands in `docs/agents/forge.md`.
32
+ - paths - restrict review to those files/dirs.
33
+ - `--fix` - apply BLOCK/WARN fixes after the review; default report-only.
34
+ - `--post` - publish findings to the pull request as inline diff-line comments + a one-line summary verdict (§8). Requires a pull-request number. Draft-and-confirm by default.
35
+ - `--yes` - with `--post`, skip the confirmation and publish straight away.
36
+ - `--ci` - non-interactive: never ask, never post, never fix; print only the §7 machine block. Implies `--full`: a gate never trusts a prior-review marker, since anyone who can comment on the pull request can post one for the current head. The model cannot set the process exit code; the CI job derives it from the output, e.g. `claude -p '/review --ci' > review.txt; [ "$(grep -c '^DIMENSION: ' review.txt)" -eq 7 ] && grep -q '^VERDICT: APPROVED' review.txt` - a review that skipped a dimension fails the job even when it approves. An empty diff is APPROVED with zero findings.
37
+
38
+ ## 2. Scope the diff
39
+
40
+ **Reviewing a pull request by number:** reviewers need files to open, and the working tree is not theirs to switch. Fetch the source branch and add a detached worktree at the pull request's head SHA, never at `FETCH_HEAD` (a failed fetch leaves it pointing at the previous ref): `git fetch origin <src-branch> && git worktree add --detach .claude/worktrees/review-<n> <head-sha>` and `pnpm install --offline --frozen-lockfile` in it (the tests in §3c need it), then confirm `git -C .claude/worktrees/review-<n> rev-parse HEAD` equals `<head-sha>` and stop if it does not. An existing `review-<n>` worktree is reset to `<head-sha>`, not reused as is. Pass the worktree path to every reviewer and remove it with `git worktree remove` after §7.
41
+
42
+ **Run the precheck before anything else reads code.** From the directory under review (the review worktree, or the working tree), run the main checkout's script - it is rendered and gitignored, so a worktree lacks it: `node <main-checkout>/tools/review-precheck.mjs --base origin/<base>` (add `--since <sha>` from §2a). It costs no tokens beyond its output and replaces what reviewers used to derive by reading:
43
+
44
+ - `SCOPE:` - mode (`full` / `incremental`) and the reviewable changed-line count that sets the split and budgets in §5.
45
+ - `RISK:` - `low`, `medium`, `high`, or `critical` from the changed paths and domain hits; it sets the reviewer effort in §5. Never judge risk from the title or the line count: a 30-line change can add a route, a table, or a migration. The tier is a floor: after reading the diff you may raise it (a component rendering untrusted HTML, a hook that moves money), never lower it; say why in the report.
46
+ - `REVIEWABLE:` - the only file list reviewers get. Group these by app/package so reviewers and any file split share one map.
47
+ - `SKIPPED:` - lockfiles, locale data, tests, generated files. No reviewer opens them; the precheck's i18n facts and CI's frozen-lockfile install stand in. List them in the report so nothing is silently dropped.
48
+ - `PRECHECK:` - mechanical hits on added lines (casts, widened maps, hardcoded limits, hand memo, banned classes, locale parity, missing keys). Reviewers judge these; they never re-derive them.
49
+ - `DOMAIN:` / `DOMAIN-HIT:` - security and compliance keyword hits; they pick each reviewer's mode in §5.
50
+
51
+ No `REVIEWABLE:` and no `SKIPPED:` lines: fall back to `git status -s`; if still empty, ask (under `--ci`: APPROVED, zero findings).
52
+
53
+ **Rule docs live in the main checkout, not the review worktree.** `.claude/rules/`, `.rulesync/rules/`, `docs/standards/`, and `docs/agents/` are rendered by `pnpm sync:agents` + `pnpm gen:agents` and gitignored, so a fresh worktree has none of them. Pass reviewers the absolute main-checkout path for every rule doc. When the render has not run (a CI job that skips `prepare`), run `pnpm sync:agents && pnpm gen:agents` before reviewing.
54
+
55
+ ## 2a. Previous review - review only what changed since
56
+
57
+ A pull request is reviewed round after round; re-reading the whole change each round is the biggest waste. Unless `--full` or `--ci`:
58
+
59
+ 1. Read `.claude/reviews/<pr>.json` in the main checkout (`{ "sha", "base", "verdict", "findings": [...], "dimensions": [...] }`; no PR number: key it by branch name). Absent and a PR number given: find the latest note carrying `<!-- review:sha=<sha> -->` per `docs/agents/forge.md` and take its SHA; its findings are the inline threads still unresolved.
60
+ 2. Found: run the precheck with `--since <sha>`. `mode incremental` narrows `REVIEWABLE:`, its line counts, `PRECHECK:`, and `DOMAIN-HIT:` to what changed since that review (base-branch merges excluded). A `NOTE: --since ... not an ancestor` (force push, rebase) means a full review - say so.
61
+ 3. Split the prior findings: those on a file in the new `REVIEWABLE:` set go to the owning reviewer to re-verify; the rest carry over unchanged.
62
+
63
+ ## 2b. Collect task context (mandatory - this is the spec axis)
64
+
65
+ Distill everything here into ONE context block of at most ~40 lines; it is the only task context reviewers receive.
66
+
67
+ - **Ticket - read it whole, per `docs/agents/issue-tracker.md`.** Resolve the `{{trackerKey}}-n` key from the MR description (`Closes {{trackerKey}}-n`), MR title, branch, or commit subjects. Read: description + AC, every comment, every attached image viewed as pixels, parent epic, linked issues, and every wiki page the ticket links (their images and comments too). Use a reader that returns image bytes (for Jira + Confluence: the `atlassian-read` skill - `read.py issue {{trackerKey}}-n`, then `page <id>` per linked page - or REST); the Atlassian MCP returns none, so it is never enough on its own. A chat thread is optional: read it (via `slack-reader` when available) only when the ticket or MR points at one ("shared in chat", a Slack link) and the AC depend on it.
68
+ - **Distill:** goal in one line; AC quoted verbatim as bullets (a `CRITERION:` line needs the exact bullet); decisions and open questions from comments (who, when); design references (which screenshot shows what); out-of-scope lines.
69
+ - **Pull-request discussion.** If reviewing one: read its description and every thread, resolved ones included, per `docs/agents/forge.md`. Distill to stated intent, open reviewer asks, and the decisions resolved threads settled (quote who asked for what and what was agreed), so the review doesn't repeat or contradict them. No pull request: use branch commit subjects as intent.
70
+ - **Reviewers have no forge access.** You own the description checks: the manual-verification evidence and the "Tests" list (§3c). Report them yourself; never hand them to a reviewer.
71
+ - **No key** -> write `no ticket` in the report and judge against the MR description only. **Fetch failed** -> write `no access`. Never skip silently, never invent AC.
72
+ - A UI change whose ticket carries design screenshots is judged against them: compare the rendered UI (`playwright-cli` screenshot when the stack is up) with the reference; when you cannot, the CRITERION is `not verifiable`, never `met`.
73
+ - The MR description is the author's claim, not the spec. Where it contradicts the ticket or the diff, that contradiction is a finding.
74
+
75
+ ## 2c. Paired OSS change - review the platform whole (mandatory)
76
+
77
+ A consumer change is often half of a pair. The OSS half is reviewed here too, so the verdict covers the platform, not one repo.
78
+
79
+ **Find the pair** - first match wins:
80
+
81
+ 1. The same branch name in `{{ossDir}}`: a worktree under `{{ossDir}}/.worktrees/`, a local branch (`git -C {{ossDir}} branch --list <branch>`), or an open OSS PR (`gh pr list --head <branch>` run in `{{ossDir}}`).
82
+ 2. A changed `@openora/*` version in `package.json`. The OSS diff is the range between the two canaries: `X.Y.Z-canary.N` was built by OSS pipeline run `N`, so resolve each side with `gh run list -R blurifycom/openora -w pipeline.yml -L 500 --json number,headSha --jq '.[] | select(.number==N) | .headSha'`, then `git -C {{ossDir}} fetch origin` and `git -C {{ossDir}} diff <old-sha>...<new-sha>`.
83
+
84
+ No match: write `no paired OSS change` in the report and move on.
85
+
86
+ **Read the OSS code without touching the main checkout.** Case 1: `pnpm oss:worktree <branch>` (idempotent) and read from that worktree. Case 2: `git -C {{ossDir}} show <sha>:<path>`. Never `git checkout` in `{{ossDir}}` - other sessions build against it.
87
+
88
+ **Review the OSS diff by the OSS rules.** Read `<worktree>/docs/standards/skills/review.md` and every `<worktree>/.rulesync/rules/*.md`. Run their request trace and dimensions on `git -C <worktree> diff origin/dev...HEAD`. OSS files join §4 as their own file group, handed to `quality-reviewer` (plus `security-reviewer` for auth paths and `compliance-reviewer` for money, wallet, KYC, or RG paths) with the worktree path. Their findings are prefixed `[oss]`, cite the OSS rule or ADR, and pass the same evidence gate (§6).
89
+
90
+ **Cross-check the contract** - what neither repo's review sees alone:
91
+
92
+ - Every export, route, event payload, config field, or table the OSS diff changes: `git grep -w` it in this repo and confirm each use still compiles and still means the same thing. A consumer caller that no longer holds is a `[BLOCK]`.
93
+ - Every consumer change that relies on the OSS change (a new export, a changed signature or behavior) is matched in the OSS diff. Consumer code relying on OSS behavior the diff does not ship is a `[BLOCK]`.
94
+ - Genericity: OSS code that encodes this operator's behavior - a jurisdiction rule, a vendor, a limit or flow only this repo needs - instead of a seam (adapter token, event, config field, hook) is a `[BLOCK]`; the behavior moves here and core keeps the seam. An OSS PR whose Why does not say why the change cannot live in the consumer is a `[WARN]`.
95
+ - Public record: operator names, internal URLs, ticket text, or operator-specific domain detail in the OSS commits or PR is a `[BLOCK]`.
96
+ - Release order: a consumer request that needs the OSS change can merge only once the `@openora/*` pin points at a canary that carries it. Say so in the report when the pin is older.
97
+ - When a trace needs runtime proof: `pnpm oss:worktree <branch> --link`, run the touched tests, then `pnpm link:oss` to restore the main checkout link.
98
+
99
+ Report `[oss]` findings and one `TRACE:` line per OSS entry point alongside the consumer ones. The verdict covers both.
100
+
101
+ ## 3. Ground every reviewer (mandatory)
102
+
103
+ Each reviewer MUST read the changed code AND the rule docs owning its dimension before judging - never infer behavior from a diff hunk; if a finding depends on a called function, open it. Each agent file carries a reading map: the few docs its focus needs, not every rule. Pass the main-checkout paths; the reviewer reads only its map, and a `docs/standards/` deep dive only for the row a finding depends on.
104
+
105
+ You read `CLAUDE.md` / `AGENTS.md` (the rendered `overview` rule) and `.claude/rules/workflow.md` once, for §2b and the `rollout` and `spec` dimensions. Reviewers get the distilled context block, never those files.
106
+
107
+ No rule doc covers performance, scalability, or most security concerns. There a finding cites the named, established principle it breaks instead (N+1, unbounded list, silent truncation, authz enforced only client-side, unvalidated URL rendered to players) - §6 accepts that citation.
108
+
109
+ ## 3b. Stance - assume the change is broken
110
+
111
+ Review to falsify, not to confirm. Every reviewer (and you, on `rollout` and `spec`) starts from "this code does not work" and lets the diff earn correctness:
112
+
113
+ - For each changed behavior, trace the concrete execution path with real inputs - happy path plus at least one hostile one (empty/`''`/`0`, error, unauthorized, concurrent/repeat) - until you hit a defect or prove it sound. Reading the diff hunk is never enough.
114
+ - Verify the called API actually behaves as the code assumes - open the callee or check current docs. Watch for falsy-vs-nullish, off-by-default options, swallowed rejections, partial failure mid-flow.
115
+ - Author claims prove nothing: commit message, comments, green gates, and "obviously correct" wrappers are not evidence.
116
+ - Skepticism picks what to dig into; §6 still decides what becomes a finding - only a traced trigger path qualifies.
117
+
118
+ ## 3c. Request trace - end to end, then blast radius (mandatory)
119
+
120
+ Applies to every change that crosses a layer: an oRPC route, a service, a Drizzle query, a table, an event, or a job. Skip only for a change inside one pure function, a test, a doc, or a type. Money, wallet, payment, auth/session, KYC, and RG paths always get a trace.
121
+
122
+ **UI-only diff** (no route, service, query, table, event, or job changed in this repo): trace each changed data hook to the platform route it calls - hops 1, 2, and 7 only (input schema, guard, response fields) - and say so in the `TRACE:` line. The full walk is for layers this repo owns.
123
+
124
+ **Walk the hops.** For each changed route or entry point, list the hops in order and open the code at each one - the diff hunk is never enough:
125
+
126
+ 1. Contract - the input schema is the only input; every field the handler reads is declared and validated.
127
+ 2. Handler - guards run first; the operator, player, or actor id comes from the session, never from the body.
128
+ 3. Service - open every callee; typed failures return, unexpected errors do not leak to the client.
129
+ 4. Query - every read and write filters by owner/tenant; a write and its ledger/audit row share one transaction.
130
+ 5. Table - the invariant lives in a constraint, index, or FK per `docs/standards/database.md`, not only in code; a migration exists for every schema change.
131
+ 6. Side effects - an event, job, or outbox message fires after commit and its handler is safe to run twice.
132
+ 7. Response - output matches the contract schema and leaks no extra field; each error path returns the code the client expects.
133
+
134
+ **Check the blast radius.** The change must not break a part it does not name. Build the caller list with `git grep -w -- <symbol> -- '*.ts' '*.tsx' '*.sql'` for each changed export, table symbol, and SQL table name, then confirm each use still holds:
135
+
136
+ - A changed table, column, enum, or constraint: every query, migration, seed, and schema export that touches it.
137
+ - A changed query or repository function: every caller, traced through hops 4-7.
138
+ - A changed service function: every caller, including jobs, event handlers, and other modules.
139
+ - A changed contract or shared type: every consumer, including the UI apps and the shared UI package.
140
+ - A changed event or job payload: every handler, and that it accepts the old and the new shape during rollout.
141
+
142
+ **Check the migration.** For each changed `.sql` under `drizzle/migrations/`, read the SQL. A `DROP`, a `RENAME`, or a column type change breaks the instances still running the previous release - `[BLOCK]` in the same MR as the reader change; it ships in a later release, after every reader of the old shape is deployed. A new `NOT NULL` column without a default fails on existing rows - `[BLOCK]`. Expand first, contract later. A hand-edited migration is a `[BLOCK]` (`docs/standards/database.md`).
143
+
144
+ **Prove with tests.** The orchestrator may run the tests of a touched module, never the full gate: `pnpm vitest related <path>` for each caller in the blast radius, plus any existing `apps/e2e` spec that already drives the changed route. A failing test is a `[BLOCK]` with the test name as evidence; a caller with no test is `[INFO]`, not a request to write one. Tests that could not run are reported as `TESTS: not run - <reason>`, never skipped silently, and forbid APPROVED on `high` or `critical` risk.
145
+
146
+ **A feature or fix PR ships its own tests** (`docs/standards/testing.md`) - a changed behaviour with no test at the right tier is a `[WARN]`, NEVER a `[BLOCK]`. Check too that the description carries the manual-verification evidence (a short video per acceptance criterion, before/after on a fix, or the request/response trace for an API-only change) and a "Tests" list that matches the tests in the diff. Missing evidence on a user-visible change is a `[WARN]`; a "Tests" list that contradicts the diff is a finding.
147
+
148
+ **Report the trace.** One `TRACE:` line per entry point (format in §7). A missing hop, an unfiltered query, a write outside the transaction, or a caller that no longer holds is a `[BLOCK]`. A hop that could not be traced is a finding, not a silent pass.
149
+
150
+ ## 4. Dimensions - all seven, every review
151
+
152
+ Every review covers every dimension below, whatever the diff touches. Relevance is decided by looking, not by guessing from file names: a dimension that does not apply still runs its search and reports `n/a` with what it checked. Owners - never `general-purpose`:
153
+
154
+ | Dimension | Owner | Covers |
155
+ | ------------- | ----------------------------------------- | --------------------------------------------------------------------------------------- |
156
+ | `conventions` | `quality-reviewer` | correctness, boundaries, conventions, UI quality (i18n, a11y, states), dependencies |
157
+ | `performance` | `quality-reviewer` | performance and scalability at production scale |
158
+ | `reliability` | `quality-reviewer` | races, double submit, retries, partial failure, cache invalidation, error handling |
159
+ | `security` | `security-reviewer` (focus `risk`) | authz, secrets and PII, input validation, URLs |
160
+ | `compliance` | `security-reviewer` (focus `risk`) | responsible gambling, KYC/age/geo gates, ledger and money paths, audit trail |
161
+ | `rollout` | orchestrator | §3c migrations, destructive seeds, event and payload compatibility, new env/config |
162
+ | `spec` | orchestrator | AC (§2b), ticket scope, manual-verification evidence and "Tests" (§3c) |
163
+
164
+ `expert` is not a reviewer; ask it only when an AC is ambiguous enough to block a `CRITERION:` line.
165
+
166
+ Reviewers split by what they read, never by checklist. An agent's cost is its tool calls times its context: a checklist adds a few thousand tokens, while two reviewers reading the same files pay for those files twice.
167
+
168
+ **No inline fast path.** Every diff, however small, goes to the two lens reviewers in §5. One reviewer working every checklist finds about half of what two focused lenses find, for most of their cost; a small diff is cheap for them anyway.
169
+
170
+ ## 5. Allocate to `--agents N`
171
+
172
+ - N unset or 2: `quality-reviewer` with no focus - the correctness lens (failure branches, races, rollout, blast radius, performance, conventions; owns `conventions`, `performance`, `reliability`) - and `security-reviewer` with focus `risk` - the risk lens (guards, money, regulated gates, and whether the change does what its title claims; also runs the `compliance-reviewer` checklist; owns `security` and `compliance`).
173
+ - N = 3: a second `quality-reviewer`, the file groups split between the two (state the split; never silently drop files). The default when `REVIEWABLE:` changed lines exceed 1500.
174
+ - N = 4: also split `risk` back into `security-reviewer` and `compliance-reviewer`.
175
+ - N < 2: refuse the reduction - run the two and say so in the report.
176
+
177
+ **Mode per reviewer, from the precheck.** `RISK: high` or `critical` always runs `full`. Otherwise, the `risk` reviewer with `DOMAIN: security hits 0` and `DOMAIN: compliance hits 0` (or, split, each reviewer with zero hits in its own domain) runs in `confirm` mode: 5 tool calls to confirm no sensitive path is touched, returning `n/a` - or `escalate` with the file that is. On `escalate`, spawn that reviewer again in `full` mode. With hits, `full` mode, the `DOMAIN-HIT:` lines as starting points.
178
+
179
+ **Tool-call budget per reviewer** (the reviewer stops and reports `partial` when it runs out): `quality-reviewer` 40 (30 each when split), `risk` 30 (20 each when split), `confirm` mode 5. Budgets scale with the change: double them when `REVIEWABLE:` changed lines exceed 3000.
180
+
181
+ **Model and effort per reviewer:** every reviewer runs on Opus; the `RISK:` tier sets the effort - `low` low, `medium` medium, `high` high, `critical` xhigh. Where the runner cannot set effort per call, the session effort applies. A cheaper model misses findings a human then catches; save on effort and tool calls instead.
182
+
183
+ Spawn all reviewers in a SINGLE message (parallel). Pass each, and nothing more:
184
+
185
+ - its focus, mode, budget, and the `DIMENSION:` names it owns (§4);
186
+ - its `REVIEWABLE:` lines, copied verbatim from the precheck (pre-grouped - reviewers never re-scope; never hand-typed paths or globs);
187
+ - `quality-reviewer`: every `PRECHECK:` line; `risk`: the `DOMAIN-HIT:` lines of both domains;
188
+ - the prior findings on its files to re-verify (§2a);
189
+ - the review worktree path, the main-checkout path for its reading map, the base ref, the §2b context block, the §3b stance verbatim, and the §3c trace for its file group;
190
+ - hard caps: never open a `SKIPPED:` file; read changed files + only the callees a finding depends on; batch reads (several files in one shell call); max 10 findings; compact `[SEV] file:line - finding - evidence - fix` lines, no prose; do NOT run `/check`/tests.
191
+
192
+ ## 6. Evidence gate (cut false positives)
193
+
194
+ Every reviewer applies this before returning; re-apply it yourself when synthesizing:
195
+
196
+ - Every `[BLOCK]`/`[WARN]` cites a concrete `file:line` AND the rule doc violated, or - where no rule doc covers it (§3) - the named principle plus the traced trigger. Otherwise downgrade to `[INFO]` or drop.
197
+ - High-confidence findings only; unsure = downgrade or omit. Few actionable findings beat flooding.
198
+ - No invented runtime failures - state the trigger path or don't raise it.
199
+ - Don't duplicate what tooling enforces (oxlint, the `/check` gate); for a suspected lint/boundary issue say "confirm with `pnpm check:lint`" - flag only what the gates miss.
200
+ - A `PRECHECK:` line a reviewer confirmed is evidence for its finding. One no reviewer addressed goes into the report as `[INFO] ... (precheck, unconfirmed)` - never dropped, never promoted.
201
+
202
+ ## 7. Synthesize
203
+
204
+ Dedup by `file:line`, order BLOCK -> WARN -> INFO.
205
+
206
+ **Coverage gate first.** Collect one `DIMENSION:` line per dimension in §4 - from each reviewer's output, plus `rollout` and `spec` from you. A reviewer that returned no `DIMENSION:` line, or an `n/a` with no stated check, did not cover it: resume that reviewer once asking for the missing line; if it still has none, write the line as `DIMENSION: <name> - missing - <reviewer> returned no coverage` and the verdict is CHANGES REQUESTED. A `partial` line names the files the reviewer did not reach: list them in the report; `partial` on `security` or `compliance` forbids APPROVED - resume that reviewer with only the unreached files.
207
+
208
+ **Prior findings.** One `PRIOR:` line each: `fixed`, `still open`, or `obsolete` from the reviewer that re-verified it, `carried` for the rest. `still open` and `carried` findings count toward the verdict like new ones.
209
+
210
+ **Save the state** after every review, `--ci` included: write `.claude/reviews/<pr or branch>.json` in the main checkout with the reviewed HEAD SHA, base, verdict, every open finding (new, `still open`, `carried`), and the `DIMENSION:` lines.
211
+
212
+ Default and `--post`: a human-readable report - one line per finding `[SEV] file:line - finding - evidence - rule cited - fix`, one `TRACE:` line per traced entry point (format below), one status line per AC bullet, the `PRIOR:` lines, the `SKIPPED:` count, the seven `DIMENSION:` lines, and **APPROVED** / **CHANGES REQUESTED** with the most critical finding last. `--post` rewrites those findings into the §8 comments.
213
+
214
+ `--ci`: print exactly this block and nothing else - a CI job parses it line by line:
215
+
216
+ ```text
217
+ FINDING: [BLOCK|WARN|INFO] <file>:<line> - <finding> - <evidence> - <rule cited> - <fix>
218
+ TRACE: <entry point> - hops <n>/7 walked - callers <checked>/<found> - <ok|BLOCK reason>
219
+ CRITERION: <acceptance criterion> - <met|not met|not verifiable>
220
+ PRIOR: [BLOCK|WARN|INFO] <file>:<line> - <finding> - <fixed|still open|obsolete|carried>
221
+ DIMENSION: <conventions|performance|reliability|security|compliance|rollout|spec> - <ran|n/a|partial|missing> - <counts per severity, what was checked for n/a, or files not reached for partial>
222
+ VERDICT: <APPROVED|CHANGES REQUESTED> - <counts per severity> - <most critical finding>
223
+ ```
224
+
225
+ One `TRACE:` line per traced entry point, one `CRITERION:` line per AC bullet, exactly seven `DIMENSION:` lines, exactly one `VERDICT:` line, last. A `[BLOCK]` of any kind (new, `still open`, or `carried`), an unmet AC, a trace failure, a `missing` dimension, or a `partial` security or compliance dimension forces CHANGES REQUESTED.
226
+
227
+ Spec findings cite the ticket the way code findings cite a rule doc: a diff that crosses a ticket's out-of-scope line, answers an open question in code without recording it on the ticket, or ships behavior no AC asked for is a `[WARN]` with the ticket line quoted as evidence.
228
+
229
+ Severities: `[BLOCK]` must fix before merge (core edit, boundary break, authz/secret/PII risk, broken extension wiring, a §3c trace failure); `[WARN]` should fix (convention violation, missing test, weak validation); `[INFO]` FYI / hardening.
230
+
231
+ If `--fix`: apply BLOCK + WARN fixes in the working tree (smallest diff satisfying the cited rule), run `/check`, report green/red. Leave INFO untouched. Never commit or push.
232
+
233
+ ## 8. Post to the pull request (`--post`)
234
+
235
+ Only when `--post` is set and the target is a pull-request number. Turns findings into terse review comments: one line each, brief why, backtick every identifier.
236
+
237
+ **What gets a comment.** Severity decides the verdict, not what gets posted. Every verified finding is posted unless it matches one of these, and the report names which:
238
+
239
+ - D1 the code does not do what the finding says;
240
+ - D2 a duplicate - merge it into the other;
241
+ - D3 pre-existing: the diff touches neither that path nor the order of checks around it (a new gate placed in front of an old one makes the order new);
242
+ - D4 style or naming with no written rule behind it;
243
+ - D5 a request for more test cases, when the existing tests fail without the feature;
244
+ - D6 hardening for an input that cannot reach the code - name what stops it.
245
+
246
+ Nothing else is a drop reason: not "theoretical", "unlikely", "no consumer yet", "a sibling does the same", "by design", "the lockfile pins it", or "performance only".
247
+
248
+ A finding gets its own inline comment only when a concrete trigger leads to wrong or stranded money (a debit or hold that cannot be reversed, a credit that is blocked), an authz or security bypass, a compliance gap (audit, RG, KYC, geo), data loss, a crash or 5xx, a broken public contract or declared rule (a type not exported where its siblings are, an undeclared audit action, untyped error data, a loose dependency pin), a race that persists state breaking an invariant the change adds, request-path work that grows with table size, a test that passes with the feature removed or its mock unconfigured, an unmet AC, or code that does not do what the title claims. Everything else - test gaps, naming, boundary nits, actor metadata, a weaker variant of a posted defect - joins an inline comment on the same file or becomes one line in the summary note. Merging never launders: each merged point passes the same bar on its own. A merged comment leads with its most severe finding, anchors on its line, and keeps its strongest fix. At most six inline comments.
249
+
250
+ 1. **Draft.** Rewrite each finding as a terse comment keyed to its `file:line`, in the posting user's voice: when their instructions name a voice or writing guide, read it before drafting. Each comment is 1-3 sentences: what breaks, the trigger, the fix. No mechanism chain, no secondary evidence, no add-ons - the author asks if unclear. Most comments start straight with the point; soften at most one in three, never with the same opener twice in a pull request. Compose the summary as ONE sentence stating whether the changes block prod/push, e.g. `Not a blocker for push - a few cleanups worth doing.` or `Blocker: the finding in `x.ts` must be fixed before we push.` Then one short line per minor finding.
251
+ 2. **Dedupe.** Read every existing thread on the pull request, resolved or not, per `docs/agents/forge.md`. Drop a draft that an existing thread already raises, even worded differently; when it adds a new fact, reply to that thread instead of opening a new one. Drop the summary when every finding was dropped.
252
+ 3. **Confirm.** Show all drafted comments + the summary and stop for approval - UNLESS `--yes`, then skip straight to posting.
253
+ 4. **Post inline comments** anchored to the diff, using the "Inline review comments" command in `docs/agents/forge.md`. Anchor on the NEW-file line of an added (`+`) line (`git show <src-branch>:<file> | grep -n`), and verify each response actually carries a line anchor - an unanchored fallback comment must be deleted and retried, never left behind.
254
+ 5. **Post the summary** as one general comment on the pull request, per the same file, ending with the hidden marker `<!-- review:sha=<reviewed HEAD SHA> -->` so the next review on any machine can go incremental (§2a).
255
+ 6. Report back the count posted + the summary verdict. Never resolve threads; never push.
256
+ 7. `[oss]` findings go to the paired OSS PR instead, by `<worktree>/docs/standards/skills/review.md` "Posting to the PR", after their own confirmation. That PR is public: no operator name, no internal URL, no ticket text beyond the bare key.
257
+
258
+ ## 9. Several pull requests in one run
259
+
260
+ An agent re-reads its whole context on every tool call, so a long session, or one agent walking several pull requests, costs more than short agents with one pull request each.
261
+
262
+ - Triage first, without agents: skip drafts, dependency bumps, and pull requests that change only docs, rules, or tests unless asked. Say which were skipped.
263
+ - One orchestrator and roster per pull request; never one agent over several. A single-agent review returns the full §7 block (`TRACE:`, `CRITERION:`, seven `DIMENSION:` lines); one without it is rerun, not accepted.
264
+ - Check overlap before reviewing: list each open pull request's files (`gh pr view <n> --json files` / `glab mr diff <n> --name-only`) and flag two that add a migration to the same folder or edit the same function. Each review names the other pull request and which one must rebase and regenerate.
265
+ - Before approving on the forge, read the reviewable diff yourself - at 300 lines or less that is one read. An agent's clean result is a claim, not a verdict.
266
+ - Before launching, state the agent count and a token estimate. Run batches of about three pull requests, so a usage limit stops a batch, not the run.
267
+ - Keep each agent within its §5 tool-call budget. Put the prompt text all agents share first and the pull-request-specific part last, so the cached prefix is reused.
268
+ - A step that only distills the ticket or merges findings runs at low effort.
269
+
270
+ ## Constraints
271
+
272
+ - Reviewers report; only the orchestrator edits, and only under `--fix` (working tree only - no commit, no push).
273
+ - Never `git stash`, never `git checkout` another branch in the working tree: read MR sources with `git fetch` + `git show <sha>:<path>` / `git diff <base> <head>`. The stash stack and the worktree are shared with other sessions.
274
+ - NEVER edit `node_modules` or the main `{{ossDir}}` checkout. Under `--fix`, an `[oss]` finding is fixed in the OSS worktree only.
275
+ - Every finding cites a rule doc or a named principle with a traced trigger - no ungrounded opinions.
276
+ - Two reviewers minimum on every diff, four maximum; seven `DIMENSION:` lines on every review.
277
+ - Precheck first, reviewers second: no reviewer spends tokens on what `review-precheck` already printed.
@@ -0,0 +1,149 @@
1
+ ---
2
+ name: ship
3
+ targets: ['*']
4
+ description: >
5
+ Take one {{trackerKey}} ticket from plan to a green, reviewed MR with nobody in the loop: planner
6
+ plans it with test cases, builder builds it, tester attacks it, the reviewers review it, then it
7
+ pushes the ticket branch, opens the MR, moves the ticket and watches the MR until it is ready for a
8
+ person to review. Resumable: every run reads the ticket,
9
+ branch, MR and CI and does the next step, including fixing a red pipeline or new review comments.
10
+ Stops only on a question or a blocker. Use on "ship {{trackerKey}}-XXX", "add feature", "deliver
11
+ {{trackerKey}}-XXX", or /ship {{trackerKey}}-XXX [--ask].
12
+ ---
13
+
14
+ # ship ({{name}})
15
+
16
+ The orchestrator: one ticket key in, a green MR in Code Review out. You own the ticket's whole delivery, plan to review: you are done when the MR is ready for a person to review it (step 7), not when it is opened. You run in the main session and are the only one who delegates. You hand each step to its subagent, read its verdict, and pick the next step yourself - never wait for a person between steps. Every subagent you start is told it starts no subagents of its own; a domain question one of them returns comes back to you, you ask `expert`, and you pass the answer on.
17
+
18
+ ## Coordinates
19
+
20
+ - Jira: per `docs/agents/issue-tracker.md`, project `{{trackerKey}}`. Code forge: `{{gitRemotePath}}`, target `{{mrTarget}}`, commands in `docs/agents/forge.md`.
21
+ - `{{ossDir}}` (the linked OSS checkout) is read-only. Core-only work goes through `handoff.md`.
22
+
23
+ ## Arguments
24
+
25
+ - `{{trackerKey}}-XXX` from `$ARGUMENTS`. None: ask for it, that is the one question this skill always asks.
26
+ - `--ask`: stop for approval after the plan and before the push. Without it, invoking `/ship` is the authorization for every write below - and only those.
27
+
28
+ ## What ship may write without asking
29
+
30
+ - Jira, on this ticket only: the Plan comment (and its test cases where the repo's `test-plan` skill keeps them), a questions comment, a blocker comment, the MR link comment, and the transitions to In Progress and to Code Review. Nothing else: no field edits, no other transitions, no other tickets.
31
+ - Git: commits on the ticket branch `<type>/{{trackerKey}}-XXX/<slug>` and pushing it. Never a push to `{{mrTarget}}`, `stage`, `prod` or any shared branch.
32
+ - Force-push: only `git push --force-with-lease` on the ticket branch, and only while every commit on the remote branch past `{{mrTarget}}` is your own (`git log --format=%ae origin/{{mrTarget}}..origin/<branch>` shows only your `git config user.email`). Someone else's commit there: merge, never push over it. Never a plain `--force`.
33
+ - Merging: into a feature branch only (`{{mrTarget}}` merged into the ticket branch to clear conflicts, a stacked MR into its parent ticket branch). Never into `{{mrTarget}}`, `dev`, `develop`, `stage`, `staging`, `prod`, `production`, `main` or `master`.
34
+ - The forge: opening the MR for that branch and replying on its review threads. Every comment you leave starts with `Agent:`, so `watch-pr.mjs` and other tools never take it for one to answer.
35
+ - Slack: a one-line draft only, never sent.
36
+
37
+ ## Do what the work needs, inside the worktree
38
+
39
+ Never stop to ask for something local that deleting the worktree undoes: do it, and say what you did in the reply and the MR description.
40
+
41
+ - Env: a variable the change needs goes into the worktree's `.env` with a local dev value, and into every place the repo declares one (env schema, `.env.example`, deploy docs) in the same commit. A value only a person has (a real API key, a prod URL): a dev placeholder or a mock locally, and a "Needs before deploy" line in the MR description. If no test can run without the real one, that is a blocker.
42
+ - Dependencies: add what the plan needs with the repo's package manager and commit the lockfile. A repo rule that asks for a step first (unlink a locally linked package, then link it back) is followed, so the lockfile carries no local links; it is never a reason to stop.
43
+ - Data: the worktree's own database and Redis db - create, migrate, seed and reset them freely. Migrations come from the repo's generator, generated files from its regen command.
44
+ - Processes and tools: start what the tests need on the worktree's own ports and stop it before you report; install a local tool the repo's docs name (browsers for Playwright and the like).
45
+
46
+ ## Access outside the repo
47
+
48
+ The plan's Access list names every account or session outside the repo the work needs (a cloud CLI profile, a provider's dashboard, a sandbox API), each with what it is for, a read-only check that proves the session works and the login a person runs. Before 2, every run runs each check:
49
+
50
+ - One fails -> `Asked:` on its own line, then each missing login as the command a person runs (`! aws sso login --profile <p>`) or the page to log in to in the browser. Report it, stop; no ticket comment. `/ship {{trackerKey}}-XXX` again picks up from here.
51
+ - All pass -> read what it names freely. A passing check is not consent to change anything there, and neither is an Access list built from the ticket. Before the first change outside the repo (create, configure, delete, issue a key): `Asked:`, then one line per change - account, resource, what changes - report it, stop. A person's yes in this session covers that exact list; anything not on it, or a new run, asks again. Then make the changes and put a dev key it issues in the worktree's `.env`.
52
+ - Every change outside the repo goes in the reply and the MR description under "Outside the repo", one line each: where, what, how to undo it. A change to something that already existed records its old value.
53
+
54
+ ## Never, however blocked
55
+
56
+ Anything shared, remote, or not undone by deleting the worktree, unless a person approved that exact change (see Access outside the repo):
57
+
58
+ - Servers, ssh, cloud accounts, dashboards, deploys, stage and prod, and any database that is not the worktree's own.
59
+ - CI/CD settings and variables, repo settings, other people's branches and MRs.
60
+ - Anything this run did not create, in the repo or outside it: no drop, flush, kill or delete.
61
+ - Secrets: never commit, print or invent a real-looking one; a `.env` with real values stays uncommitted.
62
+ - Gates: no `--no-verify`, no skipped or loosened test, lint rule or guard hook, no hand edit to a generated file or `node_modules`.
63
+
64
+ Blocked by one of these: `Blocked:` with what is needed and who can do it. Every subagent you start gets both lists.
65
+
66
+ ## Read the state, do the next step
67
+
68
+ Every run starts here, so a run that died midway resumes where it stopped. Read the ticket per `docs/agents/issue-tracker.md`, then `git branch -a --list '*{{trackerKey}}-XXX*'`, then the MR for that branch and its CI per `docs/agents/forge.md`.
69
+
70
+ | State | Next step |
71
+ | ------------------------------------------- | ------------------------------------------- |
72
+ | No Plan comment on the ticket | 1. Plan |
73
+ | Plan, no branch | 2. Build |
74
+ | Branch, no MR | 3. Test, then 4. Review, then 5. Open the MR |
75
+ | MR open, CI red or conflicts | 6. `fix-pipeline` skill |
76
+ | MR open, review threads with no reply | 6. `fix-review-comments` skill |
77
+ | MR open, CI running, or green and answered | 7. Ready for review |
78
+ | MR merged or closed | Report it, do nothing |
79
+
80
+ A comment added to the ticket after the Plan comment that changes scope sends you back to 1.
81
+
82
+ ### 1. Plan
83
+
84
+ Start `planner` with the ticket key. It returns either `Asked:` with questions, or the plan.
85
+
86
+ - `Asked:` -> post the questions as one comment on the ticket, report them, stop.
87
+ - A plan -> post it, without its Core-only section, as one comment titled "Plan" (test cases where the repo's `test-plan` skill keeps them, if it has one), move the ticket to In Progress. `--ask`: show it and stop for approval.
88
+ - A Core-only section -> write the work order per `handoff.md` and drop that slice; ship the rest.
89
+
90
+ ### 2. Build
91
+
92
+ Add a worktree for the ticket branch off the freshly fetched `{{mrTarget}}`, per the repo's worktree rules (its own database and Redis db). Start `builder` in it with the plan. Run the **create-plugin** skill's steps through it for each overlay, adapter or page slice.
93
+
94
+ - `Blocked:` -> post the reason as one comment on the ticket, report it, stop.
95
+ - Done -> check its reply holds the gate output from HEAD and `git status` is clean. Missing either: send it back once to run the gate, then treat it as blocked.
96
+
97
+ ### 3. Test
98
+
99
+ Start `tester` in the worktree with the plan's test cases. It returns an AC table.
100
+
101
+ - Every row PASS -> 4.
102
+ - Any FAIL -> back to `builder` with the failing rows only, then `tester` again.
103
+ - UNCHECKED rows ride along to the MR description; they do not block, except a case on a money, KYC or responsible-gambling path: back to `tester` once to run it, still UNCHECKED -> blocker comment, report it, stop.
104
+ - A failing spec called pre-existing without its run on the base commit -> back to `tester` once to run it there. Still unrun: it is a FAIL.
105
+
106
+ ### 4. Review
107
+
108
+ Start `quality-reviewer`, `security-reviewer` and `compliance-reviewer` in parallel on the branch diff against `{{mrTarget}}`, with the tester's AC table so they dig where testing could not reach.
109
+
110
+ Every finding with a fix gets fixed, whatever its severity, but only once it holds. Dedupe across reviewers, then check each yourself before anything changes: open its `file:line` and confirm the evidence on this branch. One that doesn't hold (wrong line, the code already handles it, a claim the code doesn't show) is dropped and goes to the MR description with why. A product call the ticket doesn't settle goes to `expert`, then is fixed or rides along as an open question. Send the rest to `builder` in one go, then 3 for the cases they touch and 4 again. A later round of 4 reviews only the commits since the last one and whether each sent finding is fixed. Clean means no finding left that holds.
111
+
112
+ Rounds of 3 and 4 share one budget: three. After the third with anything still failing, post a blocker comment naming what is left, report it, stop.
113
+
114
+ ### 5. Open the MR
115
+
116
+ `--ask`: report the SHA and stop for "yes push". Then run **create-pr** with the tester's AC table, its videos and its Tests list. Comment the MR link on the ticket and move it to Code Review in the same turn. Draft the one-line Slack notice to `{{teamChannel}}`: emoji + MR title as a link. Then 7.
117
+
118
+ ### 6. Red CI and review comments
119
+
120
+ Run the repo's `fix-pipeline` skill on a red pipeline or conflicts, `fix-review-comments` on unanswered threads from a person or a bot. No such skill in this repo: do the same per `docs/agents/forge.md`. Under `/ship` they run like this:
121
+
122
+ - Each thread is checked against the code on this branch first: correct | already handled | wrong on this branch | out of scope. Only a correct one changes code; the rest get an answer.
123
+ - A red job is reproduced locally first; `builder` fixes its cause. Never skip or loosen a test.
124
+ - Every fix goes to `builder`. Then `tester` re-runs the cases the fix touches and leaves a test that fails without it, and 4 runs on the new commits. Nothing is pushed untested.
125
+ - Push the ticket branch without asking (a force-push only as above). Reply per thread, in the thread itself, with what changed and the test that proves it, or why nothing changed. Resolve only a thread the fix addressed; a question or a disagreement stays open for the reviewer.
126
+
127
+ Then 7.
128
+
129
+ ### 7. Ready for review
130
+
131
+ Start `node <this skill's folder>/watch-pr.mjs <branch> --until-green` as a background command, never a sleep loop in the session. It prints one line and exits when there is work:
132
+
133
+ - `failed` or `conflicts` -> 6, then watch again. Still red after three fixes -> blocker comment, report, stop.
134
+ - `threads <ids>` (unanswered for two checks in a row, from a person or a bot) -> 6 for those, then watch again.
135
+ - `green` -> check the MR is ready (below), report "Ready for review:" and the MR URL, then watch again without `--until-green`.
136
+ - `merged` or `closed` -> report it, drop the worktree's database and Redis db, stop. `error ...` -> report it, stop.
137
+
138
+ Ready means: the pipeline on the last commit is green, no conflicts with `{{mrTarget}}`, every thread has an answer, no money, KYC or responsible-gambling case is UNCHECKED, and the description holds the AC table, the screenshots and the UNCHECKED rows.
139
+
140
+ Keep watching until the MR merges or closes, for as long as the session lives. A caller that says it watches the MR itself (a headless run) gets the report at `green`, and you stop there; it brings the ticket back through `/ship {{trackerKey}}-XXX`, which lands on 6.
141
+
142
+ ## Rules
143
+
144
+ - One ticket, one branch, one MR.
145
+ - You edit no code, commit nothing and run no gate yourself, however small the fix: every fix goes to `builder`. Code changed after 3 means 3 runs again for the cases it touches, and 4 for the new commits.
146
+ - A subagent that stops short (no gate output, uncommitted work) goes back to it once, never finished by you.
147
+ - Never claim a step passed without its output: the gate from HEAD, the AC table, the review findings.
148
+ - A run you resume with a branch but no MR re-runs 3 and 4: verdicts from a dead run are gone.
149
+ - Clean up what the run started: worktree databases and Redis dbs stay for the next round until the MR merges; processes you started stop before you report.
@@ -0,0 +1,48 @@
1
+ # OSS core handoff
2
+
3
+ When a `ship` work item can only be fixed in `@openora/*` core, this consumer repo cannot edit it (the `guard-core.mjs` hook and `permissions.deny` block `{{ossDir}}/**`). Hand off to the platform-core twin skill instead of fighting the guard.
4
+
5
+ ## When to hand off
6
+
7
+ - The fix requires changing a contract, schema, service, router, or platform seam in `@openora/*`.
8
+ - An overlay plugin / adapter swap / UI provider override / config change genuinely cannot express the behavior.
9
+ - Default bias: extend from the outside first; hand off only when you've confirmed the outside-in path doesn't exist. If unsure, the planner says so in the plan; without a clear core-only reason, build it from the outside.
10
+
11
+ ## Work-order template
12
+
13
+ Write to `~/.claude/plans/<ticket-key>-oss.md` so both repos and future sessions can read it:
14
+
15
+ ```markdown
16
+ # OSS work order - <ticket-key>: <title>
17
+
18
+ ## Goal
19
+
20
+ <what core must do, 1-2 lines>
21
+
22
+ ## Unblocks
23
+
24
+ {{name}} feature <ticket-key> - <which downstream slice depends on this>
25
+
26
+ ## Core surface to change
27
+
28
+ - <package / module / contract / adapter token, as specific as possible>
29
+
30
+ ## Contract / schema impact
31
+
32
+ - <new or changed oRPC contracts, Drizzle tables, events; or "none">
33
+
34
+ ## Acceptance
35
+
36
+ - <observable outcomes that prove the core change is correct>
37
+
38
+ ## Dependency
39
+
40
+ {{name}} MR <url-or-TBD> stays in draft until this merges and a new @openora/core/\* version is consumed.
41
+ ```
42
+
43
+ ## Protocol
44
+
45
+ 1. This consumer repo writes the work-order and **stops** that slice (keep delivering independent downstream slices meanwhile).
46
+ 2. The user runs `/ship` inside the platform OSS repo (`{{ossDir}}`, separate cwd/session). It reads the work-order, implements, and opens its own MR there.
47
+ 3. The consumer MR stays draft/blocked until the OSS MR merges and the consumer bumps the consumed `@openora/*` version. Link the two by the work-order path and the ticket key.
48
+ 4. Note the handoff in the Jira ticket and the consumer MR description so the dependency is visible.