@azure-id/orc 2.1.0 → 2.2.0

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 (153) hide show
  1. package/CHANGELOG.md +374 -0
  2. package/README.md +49 -36
  3. package/bin/build-agents.js +7 -5
  4. package/bin/cli.js +1006 -235
  5. package/bin/fix.js +21 -18
  6. package/bin/graph-extract.js +314 -6
  7. package/bin/graph-gain.js +83 -2
  8. package/bin/graph-map.js +23 -1
  9. package/bin/graph-notes.js +1 -1
  10. package/bin/graph-query.js +1362 -37
  11. package/bin/graph-resolve.js +1 -1
  12. package/bin/graph-shard.js +29 -6
  13. package/bin/graph-signals.js +5 -3
  14. package/bin/graph.js +7 -3
  15. package/bin/habit.js +1 -1
  16. package/bin/pricing.json +8 -1
  17. package/bin/trace-write.js +40 -11
  18. package/bin/verify-contracts.js +169 -60
  19. package/bin/verify-package.js +3 -3
  20. package/bin/webui/api.js +8 -0
  21. package/bin/webui/fixtures/extra.js +9 -9
  22. package/bin/webui/fixtures/flow.js +1 -1
  23. package/bin/webui/fixtures/index.js +2 -2
  24. package/bin/webui/fixtures/knowledge.js +8 -1
  25. package/bin/webui/fixtures/pact.js +112 -111
  26. package/bin/webui/fixtures/stats.js +2 -2
  27. package/bin/webui/i18n/en/knowledge.json +2 -0
  28. package/bin/webui/i18n/id/knowledge.json +2 -0
  29. package/bin/webui/js/panels/knowledge.js +17 -0
  30. package/guides/code-graph-benefit.md +116 -0
  31. package/guides/configuration.md +150 -0
  32. package/guides/documents.md +262 -0
  33. package/guides/extra-models.md +448 -0
  34. package/guides/habits-and-gotchas.md +152 -0
  35. package/guides/knowledge-reads.md +190 -0
  36. package/guides/model-selection.md +186 -0
  37. package/guides/rules.md +305 -0
  38. package/guides/status-line.md +344 -0
  39. package/mock-run/a-normal-day.md +2 -2
  40. package/mock-run/extra-slots.md +177 -177
  41. package/mock-run/orc-cli.md +3 -2
  42. package/mock-run/orc-doc.md +452 -448
  43. package/mock-run/orc-fast.md +2 -2
  44. package/mock-run/orc-quick.md +146 -146
  45. package/mock-run/orc.md +4 -4
  46. package/package.json +2 -1
  47. package/templates/agents/MODEL-MAPPING.md +12 -12
  48. package/templates/agents/{orc-executor-haiku-4-5.md → orc-executor-haiku-5-high.md} +21 -8
  49. package/templates/agents/orc-executor-opus-4-7-high.md +17 -5
  50. package/templates/agents/orc-executor-opus-4-7-med.md +17 -5
  51. package/templates/agents/orc-executor-opus-4-8-high.md +17 -5
  52. package/templates/agents/orc-executor-opus-5-high.md +17 -5
  53. package/templates/agents/orc-executor-opus-5-low.md +17 -5
  54. package/templates/agents/orc-executor-opus-5-med.md +17 -5
  55. package/templates/agents/orc-executor-sonnet-4-6-high.md +17 -5
  56. package/templates/agents/orc-executor-sonnet-5-high.md +17 -5
  57. package/templates/agents/orc-executor-sonnet-5-low.md +17 -5
  58. package/templates/agents/orc-executor-sonnet-5-med.md +17 -5
  59. package/templates/agents/{orc-graph-noter-sonnet-4-6-med.md → orc-graph-noter-haiku-5-high.md} +4 -4
  60. package/templates/agents/orc-planner-mini-opus-5-med.md +3 -1
  61. package/templates/agents/orc-planner-mini-sonnet-5-high.md +3 -1
  62. package/templates/agents/orc-planner-opus-5-med.md +3 -1
  63. package/templates/agents/{orc-recon-sonnet-4-6-med.md → orc-recon-sonnet-5-med.md} +4 -4
  64. package/templates/agents/{orc-trace-writer-haiku-4-5.md → orc-trace-writer-haiku-5-high.md} +4 -3
  65. package/templates/commands/orc-doc.md +128 -128
  66. package/templates/commands/orc-export.md +51 -46
  67. package/templates/commands/orc-fast.md +10 -10
  68. package/templates/hooks/README.md +8 -3
  69. package/templates/hooks/orc-effort-guard.js +105 -27
  70. package/templates/hooks/orc-graph-hook.js +252 -4
  71. package/templates/hooks/orc-statusline.js +13 -6
  72. package/templates/hooks/orc-trace.js +1 -1
  73. package/templates/skills/_shared/README.md +2 -2
  74. package/templates/skills/_shared/code-graph.md +185 -251
  75. package/templates/skills/_shared/extra-dispatch.md +4 -4
  76. package/templates/skills/_shared/lane-contract.md +7 -3
  77. package/templates/skills/_shared/opus5-only.md +3 -3
  78. package/templates/skills/_shared/phases/execution.md +13 -11
  79. package/templates/skills/_shared/phases/planning.md +27 -9
  80. package/templates/skills/_shared/phases/preflight.md +3 -3
  81. package/templates/skills/_shared/phases/review.md +4 -3
  82. package/templates/skills/_shared/phases/ship.md +7 -10
  83. package/templates/skills/_shared/phases/summary.md +2 -3
  84. package/templates/skills/_shared/phases/trace-verbs.md +21 -16
  85. package/templates/skills/_shared/phases/trace.md +3 -3
  86. package/templates/skills/_shared/phases/wiki-consult.md +2 -2
  87. package/templates/skills/_shared/pr-templates.md +108 -106
  88. package/templates/skills/_shared/read-ladder.md +8 -2
  89. package/templates/skills/_shared/return-validation.md +10 -6
  90. package/templates/skills/_shared/review-slice.md +1 -1
  91. package/templates/skills/_shared/stack-plan.md +135 -135
  92. package/templates/skills/_shared/wait.md +14 -2
  93. package/templates/skills/context-combiner/SKILL.md +2 -2
  94. package/templates/skills/orc/SKILL.md +7 -7
  95. package/templates/skills/orc/config.md +2 -2
  96. package/templates/skills/orc/examples/full-run-mock.md +7 -7
  97. package/templates/skills/orc/references/effort-and-mode.md +222 -222
  98. package/templates/skills/orc/schemas/planning-output.md +3 -0
  99. package/templates/skills/orc-aftermath/SKILL.md +15 -15
  100. package/templates/skills/orc-analyze/SKILL.md +2 -2
  101. package/templates/skills/orc-analyze-mini/SKILL.md +2 -2
  102. package/templates/skills/orc-boundary/SKILL.md +15 -15
  103. package/templates/skills/orc-boundary/references/card.md +81 -78
  104. package/templates/skills/orc-boundary/references/gate.md +113 -113
  105. package/templates/skills/orc-brainstorm/SKILL.md +15 -15
  106. package/templates/skills/orc-budget/SKILL.md +15 -15
  107. package/templates/skills/orc-challenge/README.md +1 -1
  108. package/templates/skills/orc-challenge/SKILL.md +16 -16
  109. package/templates/skills/orc-challenge/examples/council-full-roster.md +1 -1
  110. package/templates/skills/orc-claude/SKILL.md +4 -4
  111. package/templates/skills/orc-claude/examples/claude-run-mock.md +1 -1
  112. package/templates/skills/orc-diy/SKILL.md +2 -2
  113. package/templates/skills/orc-diy/references/blocks/wiki.md +26 -26
  114. package/templates/skills/orc-diy/references/flow-schema.md +2 -2
  115. package/templates/skills/orc-doc/README.md +2 -2
  116. package/templates/skills/orc-doc/SKILL.md +501 -490
  117. package/templates/skills/orc-doc/examples/orc-doc-prd-run.md +12 -1
  118. package/templates/skills/orc-doc/references/chunking.md +6 -4
  119. package/templates/skills/orc-doc/references/gates.md +311 -311
  120. package/templates/skills/orc-doc/references/resume-protocol.md +229 -228
  121. package/templates/skills/orc-explain/SKILL.md +88 -88
  122. package/templates/skills/orc-export/SKILL.md +190 -187
  123. package/templates/skills/orc-fast/SKILL.md +17 -14
  124. package/templates/skills/orc-grill/SKILL.md +16 -16
  125. package/templates/skills/orc-grill/references/grill-doc.md +1 -1
  126. package/templates/skills/orc-handoff/SKILL.md +11 -11
  127. package/templates/skills/orc-learn/SKILL.md +13 -13
  128. package/templates/skills/orc-learn/examples/learn-run-mock.md +2 -2
  129. package/templates/skills/orc-mini/SKILL.md +12 -12
  130. package/templates/skills/orc-mini/examples/mini-run-mock.md +4 -5
  131. package/templates/skills/orc-pact/SKILL.md +15 -15
  132. package/templates/skills/orc-pact/references/gate.md +70 -70
  133. package/templates/skills/orc-pattern/SKILL.md +3 -3
  134. package/templates/skills/orc-poly/SKILL.md +4 -4
  135. package/templates/skills/orc-poly/examples/poly-run-mock.md +51 -51
  136. package/templates/skills/orc-pr-driver/SKILL.md +4 -3
  137. package/templates/skills/orc-pr-driver/references/orc-run-split.md +108 -99
  138. package/templates/skills/orc-pr-setup/SKILL.md +2 -2
  139. package/templates/skills/orc-quick/README.md +11 -12
  140. package/templates/skills/orc-quick/SKILL.md +29 -32
  141. package/templates/skills/orc-quick/references/context-doc.md +5 -5
  142. package/templates/skills/orc-quick/references/dispatch-gate.md +10 -10
  143. package/templates/skills/orc-quick/references/gh-mode.md +2 -1
  144. package/templates/skills/orc-quick/references/look.md +34 -12
  145. package/templates/skills/orc-retro/SKILL.md +2 -2
  146. package/templates/skills/orc-retro/examples/retro-mock.md +2 -2
  147. package/templates/skills/orc-route/SKILL.md +2 -2
  148. package/templates/skills/orc-test/SKILL.md +6 -3
  149. package/templates/skills/orc-verify/SKILL.md +2 -2
  150. package/templates/skills/orc-wait/SKILL.md +10 -2
  151. package/templates/skills/orc-wiki/SKILL.md +4 -4
  152. package/templates/skills/orc-wiki/references/pattern-prewarm.md +19 -19
  153. package/templates/agents/orc-executor-sonnet-4-6-med.md +0 -155
@@ -0,0 +1,190 @@
1
+ # What ORC knows about your project — the reads
2
+
3
+ > Every command here is **free**. None of them scans, refreshes, or spends a
4
+ > model token. They tell you what is already on disk.
5
+
6
+ This is the overflow from the README, so it can be as detailed as it needs to be.
7
+
8
+ ---
9
+
10
+ ## The rule these all live under
11
+
12
+ > **`--json is not a summary`** — a read's `--json` is the WHOLE computed object.
13
+ > A field the human path prints and the JSON omits is drift, and it is drift no
14
+ > lint can catch, because both halves live in one function.
15
+
16
+ Before v0.49.1, `orc wiki status --json` emitted five numbers while its own
17
+ terminal output printed the per-doc breakdown, the top five stale docs, and **the
18
+ name of the doc actually pinning the tier**. `orc ui` therefore could not be as
19
+ detailed as the terminal, no matter how well it was written.
20
+
21
+ Every legacy key kept its name, its position and its meaning — `orc doctor`, the
22
+ Overview tile and the skills' artifact probe all read them — so the change is
23
+ purely additive.
24
+
25
+ ---
26
+
27
+ ## The wiki
28
+
29
+ ### `orc wiki status [--json]`
30
+
31
+ The tier, and now everything the terminal was already printing:
32
+
33
+ | field | what it is |
34
+ |---|---|
35
+ | `tier` · `distance` · `anchor` | the wiki's freshness, which is **its worst doc's** |
36
+ | `counts` | how many docs are FRESH / AGING / STALE / unmeasurable |
37
+ | **`worst`** | the doc pinning the tier, **by name**. A hash is not a thing anybody can go and refresh |
38
+ | `per_doc[]` | one row per registered doc: its own tier, its own distance, what it covers, its usage, its tags |
39
+ | **`blind_spot`** | the changed files no doc covers — **the file list**, not the number `2` |
40
+ | `orientation` | present, or missing with the free command that regenerates it |
41
+ | `crosslink` | `PUBLISHED` / `UNPUBLISHED` / `NONE`, and the boundary row count |
42
+ | `free_repairs` | reused verbatim from `orc wiki plan` — **a user must never pay for what a free step fixes** |
43
+
44
+ **Exit code 0 in every state.** `state` and `tier` are the branch; overloading
45
+ the exit code would collide with the existence probe, where a non-zero result
46
+ reads as "absent" — and `unregistered` means the wiki very much exists.
47
+
48
+ ### `orc wiki docs [--json]`
49
+
50
+ The doc table. `orc wiki` had six subcommands and **not one of them listed the
51
+ docs** — you could learn the wiki was STALE with 14 docs and 47 commits of drift,
52
+ and could not learn what any of those 14 docs was about.
53
+
54
+ ```
55
+ STALE orc-feature-billing.md 47c used 12/20 4 tags
56
+ Billing
57
+ covers: src/billing/
58
+ FRESH orc-orientation.md 2c used 20/20
59
+ ```
60
+
61
+ **Each distance is measured against that doc's OWN covered files.** A doc about
62
+ payments does not age because the README changed forty times.
63
+
64
+ Exit **0** registered · **1** no wiki · **3** unregistered (and it names
65
+ `orc wiki sync`, which is free and instant).
66
+
67
+ ### `orc wiki show <doc> [--body]`
68
+
69
+ One doc: its header fields, its coverage list, its crosslink tags, its usage, and
70
+ **the free repairs that apply to it**. `--body` adds the markdown.
71
+
72
+ `--body` is opt-in on purpose: prose is returned only on an explicit request,
73
+ exactly one artifact at a time.
74
+
75
+ Exit **0** · **2** unreadable · **3** unknown doc (and it lists the ones that
76
+ exist).
77
+
78
+ ### `orc wiki coverage [--json]`
79
+
80
+ The number nobody could get before: **what percentage of your tracked files is
81
+ covered by at least one wiki doc.** ORC's own artifacts are excluded, so a
82
+ changed `wiki/` file never reads as a documentation gap.
83
+
84
+ The uncovered set is collapsed to **directories** and ranked by file count,
85
+ because these are opposite situations and a flat list of 240 paths hides both:
86
+
87
+ ```
88
+ 118 vendor/stripe-sdk last touched a1b2c3d 2026-02-11
89
+ 22 src/notifications last touched 9f2c41a 2026-08-08
90
+ ```
91
+
92
+ > **It is a REPORT and never a gate.** There is no threshold, no config key, and
93
+ > nothing in ORC branches on it. A repo that deliberately documents four
94
+ > subsystems out of forty is not broken — and a coverage percentage that starts
95
+ > nagging becomes a number people game.
96
+
97
+ Exit **0** fully covered · **1** gaps exist. That is a branch, not a failure.
98
+
99
+ ---
100
+
101
+ ## Code patterns
102
+
103
+ ### `orc pattern show <lang> [--body]`
104
+
105
+ The pattern file is injected **literally** into every executor slice, and nothing
106
+ would show you a line of it. This does:
107
+
108
+ - when it was codified, from what commit, against which playbook
109
+ - its section headings
110
+ - how many CONVENTIONS and how many INVARIANTS it carries
111
+ - **the conflicts the codifier flagged** — *the project does X, the invariant
112
+ says Y*. These are the most decision-shaped thing in the file and were
113
+ invisible outside it
114
+ - `--body` prints the text itself
115
+
116
+ **It reports what is on disk and invents nothing.** The codifier may not write a
117
+ parseable header today; with none it returns `headered: false`, shows what it
118
+ could parse, and says so in one line. It **never** derives a "codified at" from
119
+ the file's mtime — an mtime is when the file moved, not when the pattern was
120
+ written.
121
+
122
+ Exit **0** cached · **1** absent · **2** unknown language key. That third one is
123
+ a *caller* bug: keys are FRAMEWORK names (`react`, `nestjs`), never file
124
+ extensions.
125
+
126
+ ---
127
+
128
+ ## Repair memory
129
+
130
+ ### `orc gotcha show <id>`
131
+
132
+ One entry, **every field** — symptom, fix, why, trigger, first seen. `gotcha
133
+ list` had always emitted these and the panel rendered six columns and discarded
134
+ the rest.
135
+
136
+ Works on live entries and archived ones alike.
137
+
138
+ ### `orc gotcha list --archived`
139
+
140
+ The archive. **Eviction is an archive, never a delete**, and ids are monotonic
141
+ and never reused, so an archived gotcha stays traceable forever.
142
+
143
+ ### `orc gotcha prune --dry-run`
144
+
145
+ Exactly which entries eviction would archive, and **why** — fewest hits first,
146
+ then oldest. It writes nothing.
147
+
148
+ ```
149
+ Would archive 1 gotcha (6 live, gotchas_max=5) — nothing has been written:
150
+ G-002 · react · repair · hits 0 · 01-01-2026
151
+ rank 1 of the low-value tail — 0 hit(s), last seen 01-01-2026
152
+ ```
153
+
154
+ This exists because **a count is not consent.** The panel's Apply button stays
155
+ disabled until this has been run, and the preview names every entry.
156
+
157
+ Exit **0** nothing to prune · **1** it would prune.
158
+
159
+ ---
160
+
161
+ ## The two doctor cautions
162
+
163
+ `orc doctor` gained exactly two wiki findings, and the restraint is deliberate.
164
+
165
+ | id | Fires when | Fix |
166
+ |---|---|---|
167
+ | `wiki-unregistered` | the wiki is unregistered, drifted or corrupt | `orc wiki sync` — **free**, instant, and until it is done nothing can read the wiki at all |
168
+ | `wiki-debt` | the tier is **STALE** and `orc wiki plan` has pending rows | `/orc-wiki refresh --top 2` |
169
+
170
+ **`wiki-debt` never fires on AGING.** Aging is a normal state that every living
171
+ repo passes through, and a doctor that warns about it is a doctor people learn to
172
+ ignore.
173
+
174
+ **There is no `pattern-missing` finding.** A project with no cached pattern is
175
+ not misconfigured, and warning about it would be ORC nagging you for a paid scan.
176
+
177
+ Both route to the Knowledge panel, because that is where they can actually be
178
+ cleared — `orc wiki sync` is a button there, and `orc wiki plan` is the card
179
+ above it.
180
+
181
+ ---
182
+
183
+ ## In `orc ui`
184
+
185
+ All of it renders on **Knowledge**, now five tabs: Wiki · Coverage · Code
186
+ patterns · Memory · Peers.
187
+
188
+ The panel computes none of it. A free action gets a button, a paid action gets a
189
+ copy-able command, and a value the CLI could not compute renders as an em dash —
190
+ never a guess, and never a zero.
@@ -0,0 +1,186 @@
1
+ # How ORC picks a model (and how to check it)
2
+
3
+ Short version: **the planner measures the task, arithmetic turns that into a
4
+ score, and the score picks a named agent.** No step of that is a judgement call
5
+ made in prose, which is why you can argue with the result.
6
+
7
+ ---
8
+
9
+ ## 1. The score is computed, not guessed
10
+
11
+ The planner is the party that read every file, so it reports **facets** per task:
12
+
13
+ | Facet | What it measures |
14
+ |---|---|
15
+ | `breadth` | how many files the task touches |
16
+ | `novelty` | mechanical · imitate · new-surface |
17
+ | `logic` | none · branching · stateful |
18
+ | `test_surface` | none · update-existing · new-tests |
19
+ | `risk[]` | cited risks: auth, money, migration, … |
20
+ | `uncertainty` | the planner's own confidence |
21
+
22
+ ORC runs a fixed published formula over those numbers. Two rules ride with it:
23
+
24
+ - **A cited risk forces a floor of 70.** A small change to payment code is not
25
+ a small task.
26
+ - **Every fix-cycle dispatch is scored the same way.** A repair is not
27
+ automatically cheap.
28
+
29
+ You see the whole table before anything is dispatched.
30
+
31
+ ---
32
+
33
+ ## 2. The score → model table
34
+
35
+ The default table has 5 bands (`skills/orc/config.md`):
36
+
37
+ | Score | Model | Effort | Agent |
38
+ |---|---|---|---|
39
+ | `[0,21)` | `claude-sonnet-5-5` | low | `orc-executor-sonnet-5-low` |
40
+ | `[21,31)` | `claude-sonnet-5-5` | medium | `orc-executor-sonnet-5-med` |
41
+ | `[31,41)` | `claude-sonnet-5-5` | high | `orc-executor-sonnet-5-high` |
42
+ | `[41,90)` | `claude-opus-5-5` | low | `orc-executor-opus-5-low` |
43
+ | `[90,100]` | `claude-opus-5-5` | medium | `orc-executor-opus-5-med` |
44
+
45
+ Every band from score 41 needs an Opus 5.5 main session. Six executors are
46
+ named by no band (`orc-executor-haiku-5-high`,
47
+ `orc-executor-sonnet-4-6-high`, `orc-executor-opus-4-7-med`,
48
+ `orc-executor-opus-4-7-high`, `orc-executor-opus-4-8-high`,
49
+ `orc-executor-opus-5-high`). They still ship. To use one, name it in
50
+ `rubric_bands_override`, `orc diy`'s `fixed_executor` or `extra_fallback_agent`.
51
+
52
+ `rubric_bands` (2–8) changes **how the report is grouped**, not the table.
53
+
54
+ ### The alternative table: `opus5_only`
55
+
56
+ Set `opus5_only: true` and **every dispatched role uses Opus 5.5**, with effort as
57
+ the cost dial instead of the model:
58
+
59
+ | Score | Model | Effort |
60
+ |---|---|---|
61
+ | `[0,90)` | `claude-opus-5-5` | low |
62
+ | `[90,100]` | `claude-opus-5-5` | medium |
63
+
64
+ This ladder differs from the default table only below score 41.
65
+
66
+ Eight fixed roles switch to an Opus 5.5 variant too (mini executor, fast
67
+ executor, mini analyst, mini planner, scout, pattern codifier, the light wiki
68
+ scanner, retro miner). The CLAUDE.md writer and the deep wiki scanner are
69
+ already on Opus 5.5 low, so they do not change. Two things are **never** forced:
70
+ the Haiku trace writer (it transcribes a packet somebody else wrote) and
71
+ `/orc-diy` (its executors come from the compiled flow).
72
+
73
+ While `opus5_only` is on it **outranks** the Fable 5 override and any
74
+ hand-written band table. ORC never hides that: `orc config set` names every key
75
+ it makes inert, and `orc config list` marks them.
76
+
77
+ **It is inert in `/orc-quick`.** That lane always asks you which agent to use,
78
+ and a forcing mode would silently delete your answer.
79
+
80
+ ### Resolution order
81
+
82
+ `opus5_only` › a hand-written `rubric_bands_override` › the default 5-band
83
+ table.
84
+
85
+ ---
86
+
87
+ ## 2b. Four lanes have no score, so they have POSITIONS instead
88
+
89
+ A band answers "which agent for a task that scored 62". `/orc-quick`,
90
+ `/orc-fast`, `/orc-doc` and `/orc-wiki` never produce a score at all — they pin
91
+ one agent to a job. So each of those jobs is a **position** you can point
92
+ somewhere else (`orc extra role`, v0.55.0):
93
+
94
+ | position | lane | the agent it takes the job from |
95
+ |---|---|---|
96
+ | `quick-executor` | `/orc-quick` | `orc-executor-sonnet-5-med` · `orc-executor-opus-5-low` |
97
+ | `fast-executor` | `/orc-fast` | `orc-executor-sonnet-5-med` |
98
+ | `doc-writer` | `/orc-doc` | `orc-doc-writer-opus-5-med` |
99
+ | `doc-checker` | `/orc-doc` | `orc-doc-checker-opus-5-low` |
100
+ | `wiki-scanner-deep` | `/orc-wiki` | `orc-wiki-scanner-opus-5-low` |
101
+ | `wiki-scanner-light` | `/orc-wiki` | `orc-wiki-scanner-sonnet-5-high` |
102
+
103
+ A position with no row stays on the agent above, and it **keeps its row** in
104
+ `orc extra role` so "I left the checker on Claude on purpose" and "there is no
105
+ checker" never look the same.
106
+
107
+ **`/orc-quick`'s recon pair is NOT a position, and that is on purpose (v1.9.0).**
108
+ `orc-recon-sonnet-5-med` and `orc-recon-opus-5-low` read the repository and
109
+ hand back an answer the dispatch gate is expected to trust. Sending that job to
110
+ a third party is a different question from sending a code edit there: a wrong
111
+ edit fails a build, and a wrong answer is believed. So recon and review stay on
112
+ Claude, `quick-executor` remains the lane's only position, and the menu's third
113
+ line is an escape hatch that names a MODEL, never a routed slot.
114
+
115
+ `/orc-mini` is the one fixed-executor lane that keeps a band, and that is
116
+ deliberate: mini scores its tasks and then pins one executor over them, so
117
+ reading that agent's band is a question about numbers the run really produced.
118
+
119
+ ### The one precedence sentence
120
+
121
+ > **Extra decides whether a Claude agent runs at all. `opus5_only` and the score
122
+ > tables only decide WHICH Claude agent runs where extra did not take it.**
123
+
124
+ Under a taken position `opus5_only` is **not consulted** — and it stays fully
125
+ live for every position with no row. `orc config list` names the taken positions
126
+ beside the taken bands, because a partly shadowed setting must not be flattened
127
+ into one word.
128
+
129
+ ---
130
+
131
+ ## 3. The models are pinned, so you can check them
132
+
133
+ A dispatch names a real agent file in `.claude/agents/`, for example
134
+ `orc-executor-sonnet-5-high`, whose frontmatter carries the model and effort.
135
+ That is why **an agent's model change is always a rename**.
136
+
137
+ Three ways to confirm what actually ran:
138
+
139
+ 1. Expand the tool call in Claude Code.
140
+ 2. Read the behavior trace under `.claude/orc/logs/` — every `RETURN` records
141
+ the model that really answered.
142
+ 3. `orc stats` — it counts dispatches and **downgrades** from those traces.
143
+
144
+ Every agent return carries `actual_model` and `actual_effort`, quoted rather
145
+ than assumed, so a silent tier downgrade is flagged rather than absorbed.
146
+
147
+ ---
148
+
149
+ ## 4. The tier rule that catches everyone
150
+
151
+ > **A subagent's model can never be higher than your main session's model.**
152
+
153
+ Run your main Claude Code session on **Opus 5.5**. Otherwise every Opus-5-pinned
154
+ role (analyst, planner, reviewer, verifier, test author, combiner, ultra
155
+ advisor and judge) plus the top executor band quietly runs on whatever your
156
+ session runs. This is the most common cause of "it used the wrong model".
157
+
158
+ See `agents/MODEL-MAPPING.md` in your install for the full list.
159
+
160
+ ### The guard `orc init` installs
161
+
162
+ `orc init` merges two things into `.claude/settings.json`, without replacing
163
+ anything you already have:
164
+
165
+ - **Effort — a hard block.** `hooks/orc-effort-guard.js` (a `PreToolUse` hook)
166
+ refuses to start `/orc` below **high** effort. `claude-opus-5-5` and
167
+ `claude-fable-5` are cleared from **medium** up, because both outrank the
168
+ Opus 4.8 baseline. This is the half Claude Code lets a hook enforce.
169
+ The hook runs on two events. `PreToolUse` gates a `/orc` or `/orc-diy` that
170
+ Claude starts through the Skill tool. `UserPromptExpansion` (v2.1.2) gates a
171
+ `/orc` or `/orc-diy` that you type. The typed gate reads the effort that the
172
+ ORC status line wrote for this session. If that reading is not there (no ORC
173
+ status line, or a headless `claude -p`), the typed command is not stopped.
174
+ `orc doctor` tells you when the typed gate is not wired; `orc update` adds it.
175
+ - **Model — a warning only.** Claude Code does not expose the model id to a
176
+ blocking hook, so the tier cannot be hard-stopped. `hooks/orc-statusline.js`
177
+ carries the verdict in its ICON — `✅` good, `🚀` better, `⛔` ORC will degrade,
178
+ the last of which always names its reason in brackets — and the orchestrator
179
+ checks itself at startup. (Before v1.2.1 the verdict was a WORD; the words are
180
+ now the installed ORC version. Every segment is documented in
181
+ `.claude/hooks/README.md`.) If you already run a statusline,
182
+ `orc init` leaves it alone and prints the snippet for you to merge.
183
+
184
+ The guard matches the **exact** skill name `orc`. `/orc-fast` legitimately runs
185
+ at Sonnet medium — it does no scoring or planning — so it is not in the guard,
186
+ and it never should be.
@@ -0,0 +1,305 @@
1
+ # Rules — `orc rules` in detail
2
+
3
+ README overflow. The short version is in the README under *Rules that keep the
4
+ slop out*; this is everything that would have bloated it.
5
+
6
+ ---
7
+
8
+ ## Two halves that never mix
9
+
10
+ | Half | Who writes it | Where it lives | Changes when |
11
+ |---|---|---|---|
12
+ | **ORC rules** | ORC | `.claude/skills/_shared/rules/` | `orc update` |
13
+ | **Your rules** | the project | `.claude/orc/rules.md` | you type |
14
+
15
+ The ORC rules are **read-only to you**. A write aimed at them is refused by
16
+ name, with the command that replaces it:
17
+
18
+ ```
19
+ $ orc rules set --pack writing --priority P0 --text "…"
20
+ ❌ ORC rules are read-only — they change with `orc update`, never with a command.
21
+ Write your own instead: orc rules add --priority P0 --text "…" (yours win on any conflict).
22
+ ```
23
+
24
+ `/orc-doc` reads none of this. That lane has its own ledger (`orc doc rules`)
25
+ and its own frozen-per-document mechanic, and the two surfaces are kept apart on
26
+ purpose.
27
+
28
+ ---
29
+
30
+ ## The 65 rules
31
+
32
+ | Pack | Ids | Rules | Applies to |
33
+ |---|---|---|---|
34
+ | Writing | `OSW-01…23` | 23 | every word an agent writes |
35
+ | Code | `OSC-01…22` | 22 | source an agent writes or edits |
36
+ | Delivery | `OSD-01…10` | 10 | what an agent reports about its own work |
37
+ | UI | `OSU-01…10` | 10 | front-end work only |
38
+
39
+ `orc rules packs` prints the table. `orc rules show <pack>` prints one pack.
40
+
41
+ ### The three tiers
42
+
43
+ | Tier | Meaning | On a finding |
44
+ |---|---|---|
45
+ | **HARD** | Absolute. No exception, no purpose that redeems it. | A finding. |
46
+ | **PURPOSE** | The technique is allowed. It needs a written one-line reason. | A missing reason is a finding; the technique is not. |
47
+ | **LOCK** | A consistency requirement. | Reported, never blocking. |
48
+
49
+ The tier system is Miqdad Badjuber's, from
50
+ [`miqdadbadjuber/anti-slop`](https://github.com/miqdadbadjuber/anti-slop), and it
51
+ exists for a reason worth stating: **a ban list alone leaves a void, and a model
52
+ fills a void with its most generic output.** A purpose gate asks for the reason
53
+ instead, which is the only thing that separates craft from a default.
54
+
55
+ ### The UI pack rides per TASK
56
+
57
+ `ui` is in no lane's default set. The orchestrator adds it to a single slice
58
+ when that task's declared files are front-end — `.css`, `.scss`, `.html`,
59
+ `.jsx`, `.tsx`, `.vue`, `.svelte`, or a directory the wiki or the cached pattern
60
+ names as the UI layer.
61
+
62
+ A UI rule in a backend slice is tokens paid on every spawn for a rule that
63
+ cannot apply.
64
+
65
+ ---
66
+
67
+ ## Precedence, and the sentence people get wrong
68
+
69
+ ```
70
+ house rules > your rules > ORC rules
71
+ ```
72
+
73
+ **The house card is CODE and BEHAVIOUR only.** It governs how a change is made:
74
+ surgical, simple, honest, in-slice. It says nothing about the words an agent
75
+ writes, so it never overrules a writing rule — *it does not speak about prose at
76
+ all.*
77
+
78
+ **A project rule beats an ORC rule outright.** Not a waiver and not a
79
+ negotiation: the ORC rule is removed from the slice, and the removal is stated
80
+ inside it.
81
+
82
+ To switch an ORC rule off, name its id in a rule of your own:
83
+
84
+ ```
85
+ $ orc rules add --priority P1 --text "OSW-13: em dashes are our house voice."
86
+ ✓ P1 extended — 1 line
87
+ ORC 65 (W 23 · C 22 · D 10 · U 10) · yours 3 lines (P0 2 · P1 1) · 1 override
88
+ ```
89
+
90
+ ### How an override is counted, and why it is counted that way
91
+
92
+ The CLI counts ORC rule ids you **named**. It says so in the same breath:
93
+
94
+ > counted from ORC rule ids you NAMED in your own rules. A conflict you did not
95
+ > name is found by the agent at dispatch and returned as `rules_conflicts[]` —
96
+ > the CLI cannot parse intent, so it does not pretend to.
97
+
98
+ That split is deliberate. A validator that guessed whether one of your sentences
99
+ contradicted a rule would be right often enough to be trusted and wrong often
100
+ enough to matter, and a clean pass would then mean nothing. The agent is the only
101
+ reader that can tell, so the agent is where the answer comes from.
102
+
103
+ **An override is never silent.** It appears in the preflight line, in the panel,
104
+ and inside every slice.
105
+
106
+ ---
107
+
108
+ ## Your ledger
109
+
110
+ `.claude/orc/rules.md`. Plain text, three headings, and as much text under each
111
+ as you want.
112
+
113
+ ```markdown
114
+ # ORC · project rules
115
+ # … anything above the first heading is your own note, never dispatched …
116
+
117
+ ## P0
118
+
119
+ Never name a customer in a commit message or a PR body. Use the account id.
120
+ Every public function in src/api/ carries a one-line comment naming its caller.
121
+
122
+ ## P1
123
+
124
+ Prefer Result<T, E> over throwing inside src/core/.
125
+
126
+ ## P2
127
+
128
+ Say "customer", never "user", in anything a customer reads.
129
+ ```
130
+
131
+ | Priority | Meaning | On conflict |
132
+ |---|---|---|
133
+ | **P0** | Must. A run that breaks it is wrong. | Beats P1, P2 and every ORC rule. |
134
+ | **P1** | Should. Break it only with a reason, and the reason is recorded as a gap. | Beats P2. |
135
+ | **P2** | Prefer. A default when nothing else decides. | Loses to everything above. |
136
+
137
+ **There is no rule id and no rule count on your side.** The unit is the block,
138
+ and the whole block is handed to every agent verbatim. This is the `orc doc
139
+ rules` design, reused without change, because that argument was already had: a
140
+ standing instruction is prose, not a form, and nobody's real P0 fits on one line.
141
+
142
+ ### The commands
143
+
144
+ ```
145
+ orc rules [--json] both halves + the precedence ladder 0 / 1
146
+ orc rules packs [--json] the pack table (read-only) 0 / 2
147
+ orc rules show <pack> [--json] ONE pack, rule by rule 0 / 2
148
+ orc rules user [--json] YOUR ledger and where it lives 0 / 1
149
+ orc rules credits [--json] every source, author and licence 0 / 2
150
+ orc rules slice --lane <lane> [--pack ui] THE dispatch text 0 / 2
151
+
152
+ orc rules set --priority P0 --text "…" replace ONE block
153
+ orc rules add --priority P0 --text "…" append to a block
154
+ orc rules clear --priority P0 empty ONE block
155
+ orc rules set-all --text "…" replace the WHOLE file (what `orc ui` writes)
156
+ orc rules --set-file <path> replace it from a file
157
+ orc rules --reset back to the bare template
158
+ ```
159
+
160
+ Exit `1` on a read means **no project rules yet**. That is an answer, and the
161
+ JSON object still comes back with the template in it.
162
+
163
+ `orc ui` ▸ **Rules** is the same thing with a text box and a Save button.
164
+ Nothing is written until you press Apply, the pending edit is named, and Discard
165
+ appears only while there is something to discard.
166
+
167
+ ---
168
+
169
+ ## The lint
170
+
171
+ ```
172
+ orc rules lint <path…|--staged|--diff> [--pack w,c,d,u] [--json]
173
+ ```
174
+
175
+ Free, deterministic, zero tokens. Exit `0` clean · `1` findings · `2` nothing to
176
+ lint.
177
+
178
+ It checks **13 of the 65 rules** — the ones a string match can prove:
179
+
180
+ | Checked | Rules |
181
+ |---|---|
182
+ | Banned lexicon and phrases | `OSW-10` `OSW-11` `OSU-06` |
183
+ | Em dash density | `OSW-13` |
184
+ | Emoji in a heading | `OSW-18` |
185
+ | Comment shapes | `OSC-02` `OSC-03` `OSC-04` `OSC-05` `OSC-06` `OSC-07` |
186
+ | Unrequested artifact files | `OSC-21` |
187
+ | `outline: none` with no replacement | `OSU-03` |
188
+
189
+ And it prints, in **every** mode, human and JSON:
190
+
191
+ ```
192
+ checked 13 rules of 65 — not checked here: 52 rules. They need a reader, not a matcher.
193
+ ```
194
+
195
+ That line is the point of the command. A lint that implied it had graded all 65
196
+ would let a clean exit stand in for a review that never happened.
197
+
198
+ **Findings are advisory.** There is no gate. A style preference that fails a
199
+ build gets switched off within a week, and then nothing is enforced at all.
200
+
201
+ ### What it skips, and why it says so
202
+
203
+ - **The rule packs themselves.** A rule that bans a word has to print that word
204
+ to define it, so the packs would fail their own lint on every line — and a
205
+ lint whose loudest findings are its own documentation is a lint people learn
206
+ to ignore.
207
+ - **`orc-rules-ignore-file`** in a file's head, or **`orc-rules-ignore`** on a
208
+ line: your own opt-out.
209
+
210
+ Both are counted in the output. An exemption nobody can see is a file that
211
+ passed without being read.
212
+
213
+ ### Em dash is a DOSE rule, not a ban
214
+
215
+ `OSW-13` is measured per file, never per occurrence:
216
+
217
+ - short output (a chat answer, a commit body, a label): none;
218
+ - a long document: at most two per thousand words.
219
+
220
+ ORC's own documentation uses em dashes, and a rule the shipping project breaks
221
+ on every page is a rule nobody will believe. The lint reports **density**.
222
+
223
+ ---
224
+
225
+ ## In a run
226
+
227
+ Every lane that writes words or code carries a card in every slice it
228
+ dispatches, assembled by one command (`orc rules slice`) and never by a skill:
229
+
230
+ ```
231
+ 1 HOUSE RULES how a change is made
232
+ 2 YOUR PROJECT'S RULES read first, and they win
233
+ 3 ORC RULES the anti-slop baseline
234
+ 4 the task
235
+ ```
236
+
237
+ Preflight prints one line:
238
+
239
+ ```
240
+ rules: ORC 65 (W 23 · C 22 · D 10 · U 10) · yours 9 lines (P0 4 · P1 2 · P2 3) · 1 override
241
+ rules: ORC 65 (W 23 · C 22 · D 10 · U 10) · yours none
242
+ ```
243
+
244
+ Both spellings are mandatory in their state. `yours none` says this project has
245
+ not written its own rules — a different fact from the CLI failing to look.
246
+
247
+ Every return gains three fields:
248
+
249
+ | Field | What it holds |
250
+ |---|---|
251
+ | `rules_applied[]` | the ids the agent acted on |
252
+ | `rules_conflicts[]` | two rules that disagree. **A gap, never a silent choice** |
253
+ | `rules_overridden[]` | an ORC id a project rule replaced |
254
+
255
+ ### The cost, stated
256
+
257
+ The card rides on **every spawn**. Measured at v1.7.0: about **3 600 tokens** per
258
+ build-lane slice, **4 300** with the UI pack, **2 200** for a prose-only lane.
259
+
260
+ It is already the cheap shape — HARD rules carry their body, PURPOSE and LOCK
261
+ rules carry one line each plus the file to open when one applies. If it has to
262
+ come down, the lever is `rulesSlice()` in the CLI, and never a lane trimming its
263
+ own card.
264
+
265
+ ---
266
+
267
+ ## The boundary
268
+
269
+ Rules govern **what is written and how it reads**, and **what shape of code is
270
+ acceptable**. They can never change how a lane **runs**: the scoring, the wave
271
+ order, the gates, the dispatch contract, the ship rules, or any lane's
272
+ structural and safety rules.
273
+
274
+ A rule that asks for one of those comes back as `unsupported_request` and is
275
+ relayed as a gap. Never a guessed compromise.
276
+
277
+ There is no detector for this, and there will not be one. The CLI declares the
278
+ boundary and does not pretend to enforce it — the same decision `orc doc rules`
279
+ made, for the same reason.
280
+
281
+ ---
282
+
283
+ ## Credit
284
+
285
+ The rules are adapted from other people's work. `orc rules credits` prints the
286
+ whole table; `CREDITS.md` beside the packs is the long form, with the date each
287
+ source was read.
288
+
289
+ | Source | Author | Licence |
290
+ |---|---|---|
291
+ | [`petergyang/no-ai-slop`](https://github.com/petergyang/no-ai-slop) | Peter G. Yang | MIT |
292
+ | [`miqdadbadjuber/anti-slop`](https://github.com/miqdadbadjuber/anti-slop) | Miqdad Badjuber | MIT |
293
+ | [`ehmo/slopkit`](https://github.com/ehmo/slopkit) | `@ehmo` | see repo |
294
+ | [`BioInfo/slopless`](https://github.com/BioInfo/slopless) | `@BioInfo` | see repo |
295
+ | Karpathy's `CLAUDE.md` | Andrej Karpathy | — |
296
+ | [The Anti-Slop Writing Rules](https://mattycartwright.com/blog/the-anti-slop-writing-rules) | Matty Cartwright | — |
297
+
298
+ Plus three papers on LLM code smells:
299
+ [2512.18020](https://arxiv.org/html/2512.18020v1) ·
300
+ [2605.02741](https://arxiv.org/html/2605.02741v1) ·
301
+ [2510.03029](https://arxiv.org/pdf/2510.03029).
302
+
303
+ If you are one of these authors and would prefer different wording, a different
304
+ attribution, or removal, open an issue on
305
+ [`azure-id/orc`](https://github.com/azure-id/orc).