@azure-id/orc 1.5.0 → 1.7.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 (74) hide show
  1. package/CHANGELOG.md +185 -0
  2. package/README-id.md +206 -125
  3. package/README.md +270 -57
  4. package/bin/cli.js +1676 -2
  5. package/bin/mockrun-catalog.js +272 -267
  6. package/bin/verify-contracts.js +4485 -4449
  7. package/bin/verify-package.js +9 -0
  8. package/bin/webui/api.js +26 -0
  9. package/bin/webui/app.html +10 -0
  10. package/bin/webui/css/panels/knowledge.css +30 -0
  11. package/bin/webui/css/panels/rules.css +145 -0
  12. package/bin/webui/fixtures/index.js +27 -0
  13. package/bin/webui/fixtures/rules.js +1002 -0
  14. package/bin/webui/fixtures/wiki-one.js +198 -0
  15. package/bin/webui/i18n/en/knowledge.json +127 -117
  16. package/bin/webui/i18n/en/nav.json +1 -0
  17. package/bin/webui/i18n/en/overview.json +1 -0
  18. package/bin/webui/i18n/en/rules.json +55 -0
  19. package/bin/webui/i18n/id/knowledge.json +127 -117
  20. package/bin/webui/i18n/id/nav.json +1 -0
  21. package/bin/webui/i18n/id/overview.json +1 -0
  22. package/bin/webui/i18n/id/rules.json +55 -0
  23. package/bin/webui/js/01-i18n.js +1 -0
  24. package/bin/webui/js/panels/knowledge.js +117 -1
  25. package/bin/webui/js/panels/overview.js +8 -0
  26. package/bin/webui/js/panels/rules.js +351 -0
  27. package/mock-run/INDEX.md +107 -106
  28. package/mock-run/orc-rules.md +254 -0
  29. package/package.json +1 -1
  30. package/templates/commands/orc-rules.md +66 -0
  31. package/templates/commands/orc-wiki.md +23 -1
  32. package/templates/hooks/README.md +110 -1
  33. package/templates/hooks/orc-read-gate.js +279 -0
  34. package/templates/skills/_shared/README.md +61 -54
  35. package/templates/skills/_shared/phases/README.md +1 -0
  36. package/templates/skills/_shared/phases/preflight.md +20 -0
  37. package/templates/skills/_shared/phases/rules.md +154 -0
  38. package/templates/skills/_shared/return-validation.md +28 -0
  39. package/templates/skills/_shared/rules/CREDITS.md +141 -0
  40. package/templates/skills/_shared/rules/INDEX.md +107 -0
  41. package/templates/skills/_shared/rules/code.md +229 -0
  42. package/templates/skills/_shared/rules/delivery.md +114 -0
  43. package/templates/skills/_shared/rules/ui.md +139 -0
  44. package/templates/skills/_shared/rules/writing.md +223 -0
  45. package/templates/skills/context-combiner/SKILL.md +9 -1
  46. package/templates/skills/orc/SKILL.md +7 -0
  47. package/templates/skills/orc-aftermath/SKILL.md +7 -0
  48. package/templates/skills/orc-analyze/SKILL.md +7 -0
  49. package/templates/skills/orc-analyze-mini/SKILL.md +9 -1
  50. package/templates/skills/orc-boundary/SKILL.md +7 -0
  51. package/templates/skills/orc-brainstorm/SKILL.md +7 -0
  52. package/templates/skills/orc-budget/SKILL.md +7 -0
  53. package/templates/skills/orc-challenge/SKILL.md +7 -0
  54. package/templates/skills/orc-claude/SKILL.md +7 -0
  55. package/templates/skills/orc-diy/SKILL.md +7 -0
  56. package/templates/skills/orc-explain/SKILL.md +7 -0
  57. package/templates/skills/orc-export/SKILL.md +7 -0
  58. package/templates/skills/orc-fast/SKILL.md +7 -0
  59. package/templates/skills/orc-grill/SKILL.md +7 -0
  60. package/templates/skills/orc-handoff/SKILL.md +9 -1
  61. package/templates/skills/orc-learn/SKILL.md +7 -0
  62. package/templates/skills/orc-mini/SKILL.md +7 -0
  63. package/templates/skills/orc-pact/SKILL.md +7 -0
  64. package/templates/skills/orc-poly/SKILL.md +7 -0
  65. package/templates/skills/orc-pr-driver/SKILL.md +9 -1
  66. package/templates/skills/orc-pr-setup/SKILL.md +9 -1
  67. package/templates/skills/orc-quick/SKILL.md +7 -0
  68. package/templates/skills/orc-retro/SKILL.md +7 -0
  69. package/templates/skills/orc-route/SKILL.md +7 -0
  70. package/templates/skills/orc-test/SKILL.md +7 -0
  71. package/templates/skills/orc-verify/SKILL.md +7 -0
  72. package/templates/skills/orc-wiki/SKILL.md +15 -0
  73. package/templates/skills/orc-wiki/references/partial-refresh.md +68 -0
  74. package/templates/skills/orc-wiki/references/phases/phase-0.md +15 -1
@@ -0,0 +1,254 @@
1
+ # Mock run — `orc rules`
2
+
3
+ > ORC ships 65 anti-slop rules. Your project writes its own. Yours win.
4
+
5
+ ---
6
+
7
+ ## 1. What it does
8
+
9
+ ORC writes a lot of prose and a lot of code, and both come out carrying the
10
+ same recognisable defaults: sentences that say nothing in a confident shape,
11
+ and code that is longer, more defensive and more abstract than the task asked
12
+ for. These rules are the filter.
13
+
14
+ There are two halves, and they never mix.
15
+
16
+ | Half | Who writes it | Where it lives | Changes when |
17
+ |---|---|---|---|
18
+ | **ORC rules** | ORC | `.claude/skills/_shared/rules/` | you run `orc update` |
19
+ | **Your rules** | you | `.claude/orc/rules.md` | you type |
20
+
21
+ The ORC rules are **read-only**. They were adapted, with credit, from other
22
+ people's work — `orc rules credits` names every source, its author, its licence
23
+ and what ORC took from it.
24
+
25
+ `/orc-doc` uses none of this. That lane has its own rules: `orc doc rules`.
26
+
27
+ ---
28
+
29
+ ## 2. Look at what you have
30
+
31
+ Rina has just installed ORC in the `acme-api` repo.
32
+
33
+ ```
34
+ $ orc rules
35
+
36
+ orc rules — ORC 65 (W 23 · C 22 · D 10 · U 10) · yours none
37
+
38
+ Precedence the order never changes
39
+ 1. house rules CODE and agent BEHAVIOUR only
40
+ _shared/phases/house-rules.md + the project's CLAUDE.md P0
41
+ beats everything below it, always
42
+ 2. your rules everything
43
+ <claude>/orc/rules.md
44
+ beats the ORC rules OUTRIGHT on any conflict
45
+ 3. ORC rules everything
46
+ <claude>/skills/_shared/rules/
47
+ beats nothing — it is the floor, and yours replaces it
48
+
49
+ ORC rules read-only — `orc update` changes them, nothing else
50
+ OSW Writing 23 HARD 14 · PURPOSE 2 · LOCK 7
51
+ OSC Code 22 HARD 17 · PURPOSE 4 · LOCK 1
52
+ OSD Delivery 10 HARD 7 · PURPOSE 0 · LOCK 3
53
+ OSU UI 10 HARD 7 · PURPOSE 1 · LOCK 2
54
+ /home/rina/acme-api/.claude/skills/_shared/rules
55
+
56
+ Your rules they win on any conflict
57
+ none yet
58
+ add one: orc rules add --priority P0 --text "…"
59
+ /home/rina/acme-api/.claude/orc/rules.md
60
+ ```
61
+
62
+ **`yours none` is an answer, not a gap.** It says this project has not written
63
+ its own rules yet. That is a different fact from the command failing to look,
64
+ and the line keeps the two apart.
65
+
66
+ The three tiers mean:
67
+
68
+ - **HARD** — absolute. No exception.
69
+ - **PURPOSE** — the technique is allowed. It needs a written one-line reason.
70
+ - **LOCK** — a consistency rule. Reported, never blocking.
71
+
72
+ ---
73
+
74
+ ## 3. Read one pack
75
+
76
+ ```
77
+ $ orc rules show writing
78
+
79
+ Writing (OSW) — 23 rules read-only
80
+
81
+ OSW-01 HARD Lead with the point
82
+ OSW-02 HARD No binary contrast
83
+ OSW-03 HARD No faux-insight setup
84
+ OSW-04 LOCK No colon reveal
85
+ OSW-05 HARD No fake-profound kicker, no summary recap
86
+ …
87
+ OSW-22 HARD A human's paragraph is not yours to restyle
88
+ OSW-23 HARD Never invent a specific
89
+
90
+ /home/rina/acme-api/.claude/skills/_shared/rules/writing.md
91
+ ```
92
+
93
+ ---
94
+
95
+ ## 4. Write your own
96
+
97
+ Rina's team has two standing rules. She types them the way she would say them.
98
+
99
+ ```
100
+ $ orc rules add --priority P0 --text "Never name a customer in a commit message or a PR body. Use the account id.
101
+ Every public function in src/api/ carries a one-line comment naming its caller."
102
+
103
+ ✓ P0 extended — 2 lines
104
+ ORC 65 (W 23 · C 22 · D 10 · U 10) · yours 2 lines (P0 2)
105
+ /home/rina/acme-api/.claude/orc/rules.md
106
+ ```
107
+
108
+ There is **no rule id and no rule count** on your side. The unit is the block,
109
+ and the whole block is handed to every agent exactly as you typed it. A rule you
110
+ no longer want, you delete.
111
+
112
+ Three headings, and as much text under each as you want:
113
+
114
+ - **P0** — must. A run that breaks it is wrong.
115
+ - **P1** — should. Break it only with a reason, and the reason is recorded.
116
+ - **P2** — prefer. A default when nothing else decides.
117
+
118
+ You can edit the file in your own editor instead. Or open `orc ui` ▸ **Rules**,
119
+ which is one text box and a Save button.
120
+
121
+ ---
122
+
123
+ ## 5. Turn an ORC rule off
124
+
125
+ ORC caps em dashes (`OSW-13`). Rina's team likes them. She does not argue with
126
+ the tool — she writes her own rule and names the id.
127
+
128
+ ```
129
+ $ orc rules add --priority P1 --text "OSW-13: em dashes are our house voice. Use them where they read best."
130
+
131
+ ✓ P1 extended — 1 line
132
+ ORC 65 (W 23 · C 22 · D 10 · U 10) · yours 3 lines (P0 2 · P1 1) · 1 override
133
+ ```
134
+
135
+ `1 override`. That count is **never silent**: it prints at preflight, it is
136
+ listed in the panel, and it is stated inside every slice ORC dispatches.
137
+
138
+ The count comes from ORC rule ids you **named**. A rule of yours that
139
+ contradicts an ORC rule without naming it is found by the agent while it works,
140
+ and comes back as a conflict for you to settle — never a choice it makes
141
+ quietly. The command says so in its own output.
142
+
143
+ **Trying to edit ORC's own packs is refused by name:**
144
+
145
+ ```
146
+ $ orc rules set --pack writing --priority P0 --text "…"
147
+ ❌ ORC rules are read-only — they change with `orc update`, never with a command.
148
+ Write your own instead: orc rules add --priority P0 --text "…" (yours win on any conflict).
149
+ ```
150
+
151
+ ---
152
+
153
+ ## 6. Check a file, for free
154
+
155
+ ```
156
+ $ orc rules lint src/checkout.js README.md
157
+
158
+ orc rules lint — 2 files (paths)
159
+
160
+ src/checkout.js
161
+ 1 OSC-02 HARD No decorative separator
162
+ ==========================
163
+ → one plain line, or nothing
164
+ 2 OSC-04 HARD No empty label
165
+ MAIN LOGIC
166
+ → the label names a category, not a fact — delete it
167
+ 7 OSC-05 HARD A TODO names a task
168
+ TODO: improve this
169
+ → name the task and enough context to act on it, or delete it
170
+
171
+ README.md
172
+ 3 OSW-11 HARD Banned phrases
173
+ it's worth noting
174
+ → delete the clause and keep the point
175
+
176
+ off here your own rules name these ids
177
+ OSW-13
178
+
179
+ checked 12 rules of 65 — not checked here: 53 rules. They need a reader, not a matcher.
180
+ ```
181
+
182
+ That last line is the important one. **The lint only checks what a string match
183
+ can prove** — banned words, banned phrases, comment shapes, emoji in a heading,
184
+ em dash density, a few more. The other 53 rules need a reader.
185
+
186
+ A clean lint is not a clean review, and the command says so every time, even
187
+ when it finds nothing.
188
+
189
+ It costs nothing and calls no model. It **reports**; it never fixes.
190
+
191
+ Two things it skips, and it counts both rather than staying quiet: the rule
192
+ packs themselves (a rule that bans a word has to print that word to define it),
193
+ and any file you mark `orc-rules-ignore-file`. One line you want left alone gets
194
+ `orc-rules-ignore` on it.
195
+
196
+ ---
197
+
198
+ ## 7. What a run does with them
199
+
200
+ Every lane that writes words or code now carries a card in every slice it
201
+ dispatches, in this order and no other:
202
+
203
+ ```
204
+ 1 HOUSE RULES how a change is made: surgical, simple, honest
205
+ 2 YOUR PROJECT'S RULES read first, and they win
206
+ 3 ORC RULES the anti-slop baseline
207
+ 4 the task
208
+ ```
209
+
210
+ The house rules are about **code and behaviour**. They say nothing about the
211
+ words an agent writes, so they never overrule a writing rule.
212
+
213
+ At preflight you see one line:
214
+
215
+ ```
216
+ rules: ORC 65 (W 23 · C 22 · D 10 · U 10) · yours 3 lines (P0 2 · P1 1) · 1 override
217
+ ```
218
+
219
+ And every agent reports back what it did with them: which rules it acted on,
220
+ which two rules disagreed, and which ORC rule your own rule replaced. A conflict
221
+ comes back as a gap for you to settle.
222
+
223
+ ---
224
+
225
+ ## 8. Where the rules came from
226
+
227
+ ```
228
+ $ orc rules credits
229
+ ```
230
+
231
+ Every source, with its licence and what was taken:
232
+
233
+ - **Peter G. Yang** — [`petergyang/no-ai-slop`](https://github.com/petergyang/no-ai-slop) (MIT)
234
+ - **Miqdad Badjuber** — [`miqdadbadjuber/anti-slop`](https://github.com/miqdadbadjuber/anti-slop) (MIT)
235
+ - **`@ehmo`** — [`ehmo/slopkit`](https://github.com/ehmo/slopkit)
236
+ - **`@BioInfo`** — [`BioInfo/slopless`](https://github.com/BioInfo/slopless)
237
+ - **Andrej Karpathy** — his `CLAUDE.md`
238
+ - **Matty Cartwright** — The Anti-Slop Writing Rules
239
+ - Three research papers on LLM code smells
240
+
241
+ The long form is `CREDITS.md` beside the packs, and the panel renders the same
242
+ table. Credit is a shipped file here, not a line in a commit message.
243
+
244
+ ---
245
+
246
+ ## 9. What it never does
247
+
248
+ - It never edits ORC's own packs. `orc update` does that, and nothing else.
249
+ - It never resolves a conflict for you. A conflict is a gap you settle.
250
+ - It never blocks a run. The lint reports; there is no gate.
251
+ - It never pretends the lint covered rules it could not check.
252
+ - It never guesses that one of your sentences contradicts a rule. It counts the
253
+ ids you named and says that is what it counted.
254
+ - It never reaches `/orc-doc`. That lane has `orc doc rules`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@azure-id/orc",
3
- "version": "1.5.0",
3
+ "version": "1.7.0",
4
4
  "description": "ORC — an orchestrator skill constellation for Claude Code: intake, planning, scored parallel subagents, code-pattern matching, review, verify, ship, plus a project knowledge-base wiki.",
5
5
  "bin": {
6
6
  "orc": "bin/cli.js"
@@ -0,0 +1,66 @@
1
+ ---
2
+ description: The anti-slop rules — ORC's shipped packs (read-only) and this project's own, which win on any conflict
3
+ ---
4
+
5
+ Do not use a skill. This command is a **CLI surface**, and the CLI is the only
6
+ thing that reads or writes either half.
7
+
8
+ ## What this is
9
+
10
+ Two rule sets, and they never mix:
11
+
12
+ - **ORC rules** — 65 shipped rules in four packs, tagged `ORC RULE`, **read-only**.
13
+ They change with `orc update` and with nothing else. Adapted, with credit, from
14
+ `petergyang/no-ai-slop`, `miqdadbadjuber/anti-slop`, `ehmo/slopkit`,
15
+ `BioInfo/slopless`, Andrej Karpathy's `CLAUDE.md` and Matty Cartwright's
16
+ anti-slop writing rules. `orc rules credits` names every one.
17
+ - **Your rules** — a plain text file, `.claude/orc/rules.md`, three headings
18
+ (P0, P1, P2) and as much text under each as you want. **They beat an ORC rule
19
+ outright** wherever the two disagree.
20
+
21
+ Above both sits the project's CODE house rules, which govern how a change is
22
+ made and say nothing about the words an agent writes.
23
+
24
+ ```
25
+ house rules > your rules > ORC rules
26
+ ```
27
+
28
+ `/orc-doc` reads none of this. That lane has its own ledger: `orc doc rules`.
29
+
30
+ ## Run this
31
+
32
+ ```
33
+ orc rules both halves, the ladder, the counts
34
+ orc rules packs the four packs (read-only)
35
+ orc rules show writing|code|delivery|ui one pack, rule by rule
36
+ orc rules credits every source, author and licence
37
+ orc rules user your own ledger and where it lives
38
+
39
+ orc rules add --priority P0 --text "…" append a rule, as many lines as you like
40
+ orc rules set --priority P1 --text "…" replace that whole block
41
+ orc rules clear --priority P2 empty one block
42
+ orc rules --reset back to the bare template
43
+
44
+ orc rules lint <path> | --staged | --diff the FREE check, zero tokens
45
+ ```
46
+
47
+ `orc ui` ▸ **Rules** is the same thing with a text box and a Save button.
48
+
49
+ ## Then report, in this order
50
+
51
+ 1. `orc rules` — print its output. The precedence ladder is the part people get
52
+ wrong, so it goes first and is never summarised away.
53
+ 2. If the user asked to ADD a rule, run the `add` command with their words
54
+ **verbatim**. Never re-word a standing instruction into your own phrasing:
55
+ the whole block is handed to every agent exactly as typed.
56
+ 3. If they asked to turn an ORC rule OFF, tell them how: name its id in a rule
57
+ of their own (`OSW-13: em dashes are our house voice.`). The override is then
58
+ counted, printed at preflight, and stated inside every slice.
59
+ 4. If they asked whether something IS slop, run `orc rules lint` on it and relay
60
+ the coverage line it prints — the one that says how many rules it did not
61
+ check. A clean lint is not a clean review, and that line is the difference.
62
+
63
+ Never edit `.claude/orc/rules.md` with a file tool. `orc rules` is its only
64
+ writer, and the panel goes through the same command.
65
+
66
+ What about the rules: $ARGUMENTS
@@ -33,10 +33,32 @@ linked repo (in-place, user content byte-preserved). Requires a crosslink
33
33
  config with ≥1 edge; every step warn-only; never a re-scan. Peer writes are
34
34
  FILE writes only — never a commit or push.
35
35
 
36
+ **`/orc-wiki update <doc-or-topic>`** → ONE doc, re-scanned. A filename goes
37
+ straight into the targeted refresh. A topic ("the remittance feature") is
38
+ resolved first with `orc wiki resolve` — free, no scan — and an AMBIGUOUS result
39
+ is a question for you, never a guess. Branch detection and area planning are both
40
+ skipped: the doc exists, so its coverage area is already in its own header.
41
+
42
+ **`/orc-wiki add "<topic>"`** → ONE new doc, in a wiki that already exists, with
43
+ no other area re-planned. It resolves the topic first (if something already
44
+ covers it, that is an `update` and it says so), proposes a coverage scope from
45
+ path names for you to correct, confirms the slug, the covers, the tier and the
46
+ cost in ONE turn, and scans nothing until you say yes. It ends with
47
+ `orc wiki refs`, the derived-reference sweep — adding a doc moves more derived
48
+ surfaces than changing one does: the registration, the orientation page, the
49
+ architecture overview, the CLAUDE.md pointer's doc count, and any crosslink tag
50
+ left anchored to a file that is gone. Only the registration is repaired for you;
51
+ the rest is reported with its command, because a sweep that silently regenerated
52
+ prose would be spending money nobody asked it to spend.
53
+
36
54
  | Argument | Branch |
37
55
  |---|---|
38
56
  | *(none)* | Phase 0 auto-branch: repair / fresh / resume / refresh (delta default) |
57
+ | `update <doc>` | targeted refresh of ONE doc (skips branch detection + area planning) |
58
+ | `update "<topic>"` | resolve the topic to a doc, then refresh it |
59
+ | `add "<topic>"` | reserve + scan + write ONE new doc, then sweep every derived reference |
39
60
  | `crosslink` | Phase 3c legacy backfill (publish tags from existing docs) |
40
61
  | `crosslink compile` | one-shot resolve + atlas + CLAUDE.md injection (local + peers) |
41
62
 
42
- Optional focus (or `crosslink` / `crosslink compile`): $ARGUMENTS
63
+ Optional focus (`update <doc>` · `add "<topic>"` · `crosslink` ·
64
+ `crosslink compile`): $ARGUMENTS
@@ -1,8 +1,11 @@
1
- # The ORC status line
1
+ # The ORC hooks
2
2
 
3
3
  > This page is written in Simplified Technical English. Short sentences, one
4
4
  > idea each, plain words. See `bin/webui/i18n/TERMS.md` for the term list.
5
5
 
6
+ This page covers the two hooks you can see. The STATUS LINE, which shows what
7
+ is happening, and the READ GATE, which can stop an oversized read.
8
+
6
9
  ORC shows two lines at the bottom of your terminal. Claude Code draws them.
7
10
  ORC writes them.
8
11
 
@@ -258,6 +261,91 @@ it did not see.
258
261
 
259
262
  ---
260
263
 
264
+ ## The read gate
265
+
266
+ This is a different hook. It is off when you install ORC.
267
+
268
+ ORC has a rule about reading. The main session reads a file to FIND things.
269
+ To UNDERSTAND a file, ORC sends an agent to read it and report back. The agent
270
+ uses its own context, not yours. The rule was written in three guide files and
271
+ nothing checked it. The read gate is the part that can say no.
272
+
273
+ Turn it on like this:
274
+
275
+ ```
276
+ orc config set read_gate warn # it tells you, and still reads the file
277
+ orc config set read_gate block # it stops the read
278
+ orc config set read_gate off # the default
279
+ ```
280
+
281
+ ### What it does
282
+
283
+ It looks at one thing: a `Read` of a whole file, by the main session, during an
284
+ ORC run, when the file is 1000 lines or more.
285
+
286
+ In `warn` it shows you a note and reads the file anyway. In `block` it stops the
287
+ read and tells you three other ways to get what you need:
288
+
289
+ - Read the file with `offset` and `limit`. This is never stopped.
290
+ - Search the file first, then read that part.
291
+ - Send an agent to read it. An agent's reads are never stopped.
292
+
293
+ **A block always names another way.** A gate that only says no is a gate people
294
+ turn off.
295
+
296
+ ### When it says nothing
297
+
298
+ This list is the important part. The gate is quiet in all of these states, and
299
+ each one is on purpose:
300
+
301
+ | State | Why |
302
+ |---|---|
303
+ | An agent is reading | An agent must read a file in full before it edits it. If it could not, it would guess the old text and damage the file. |
304
+ | `read_gate` is `off` | This is the default. With `off`, the hook does nothing at all. |
305
+ | No ORC run is open | The gate is about ORC's own reading. It is not a rule for your session. Outside a run it never stops anything. |
306
+ | You used `offset` or `limit` | This is the behaviour the gate wants. It can never stop it. |
307
+ | The file is under 1000 lines | See the next part. |
308
+ | The file is a build log, a test result, or `.jsonl` | ORC reads these to decide pass or fail. A cut-short failing build looks like a passing build. That is worse than any saving. |
309
+ | The gate hit an error | It always lets the read through. Then it writes down what went wrong. |
310
+
311
+ **The gate cannot see a file you read with a shell command** such as `cat` or
312
+ `head`. It only sees the `Read` tool.
313
+
314
+ ### Why 1000 lines
315
+
316
+ Sending an agent is not free. One real agent read cost about 13,000 tokens and
317
+ about 76 seconds. A line in this project is about 55 characters. So a file must
318
+ be near 1000 lines before sending an agent costs less than reading it yourself.
319
+
320
+ Below that number, sending an agent costs more than it saves.
321
+
322
+ You can change it:
323
+
324
+ ```
325
+ orc config set read_gate_max_lines 500
326
+ ```
327
+
328
+ ### What it never does
329
+
330
+ - It never stops an agent's read.
331
+ - It never stops a read outside an ORC run.
332
+ - It never stops a `Bash` command.
333
+ - It never reads the file to you. It only counts the lines.
334
+ - It never fails closed. If the hook breaks, your read still happens.
335
+
336
+ ### Where to look when it acts
337
+
338
+ Every `warn` and every `block` writes one line in the run trace:
339
+
340
+ ```
341
+ [070926 14:22:01.220] hook READ-GATE block :: lines=2400 max=1000 file=big-plan.md
342
+ ```
343
+
344
+ An allowed read writes nothing. `orc doctor` tells you if the gate is on but not
345
+ wired, and if it ever had to let a read through because it could not judge it.
346
+
347
+ ---
348
+
261
349
  ## For maintainers
262
350
 
263
351
  - The hook is `orc-statusline.js`. `orc init` installs it and wires it into
@@ -285,3 +373,24 @@ it did not see.
285
373
  - The cache file is `.claude/orc/usage-session.json`. The hook reads it once and
286
374
  writes it once, after the text is ready. It stores raw numbers only — never a
287
375
  word like `fresh` or `STALE`, which is computed each time it is shown.
376
+
377
+ ### The read gate
378
+
379
+ - The hook is `orc-read-gate.js`, on `PreToolUse` with matcher `Read`. `orc
380
+ init` wires it even though `read_gate` defaults to `off`, so arming it is a
381
+ config edit and never an install step somebody has to find.
382
+ - **`off` is byte-identical to not having the hook**, and a test asserts it.
383
+ - **`agent_id` is the only way to tell a subagent's read from the main
384
+ session's, and this was MEASURED, not assumed.** `PreToolUse` does fire
385
+ inside a dispatched subagent, and `session_id` and `transcript_path` are
386
+ identical in both. A gate written against either would block the full read an
387
+ executor must do before it edits, and a reconstructed `old_string` corrupts
388
+ files. Test for the PRESENCE of `agent_id`. Never test for the absence of
389
+ another key — that is not a positive statement about anything.
390
+ - The threshold is measured, not borrowed. See `read_gate_max_lines`.
391
+ - It fails open on every path, and each failure it can name writes
392
+ `.claude/orc/read-gate-fallback.json` for `orc doctor` to turn into a
393
+ sentence — only while the feature is armed.
394
+ - It writes one trace line per `warn` and per `block`, never on an allow. That
395
+ is affordable here for a structural reason: the gate only acts while a run is
396
+ open, so a trace always exists.