@redue/cli 0.1.0-alpha.3 → 0.1.0-alpha.30

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 (67) hide show
  1. package/CHANGELOG.md +806 -0
  2. package/README.md +157 -99
  3. package/bin/redue.mjs +267 -61
  4. package/docs/README.md +3 -1
  5. package/docs/user/agents.md +333 -15
  6. package/docs/user/configuration.md +28 -2
  7. package/docs/user/direct-typescript.md +219 -0
  8. package/docs/user/getting-started.md +49 -7
  9. package/docs/user/json.md +4 -2
  10. package/docs/user/node-script.md +177 -0
  11. package/docs/user/npm-launcher-notice.md +42 -0
  12. package/docs/user/pilot.md +146 -0
  13. package/docs/user/sandbox.md +312 -0
  14. package/docs/user/shell.md +3 -3
  15. package/docs/user/supported-projects.md +69 -23
  16. package/docs/user/tests-direct.md +143 -0
  17. package/package.json +4 -3
  18. package/src/agent-integration.mjs +467 -0
  19. package/src/agent-policy.md +28 -0
  20. package/src/cached-state.mjs +24 -1
  21. package/src/claude-hook.mjs +616 -0
  22. package/src/cli.mjs +449 -54
  23. package/src/daemon.mjs +442 -93
  24. package/src/decision-profile.mjs +15 -1
  25. package/src/decision-validation.mjs +12 -1
  26. package/src/declared-plan.mjs +38 -6
  27. package/src/direct-run-certificate.mjs +254 -0
  28. package/src/direct-typescript-probe.mjs +27 -0
  29. package/src/direct-typescript.mjs +205 -0
  30. package/src/glob.mjs +8 -0
  31. package/src/history-worker.mjs +21 -13
  32. package/src/index.mjs +108 -21
  33. package/src/installed-inputs.mjs +7 -1
  34. package/src/installed-observation.mjs +23 -0
  35. package/src/landlock.py +527 -0
  36. package/src/linux-inotify.py +39 -10
  37. package/src/node-onboarding.mjs +203 -54
  38. package/src/node-script.mjs +406 -0
  39. package/src/npm-integrity.mjs +124 -0
  40. package/src/npm-typecheck-environment.mjs +36 -0
  41. package/src/npmrc.mjs +16 -0
  42. package/src/observation.mjs +34 -12
  43. package/src/path-identity.mjs +8 -0
  44. package/src/plan-worker.mjs +17 -17
  45. package/src/pnpm-inputs.mjs +122 -57
  46. package/src/pnpm-shim-templates.json +180 -0
  47. package/src/pnpm-shims.mjs +54 -0
  48. package/src/pnpm-typecheck-probe.mjs +11 -6
  49. package/src/presentation.mjs +13 -4
  50. package/src/probe-deadline.mjs +37 -0
  51. package/src/probe-result.mjs +7 -3
  52. package/src/project-location.mjs +34 -0
  53. package/src/python-onboarding.mjs +89 -0
  54. package/src/run-recorder.cjs +91 -0
  55. package/src/sandbox.mjs +653 -0
  56. package/src/setup.mjs +205 -0
  57. package/src/stats.mjs +72 -0
  58. package/src/test-direct.mjs +608 -0
  59. package/src/test-recorder.cjs +435 -0
  60. package/src/typescript-contract-probe.mjs +4 -187
  61. package/src/typescript-input-facts.mjs +92 -0
  62. package/src/typescript-invocation.mjs +92 -0
  63. package/src/typescript-list.mjs +118 -13
  64. package/src/typescript-qualification.mjs +29 -49
  65. package/src/workspace-manifests.mjs +24 -0
  66. package/src/yarn-workspace-inputs.mjs +3 -0
  67. package/src/yarn-workspace-typecheck-probe.mjs +2 -1
@@ -1,20 +1,29 @@
1
1
  # Agent decision policy
2
2
 
3
- Use the CLI; no SDK or bespoke agent integration is required. Add these
4
- instructions to a session or project only with its owner's permission.
5
-
6
- 1. Query ordinary `redue status --json` first.
7
- 2. If a check has `freshness: "CURRENT"`, `result: "PASS"`, and
8
- `reuse_eligible: true`, reuse it. Do not rerun merely for freshness.
9
- 3. If STALE, run `redue run CHECK` when that verification is needed.
10
- 4. If the historical `result` is FAIL, report it honestly. The human CLI calls
11
- this FAILED; applicability is a separate field, never an excuse to call it green.
12
- 5. If UNVERIFIED, inspect its reason. Use `status --sync --json` when establishing
13
- applicability is worthwhile, or rerun the underlying check when cheaper/simpler.
14
- Use `redue run CHECK` if a new receipt is wanted. Incomplete coverage can remain
15
- UNVERIFIED even after success.
16
- 6. Do not assume synchronization is cheaper than execution. There are no universal
17
- package-manager or OS thresholds. Inexpensive checks may be cheaper to rerun.
3
+ Use the CLI with explicit project-local activation below, or add this policy to a
4
+ generic agent's instructions with the project owner's permission.
5
+
6
+ 1. If fresh execution is already required, execute it; do not synchronize merely
7
+ to confirm an irrelevant reuse opportunity. Use `redue run CHECK` when recording
8
+ the configured check. An explicit npm-script request still requires npm.
9
+ 2. For reuse of the explicitly configured direct compiler recipe
10
+ (`qualification: "npm-typescript-direct-v1"`, direct compiler command; receipt
11
+ `verification_recipe: "npm-direct-typescript@1"`), query once:
12
+ `redue --config CONFIG status --sync --json`. Do not infer a recipe from its name.
13
+ Cached status cannot establish its caller context. In mixed configurations,
14
+ assess each check's contract separately; this is not a global sync-first policy.
15
+ 3. For other/unknown recipes, `status --json` synchronizes too (`--sync` is the
16
+ same); `status --cached --json` and `--short` remain cheap inspection.
17
+ 4. Reuse only schema 1, healthy observation and the selected check's CURRENT/PASS
18
+ with `reuse_eligible: true`. Missing eligibility means false. A historical FAIL
19
+ is never green evidence. Do not rerun eligible evidence merely for freshness.
20
+ 5. STALE requires execution when verification is needed. UNVERIFIED requires an
21
+ honest choice of synchronization, permitted execution or reporting the limitation.
22
+ Recording-only success can remain UNVERIFIED. A deliberate cheap-check rerun is
23
+ permitted; there are no universal platform/package-manager timing thresholds.
24
+ 6. Use a successful synchronized response for the current decision without repeated
25
+ sync/explain calls unless edits, context changes or missing information require it.
26
+ Do not loop until green or use an earlier response after a later query fails.
18
27
 
19
28
  `redue explain CHECK --json` gives synchronized detail, including a known changed
20
29
  input when available. It has the same cost caveat as synchronized status.
@@ -25,8 +34,317 @@ check is not universal product correctness. Report additional uncaptured checks
25
34
  separately. Do not infer that an outer invocation's success proves a specific
26
35
  check ran or that an upstream cache was hit; inspect `target_provenance`.
27
36
 
37
+ Reassess at the decision point after edits or context changes; previous CURRENT is
38
+ not continuing authorization. A status exit code of zero is not proof of CURRENT.
39
+ An empty changed-input list does not prove nothing changed. `run CHECK --json`
40
+ streams check output; use a subsequent status/explain query for structured evidence.
41
+ Explicit fresh-execution requests still require execution.
42
+
28
43
  On a CLI error, unhealthy observation, or unavailable context, do not infer
29
44
  CURRENT. Do not delete state or reset receipts to make the output green.
30
45
 
31
46
  REDUE tells you what evidence exists and whether it still applies. It does not
32
47
  promise that establishing applicability is cheaper than every possible check.
48
+
49
+ ## Connect once (experimental)
50
+
51
+ Alpha.5 and later support opt-in project-local activation and direct
52
+ TypeScript evidence, with fresh-session reuse demonstrated for Codex CLI 0.160.1
53
+ and subsequent 0.162.0 trials on macOS under the documented owner-approved checkout/state/socket route. CLI
54
+ mechanics are tested on macOS/Linux/Windows; model behavior is not claimed for
55
+ every host/platform or sandbox policy. Claude setup/removal mechanics are tested,
56
+ but Claude behavior and cross-host reuse remain untested. Reuse is not guaranteed,
57
+ and the existing subsecond example establishes no meaningful net time saving.
58
+
59
+ After installing REDUE and running `redue init` in a trusted project:
60
+
61
+ ```sh
62
+ redue agent setup codex --dry-run
63
+ redue agent setup codex --apply
64
+ # Or: redue agent setup claude --apply
65
+ redue agent doctor
66
+ ```
67
+
68
+ Start a fresh agent session in this checkout, then give it your ordinary task.
69
+ Interactive setup shows the changes and asks before applying; noninteractive
70
+ setup requires `--apply`. `--dry-run` never writes. Installing REDUE or running
71
+ `init` does not connect an agent automatically. Setup does not start an observer
72
+ or execute verification. With Claude Code, a SessionStart hook starts the
73
+ observer when a session starts (below); otherwise use `redue start`.
74
+
75
+ ## Claude Code typecheck hook
76
+
77
+ `redue agent setup claude --apply` (and `redue setup claude`) also adds a
78
+ PreToolUse hook and a SessionStart hook to `.claude/settings.local.json`.
79
+ Both run `redue agent hook claude`, which needs a local REDUE install, so
80
+ they are per-developer; keep that file out of commits. Setup names REDUE
81
+ plainly only when the `redue` that both your shell and a login shell find on
82
+ PATH is the install running setup. Otherwise the hooks name this install's
83
+ Node and entry by absolute path, so a Claude Code started from an IDE, a
84
+ desktop app or another shell still runs the right REDUE; run setup again
85
+ after moving or upgrading Node. `redue agent doctor` reports a hook whose
86
+ paths no longer exist. When the hook runs a check through REDUE for the
87
+ agent, it likewise writes plain `redue run` only if its own PATH finds this
88
+ install, else the absolute form.
89
+
90
+ Agents often chain an edit and a check (`printf … >> README.md && npm run
91
+ lint`). In a simple chain (commands joined by `&&`, `||` or `;`, with no
92
+ subshell, here-document, command substitution, background job or shell
93
+ keyword) where every part before a check is a program on PATH (not a
94
+ builtin such as `cd` or `export`, a shell function such as `nvm`, or a bare
95
+ assignment), the hook rewrites each check to `redue run CHECK --if-due`. That
96
+ command decides when its turn comes, after the earlier parts may have
97
+ changed files: it skips the check (exit 0, and says so) when its last pass
98
+ still applies, and otherwise runs it through REDUE with the exit code a plain
99
+ run gives. A script that runs several checks becomes `{ redue run a --if-due
100
+ && redue run b --if-due; }`. The rest of the chain is unchanged. The hook
101
+ rewrites only while the observer is healthy and knows each check. It changes
102
+ such a command without approving it, so your permission rules apply to the
103
+ rewritten command; a rule that allows only `npm run lint` will ask about
104
+ `redue run lint --if-due`. Anything more complex runs untouched. Known
105
+ limit: if REDUE cannot start the check when its turn comes (another
106
+ `redue run` holds the project's run lock), that part exits with REDUE's
107
+ error instead of running the check. Other settings in the file are kept,
108
+ but the file is rewritten as 2-space JSON. `.claude/settings.json` is not touched.
109
+ `redue agent remove claude --apply` removes only the entries REDUE added.
110
+
111
+ When a session starts, resumes, clears or compacts, the SessionStart hook starts
112
+ this project's observer if none is running. It launches `redue start` in the
113
+ background and returns at once, and prints nothing, so it adds nothing to the
114
+ agent's context. Until the observer's first index is done, checks are
115
+ UNVERIFIED and run as typed. An observer you stopped with `redue stop` starts
116
+ again with the next session; remove the hook to prevent that. Setups from
117
+ alpha.15 or earlier get the hook by running `redue agent setup claude --apply`
118
+ again.
119
+
120
+ The hook skips an exact rerun of a configured typecheck (a check with
121
+ `kind: "typecheck"` or named `typecheck`) or direct test check. It matches
122
+ these commands, run from the project root:
123
+
124
+ - `redue run CHECK`, or `redue --config FILE run CHECK` when the config is not
125
+ `redue.config.json`
126
+ - the check's script through the project's package manager: `npm run SCRIPT`
127
+ (and `npm test`), `pnpm SCRIPT`, `pnpm run SCRIPT`, `yarn SCRIPT` or
128
+ `yarn run SCRIPT`. The short form is left out when the script is named like
129
+ one of the package manager's own commands.
130
+ - the tool the check runs: `npx tsc ARGS` (and `pnpm exec tsc ARGS` with pnpm)
131
+ for a direct TypeScript check, or the runner's command, alone or after `npx`,
132
+ for a direct test check
133
+ - the check's `command`, when it has no `@` tokens
134
+ - for a workspace package's check: `pnpm --filter NAME SCRIPT` (also
135
+ `--filter=NAME`, `-F NAME`, and with `run`), `yarn workspace NAME SCRIPT`, or
136
+ `npm run SCRIPT -w NAME` (also `--workspace NAME`, `--workspace=NAME` and
137
+ `npm -w NAME run SCRIPT`). After `cd` into the package's directory, the
138
+ package-manager script forms and tool forms match that check.
139
+
140
+ A `turbo run TASK` (or `turbo TASK`, alone or after `npx` or `pnpm exec`) or,
141
+ in a pnpm project, `pnpm -r TASK` (`--recursive`, with or without `run`) that
142
+ runs a checked task in every workspace package is skipped only when every check
143
+ it would run is CURRENT, PASS and `reuse_eligible`. Every package with the
144
+ task's script must have a check. turbo must define the task, with `dependsOn`
145
+ listing at most `^TASK`, no `with`, no `PACKAGE#TASK` entries and no package
146
+ `turbo.json`; `pnpm -r` must not include the workspace root. A root script
147
+ whose text is such a command counts as that command, unless it has pre- or
148
+ post-scripts. In every other case the command runs as typed: turbo caches its
149
+ own results, so the hook never rewrites it. Filters (`--filter`) and nx are not
150
+ matched.
151
+
152
+ For a typecheck check that runs the compiler, the script's forms act only when
153
+ the script in package.json still has exactly the configured runs: one `tsc`
154
+ run per check with the same arguments, and no pre- or post-script. Otherwise
155
+ the command runs as typed. A script that chains `tsc` runs with `&&` has one
156
+ check per run, `typecheck.1`, `typecheck.2` and so on (see
157
+ [direct TypeScript](direct-typescript.md#script-forms)); each run's own
158
+ `npx tsc ...` form matches its check. The hook skips the script when all its
159
+ runs are CURRENT, PASS and `reuse_eligible`, and otherwise rewrites it to
160
+ `redue run` of the runs that are not, in the script's order, joined by `&&`.
161
+ In a turbo or `pnpm -r` fan-out, a package's script counts only the same way.
162
+
163
+ Each form may end with `2>&1` and then one `| tail -n N`, `| head -n N`,
164
+ `| tail -N` or `| head -N`. It may also be the first command of a `;` or `&&`
165
+ chain. Nothing else matches. Each form has its own `if` rule, so other Bash
166
+ commands never start the hook. The installed skill lists these exact commands,
167
+ so the agent uses forms the hook recognizes.
168
+
169
+ On a match, the hook runs `redue status --sync --json`. It waits up to half the
170
+ duration of the check's last completed run, at least 2 seconds and at most 10
171
+ seconds. A status call usually takes 70-250 ms, so a fast check (mypy in 0.2 s)
172
+ is still skipped when CURRENT, or run through `redue run` and recorded when not.
173
+ When the observer is slow or stuck, a matching command can wait the full 2
174
+ seconds before it runs as written. Claude Code's own limit for the hook is 15
175
+ seconds.
176
+
177
+ To see why the hook decided what it did, set `REDUE_HOOK_LOG` to an absolute
178
+ file path in the environment Claude Code starts with. The hook appends one JSON
179
+ line per Bash command: the command, the decision (`deny`, `rewrite` or
180
+ `allow`) and why, such as `no check matches the command` or `status did not
181
+ answer within 2000 ms`.
182
+ It blocks the command only when the check is CURRENT, PASS and
183
+ `reuse_eligible: true`. The message names the check and the receipt's run ID. Every
184
+ other result allows the command: STALE, UNVERIFIED, FAILED, a timeout, an error, or
185
+ a missing `redue`. A command that starts with `REDUE_FORCE=1` always runs. A
186
+ blocked chain runs none of its commands; the message names the rest of the chain
187
+ so the agent can run it on its own.
188
+
189
+ When the check is not CURRENT but the observer answered for it, the hook rewrites
190
+ the command to `redue run CHECK` and allows it, keeping any `2>&1` and
191
+ `| tail`/`| head` suffix. It adds `--config FILE` when the config is not
192
+ `redue.config.json`. The run is recorded, so the next identical command can be
193
+ skipped. Without a healthy answer (timeout, error, no observer) the command runs
194
+ as typed. Claude Code still applies deny and ask rules to the rewritten command.
195
+ A chain is never rewritten: the rewrite is allowed without a prompt, and that
196
+ would also skip the prompt for the rest of the chain.
197
+
198
+ Limits:
199
+
200
+ - The hook judges its own environment, which Claude Code passes to it. The Bash
201
+ tool can add variables from your shell profile. The hook cannot see those.
202
+ - Commands run from a session that started in a subdirectory, after a `cd`
203
+ outside the project, or combined with `||`, `&` or other pipes, are not
204
+ matched. After a `cd` into any other directory than the root or a checked
205
+ package's, nothing matches.
206
+ - A skip writes nothing. If a typecheck command also emits files, later
207
+ commands see the files from its last run.
208
+ - Only the Bash tool is covered, not PowerShell.
209
+ - Run setup again after you rename a check or script.
210
+ - The rewrite is allowed without a permission prompt, even where the original
211
+ command would have prompted.
212
+
213
+ ## Update an existing connection
214
+
215
+ Installing a newer package does **not** rewrite project instructions. From the
216
+ same project and installation, stop every observer using that installation before
217
+ replacing it. Keep the original config and state selection; do not create a second
218
+ config or delete receipts. Example for a default npm installation/config:
219
+
220
+ ```sh
221
+ redue --config redue.config.json stop
222
+ npm install --global @redue/cli@alpha
223
+ redue --config redue.config.json agent setup codex --dry-run
224
+ redue --config redue.config.json agent setup codex --apply
225
+ redue --config redue.config.json start
226
+ redue --config redue.config.json status --sync --json
227
+ ```
228
+
229
+ Use the **same `--prefix`** as the existing npm installation when it has a custom
230
+ prefix, and invoke its corresponding `redue` binary. Keep your actual config path
231
+ on every command. For Claude, select `claude` in both setup commands. Preserve any
232
+ existing `--state-dir` on lifecycle/status commands; setup does not embed custom
233
+ state locations, so retain the documented generic instruction path if your agent
234
+ workflow needs an explicit custom state. PowerShell may use the existing
235
+ `npm.cmd`/`redue.cmd` shims without changing script policy.
236
+
237
+ Review the preview before applying. Intact owned content updates; unrelated text
238
+ is preserved. Edited managed content is refused, not overwritten. If refused,
239
+ review/reconcile those edits deliberately; do not remove ownership records to force
240
+ an update. Restart the observer with its original selection even if you postpone
241
+ updating instructions, then start a **fresh agent session** after a successful
242
+ update. Setup creates no verification receipt.
243
+
244
+ Managed project metadata can itself be an observed input. Prior receipts remain
245
+ historical evidence, but setup may make them STALE or UNVERIFIED. Reassess normally
246
+ and run required checks; an upgrade is not a promise that existing receipts remain
247
+ CURRENT. Do not suppress that invalidation or reset state.
248
+
249
+ Codex gets a short managed section in project `AGENTS.md` that points to
250
+ `.agents/skills/redue-verification/SKILL.md`. Claude Code gets one in `CLAUDE.md`
251
+ that names the typecheck command the hook matches and says what a skip means,
252
+ plus `.claude/skills/redue-verification/SKILL.md`. The skill holds the reuse
253
+ rules and the exact commands for the selected config. When the hook matches a
254
+ typecheck, the `CLAUDE.md` section does not point to the skill: the hook does
255
+ the work, and the skill is there for agents that look for it. Small
256
+ ownership records in `.redue/agents/` support safe updates/removal. These are
257
+ portable project files, not receipts; review and commit them if the team wants
258
+ this integration. Do not ignore just the ownership records while committing the
259
+ managed files.
260
+
261
+ Existing instruction text is retained. Review it in the preview: setup cannot
262
+ prove arbitrary natural-language policies are consistent. Conflicts such as a
263
+ root `AGENTS.override.md` or an alternative `.claude/CLAUDE.md` are reported
264
+ instead of silently outranked. Global/managed policies, nested instructions,
265
+ Codex instruction-size limits, skill disabling, and host-specific exclusions
266
+ still apply. Complete the host's ordinary trust/permission prompts yourself;
267
+ REDUE never grants tool permission. Sandboxed hosts may need owner-approved access
268
+ to the checkout, owned state directory and local observer socket. A healthy daemon
269
+ does not establish that the agent can reach it; doctor reports control access
270
+ separately. Do not disable sandbox protections to make this work. Do not use a mode that disables project
271
+ instructions and expect automatic activation.
272
+
273
+ Control access is not simply file-read permission. The observer can reconcile and
274
+ write its owned index, run the trusted configuration's probes in its own process
275
+ context, reload receipts, and stop. Approve only the intended checkout/state and
276
+ endpoint, accounting for that authority. Doctor sends only a bounded metrics
277
+ request; it does not synchronize or run these probes.
278
+
279
+ `agent doctor [codex|claude] --json` is read-only. It distinguishes command lookup,
280
+ config resolution, cached observer health, a bounded read-only control-access probe,
281
+ managed-file integrity, detected host
282
+ version, and loading guidance. `behavior_verified: false` is deliberate: intact
283
+ files do not prove the agent followed them. For Claude, doctor reports whether the
284
+ typecheck hook is installed. Doctor neither
285
+ executes checks nor starts observers, reconciles inputs, or installs a host.
286
+
287
+ Doctor separates missing/unreadable state, a missing or refused endpoint, an
288
+ explicit EPERM/EACCES access denial, and timeout/invalid response. A denial does
289
+ not identify whether OS permissions or host policy caused it. A live PID and
290
+ healthy cached observation do not prove control access. An older cached response
291
+ without receipt-selection validation gets stop/start guidance. Windows command
292
+ shims whose target has not been established are reported as unknown, not a
293
+ proven installation mismatch.
294
+
295
+ Codex CLI 0.160.1 on macOS can use the approved exact observer-socket route while
296
+ other sockets and direct network access remain denied. Its independent sessions
297
+ receive different proxy values. Ordinary npm invocation is **not** equivalent
298
+ across arbitrary notifier state: REDUE withholds automatic npm-launcher
299
+ reuse. Do not change proxy settings or permissions to get green evidence.
300
+
301
+ The separate opt-in [direct local compiler recipe](direct-typescript.md) does not
302
+ run npm. Its reviewed compiler implementation does not consume npm/proxy settings;
303
+ a digest preserves their observed provenance without treating them as compiler
304
+ inputs. Other execution context remains strict, and cached status still cannot
305
+ assert caller eligibility. An explicit user request for `npm run typecheck` still
306
+ requires npm execution; direct compiler evidence is not a substitute.
307
+
308
+ Before model trials, run `redue agent doctor --json` and
309
+ `redue status --sync --json` inside the agent's actual command boundary. The
310
+ contributor helper `test/acceptance/codex-preflight.mjs --config FILE --check CHECK`
311
+ performs the same bounded, read-only decision check and exits 2 when reuse is not
312
+ eligible. It neither executes verification nor grants access; synchronization
313
+ may run configured probes. A successful outside-shell result is insufficient.
314
+
315
+ Use the same setup command after an upgrade; it updates intact managed
316
+ content idempotently. Changed skill text or a changed managed block causes a
317
+ conflict instead of an overwrite. Review your edits before retrying.
318
+
319
+ ```sh
320
+ redue agent remove codex --dry-run
321
+ redue agent remove codex --apply
322
+ redue agent remove claude --apply
323
+ ```
324
+
325
+ Removal deletes only intact REDUE-owned content for that host. Unrelated text,
326
+ other integrations, project config, receipts and installed dependencies remain.
327
+ User edits outside the managed section survive. Modified managed content is left
328
+ intact with a diagnostic; compare it with a preview and resolve manually. Empty
329
+ parent directories may remain. If the selected config has been deleted, restore
330
+ it or manually remove only the marked REDUE section, that host's skill, and its
331
+ `.redue/agents/HOST.json` ownership record after review. Do not delete an entire
332
+ instruction file containing user content.
333
+
334
+ ## Project identity and generic agents
335
+
336
+ Commands from nested directories search toward the nearest Git root. If more than
337
+ one configuration applies, select one with `--config FILE`; REDUE refuses to guess.
338
+ The generated skill names its project-relative configuration and gives the exact
339
+ status and run commands for it. External configs or custom machine-local `--state-dir`
340
+ setups should use a reviewed generic instruction instead of committing absolute
341
+ paths. Other worktrees and remote containers have separate local evidence.
342
+
343
+ For another agent, put a short instruction in its documented project mechanism:
344
+ “Before deciding whether configured verification needs repeating, read REDUE's
345
+ agent policy, identify the selected recipe and use its decision query for the intended config.
346
+ Apply the schema/health/reuse rules.” Supply this document and the
347
+ [JSON contract](json.md) as the detailed policy. Review the agent's actual tool
348
+ trace before calling activation verified. A local npm installation does not install
349
+ REDUE in a remote container; that environment needs its own CLI, checkout,
350
+ dependencies and state. There is no cloud/team receipt synchronization.
@@ -1,7 +1,7 @@
1
1
  # Configuration
2
2
 
3
- Prefer `redue init` over hand-authoring a qualified contract. A typical generated
4
- npm configuration is concise and portable:
3
+ Prefer `redue init` over hand-authoring a contract. An ordinary generated npm script (recording-only in this candidate)
4
+ configuration is concise and portable:
5
5
 
6
6
  ```json
7
7
  {
@@ -28,6 +28,11 @@ Use `--config FILE` to select an external configuration. `root` is relative to
28
28
  that file. Runtime paths, resolved executables, local evidence, and sockets stay
29
29
  out of version-controlled configuration.
30
30
 
31
+ For the explicit direct compiler choice and generated exact argv, see
32
+ [direct TypeScript](direct-typescript.md). Existing script receipts cannot satisfy it.
33
+ A general check (`"qualification": "node-script-v1"`) has a `script` and no
34
+ `command`; see the [general recipe](node-script.md).
35
+
31
36
  ## Arbitrary commands
32
37
 
33
38
  An unrecognized ecosystem can still record ordinary execution:
@@ -53,5 +58,26 @@ Advanced explicit contracts may declare `generatedInputs`, `installedInputs`, na
53
58
  reviewed escape hatches, not onboarding requirements. A coverage rationale cannot
54
59
  override unsupported storage, unresolved links, missing inputs, or observation failure.
55
60
 
61
+ A chained typecheck script gets one generated check per `tsc` run, all with
62
+ the script's name (see [script forms](direct-typescript.md#script-forms)). A
63
+ proposed check for a project without a typecheck script has no `script`.
64
+
65
+ Input patterns are relative to the project root. They cannot name a `.git`
66
+ directory, because REDUE does not observe one; `!.git/**` is fine.
67
+
56
68
  Changing commands, relevant configuration, installed material, or consumed inputs
57
69
  invalidates prior applicability. It does not erase historical execution outcomes.
70
+
71
+ Installed inputs (under `node_modules` or other installed roots) are observed by
72
+ file identity: inode, size, mode, link count, and modification and change times.
73
+ REDUE does not read every installed file, so large installations become ready
74
+ quickly. Any write to an installed file makes dependent checks STALE until they
75
+ run again, even when it restores earlier bytes, reinstalls identical packages
76
+ (`npm ci`), copies the installation, or remounts it under another device. Timestamps tick in milliseconds, so a file
77
+ changed in the last 2 seconds could be rewritten at the same size without a new
78
+ identity; `redue run` waits until such files are 2 seconds old before it records
79
+ a checkpoint, which adds up to 2 seconds right after an install. Source files are
80
+ content-hashed, and the direct TypeScript recipe's probe content-checks every file
81
+ the compiler reads. The 2-second window assumes the filesystem clock matches this
82
+ machine's; on a network or VM-shared mount whose clock runs behind, keep the
83
+ installation on a local disk.
@@ -0,0 +1,219 @@
1
+ # Explicit local TypeScript verification
2
+
3
+ This check means: the reviewed local TypeScript compiler completed the configured
4
+ check against declared, observed inputs and relevant execution context. It does
5
+ not mean npm or npm lifecycle scripts completed.
6
+
7
+ For a supported single-package npm project with a typecheck script of `tsc`
8
+ runs (see [script forms](#script-forms)) or no typecheck script and a root
9
+ `tsconfig.json`, installed dependencies, Node 22/24 and TypeScript 5.x or 6.0
10
+ (see [compiler identity](#compiler-identity)). TypeScript 7 is a native
11
+ compiler this recipe cannot run: `init` refuses it
12
+ (`direct-typescript-version-unsupported`):
13
+
14
+ ```sh
15
+ redue init --recipe typescript-direct --check typecheck --dry-run
16
+ redue init --recipe typescript-direct --check typecheck
17
+ redue start
18
+ redue run typecheck
19
+ redue status --sync
20
+ ```
21
+
22
+ The preview shows the discovered script and recorded direct invocation. Nothing
23
+ executes during init. package.json, environment and dependencies remain unchanged.
24
+ A generated check contains:
25
+
26
+ ```json
27
+ {
28
+ "name": "typecheck",
29
+ "script": "typecheck",
30
+ "kind": "typecheck",
31
+ "command": ["@node", "@typescript-compiler:.", "--noEmit"],
32
+ "cwd": ".",
33
+ "qualification": "npm-typescript-direct-v1",
34
+ "inputs": ["package.json", "package-lock.json", "tsconfig.json", "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json,jsonc}", "!node_modules/**", "!.git/**"]
35
+ }
36
+ ```
37
+
38
+ `script` identifies the reviewed source recipe; `command` is what actually runs:
39
+ the resolved Node executable and local TypeScript implementation, with exact argv
40
+ and no shell. The entry is `lib/_tsc.js` where the package has one (5.7 and
41
+ later), without its outer compile-cache-enabling shim, and `lib/tsc.js`
42
+ otherwise. No compiler is fetched or bundled.
43
+
44
+ ## Compiler identity
45
+
46
+ The entire installed `node_modules/typescript` must be an official package,
47
+ byte for byte, in one of two ways:
48
+
49
+ - TypeScript 5.5.2, 5.6.3, 5.9.3, 6.0.2 or 6.0.3: its files match the digest
50
+ REDUE ships for that release.
51
+ - Any other TypeScript 5.x or 6.0 release: package-lock.json records the
52
+ registry's `typescript` package at the installed version (no alias, an
53
+ `https` tarball URL, not a file or git source) with an integrity (sha512,
54
+ or sha1 where a registry records only sha1), npm's cache holds the tarball
55
+ under that integrity, and the installed files are exactly the tarball's
56
+ files. REDUE reads the cache only; it never downloads. The cache is the one
57
+ npm uses: `npm_config_cache`, else `cache` in the project's `.npmrc`, then
58
+ the user's, else `~/.npm` (`%LocalAppData%\npm-cache` on Windows); the
59
+ global npmrc is not read. `npm-shrinkwrap.json` is not read on this path.
60
+ `npm ci` fills the cache. When the tarball is missing the check stays
61
+ recording-only with the reason `npm-tarball-uncached`; `npm cache add
62
+ typescript@VERSION` adds it. The check's compiler identity is then the
63
+ lockfile integrity, so a lockfile change re-probes.
64
+
65
+ CI runs the same contract suite against the last release of each minor from
66
+ 5.0 to 5.8 that the reviewed releases do not cover. Later minors (6.1 and up)
67
+ wait until CI covers them. TypeScript 7 (the native compiler) is not
68
+ supported.
69
+
70
+ ## Script forms
71
+
72
+ A typecheck script qualifies when it is one or more `tsc` runs joined by `&&`,
73
+ each with `--noEmit` and only these arguments, in any order: `-p`/`--project`
74
+ with a config file or directory inside the project, `--skipLibCheck`, and
75
+ `--pretty` (optionally `true` or `false`). For example
76
+ `tsc -p tsconfig.app.json --noEmit` or
77
+ `tsc --noEmit && tsc --noEmit -p tsconfig.node.json`. `tsc -b`, `--watch`,
78
+ other options, quotes, variables and other commands keep the script
79
+ recording-only.
80
+
81
+ A chain gets one check per run, named `typecheck.1`, `typecheck.2` and so on,
82
+ each with the script's name and that run's arguments in its command. Each run
83
+ is checked as its own program against its own config, and is reused only while
84
+ the script still has as many runs as the config has checks for it, one of them
85
+ with exactly those arguments. Adding or removing a run, or a pre- or
86
+ post-script, makes every check of the script not reusable until `init` runs
87
+ again. The script as a whole
88
+ (`npm run typecheck`) is skipped only when its current runs and the configured
89
+ checks correspond one to one and all are CURRENT (see [agents](agents.md)).
90
+
91
+ With no typecheck script and a root `tsconfig.json`, init proposes a
92
+ `tsc --noEmit` check with no `script` field, unless a script already runs a
93
+ TypeScript checker in another form (`tsc -b`, `vue-tsc`, `svelte-check`,
94
+ `tsgo`, `astro check`, `nuxi typecheck`). package.json is not changed. The
95
+ check is written only when the contract holds; otherwise no typecheck check is
96
+ added. The pnpm contract does the same for each workspace package with a
97
+ `tsconfig.json` and no typecheck script.
98
+
99
+ Existing configs are never overwritten. To compare choices, use a new project-local
100
+ `--config redue.direct.config.json` with init; this explicitly selects separate
101
+ state. To replace an existing check deliberately, preview JSON, stop its observer,
102
+ review/edit that check's config, and restart using the same config/state. Existing
103
+ npm receipts remain historical; the new command/interpretation needs a fresh run.
104
+ Do not delete receipts. `redue run` always executes the configured command.
105
+
106
+ ## Existing npm configuration: deliberate replacement
107
+
108
+ First upgrade through the [alpha.4 containment](npm-launcher-notice.md), stopping
109
+ observers before the installation change and restarting with the same config/state.
110
+ The old npm check becomes recording-only; its receipts remain historical.
111
+ To opt into the direct recipe afterward:
112
+
113
+ 1. Stop the observer, install the selected released version into the same prefix,
114
+ and keep the original `redue.config.json` and any explicit `--state-dir` selection.
115
+ 2. Run `redue init --recipe typescript-direct --check typecheck --dry-run --json`
116
+ using that config selection. Inspect `proposed_config.checks` and the recorded
117
+ invocation. This does not write anything, even when the config already exists.
118
+ 3. In your editor, replace only the intended check object with the reviewed proposed
119
+ object. Preserve its name, the top-level project configuration, and every other
120
+ check. Do not replace the whole config with a one-check preview. Keep a local
121
+ backup outside observed inputs if desired.
122
+ 4. Run `redue start` with the same config/state. `redue status --sync --json` must
123
+ not treat the old npm receipt as eligible compiler evidence.
124
+ 5. Run `redue run typecheck`, then `redue status --sync --json`. A qualified success
125
+ now records the direct compiler recipe with a new run ID. Old npm runs remain
126
+ immutable history. Other check definitions are unchanged.
127
+
128
+ Substitute the actual selected check name throughout. Repeating plain `init`
129
+ does **not** migrate an existing config. A deliberately separate `--config` file
130
+ is useful for comparison, but has separate state by design. Do not create one
131
+ accidentally when intending to preserve the original selection.
132
+
133
+ Pre/post scripts, compound commands, wrappers, environment assignments, workspace
134
+ projects and unsupported compiler versions are not automatically converted.
135
+ Init retains the original script with a reason. Development-mode source-map helpers,
136
+ Node preloads/loaders/compile-cache settings, `TS_ETW_MODULE_PATH` (including empty or case aliases), unsupported compiler plugins, a
137
+ `composite` root tsconfig, a program that uses a referenced project's files,
138
+ outside-root inputs and uncertain observation withhold applicability. Extra custom probes cannot inherit this recipe's context
139
+ exception. Relevant source, declaration, config, membership and installed-content
140
+ changes invalidate or withdraw applicability normally. Installed files are observed
141
+ by identity, so reinstalling identical packages or restoring an installed file's
142
+ bytes also needs one rerun (see [configuration](configuration.md)).
143
+
144
+ Vitest writes its results under `node_modules/.vite/vitest` at every run.
145
+ They are not inputs, so a test run leaves the typecheck CURRENT. Everything
146
+ else under `node_modules/.vite` is still an input. A program that asks about
147
+ anything under `node_modules/.vite` (by any spelling or through a link that
148
+ resolves there), or lists `node_modules`, is UNVERIFIED: REDUE does not
149
+ observe what Vitest writes there. A check configured before 0.1.0-alpha.25 gets the new inputs on
150
+ its own and reports STALE once after the upgrade.
151
+
152
+ A root tsconfig with `incremental: true` is supported. tsc reads and writes
153
+ its build-info file (`tsBuildInfoFile`, or the default next to the config) on
154
+ each run, so REDUE leaves that file out of the inputs and lets the run write
155
+ only that file and the directories it needs; any other write makes the run
156
+ non-reusable. The result is what your own incremental tsc reports, so it
157
+ trusts TypeScript's build-info cache, which TypeScript discards after a
158
+ compiler or option change. The file must be inside the checkout and named
159
+ `*.tsbuildinfo`, with no glob characters in its path.
160
+ `assumeChangesOnlyAffectDirectDependencies` is refused: with it, the result
161
+ depends on earlier runs. REDUE reads the setting when the observer starts:
162
+ after turning `incremental` on or moving the file, restart the observer;
163
+ status says so until then. On Linux, a run that creates the build-info directory is an
164
+ observation gap, so the first run after that is not reusable.
165
+
166
+ A root tsconfig may reference other configs (`references`), for example a
167
+ composite `tsconfig.node.json`. Plain `tsc --noEmit` reads those configs but
168
+ does not build them, so REDUE treats them as configuration. If the program
169
+ uses a referenced project's sources or built outputs, the check is not
170
+ qualified.
171
+
172
+ On macOS and Linux, `redue run` records which files the compiler looked up and
173
+ compares them with what the observer's last probe saw. The probe only builds the
174
+ program. With `declaration: true`, tsc also resolves the project's dependencies
175
+ while it checks declarations, so the run looks up files the probe never did,
176
+ some outside the checkout, and reads those dependencies' `package.json`. The
177
+ receipt keeps the run's answers to those existence, `realpath` and
178
+ `package.json` lookups as run facts. Before every CURRENT answer, status asks
179
+ each one again; a cached `redue status` asks them again when it is read. If any
180
+ now answers differently, the check is STALE and the reason names the path. Any
181
+ other file the run read, or a directory it listed, that the probe never did
182
+ still makes the run non-reusable, as do more than 10,000 run facts. Receipts
183
+ with run facts use a new format, so earlier observers do not reuse them. A
184
+ direct receipt recorded before run facts is UNVERIFIED until the check runs
185
+ again. Windows does not record direct runs, so it has no run facts: there, a
186
+ lookup only declaration checks make is not checked again.
187
+
188
+ The versioned `npm-direct-typescript@1` interpretation retains relevant Node context
189
+ and identity. Reviewed compiler code does not parse npm settings or proxy variables;
190
+ these remain untouched in the child environment and are recorded only as a digest
191
+ of observed provenance. This is not an environment ignore option for arbitrary
192
+ commands or other providers. No remote service equivalence is claimed. Ordinary
193
+ cached status remains conservative; synchronize deliberately when worth the cost.
194
+
195
+ Explain/JSON report `verification_recipe: "npm-direct-typescript@1"` for receipts
196
+ recorded with this recipe. Report compiler evidence as compiler evidence. A user's
197
+ explicit request for `npm run typecheck` is not satisfied by this different command.
198
+
199
+ The injected `NODE_USE_ENV_PROXY=1` setting is admitted only on Node 22.13.0,
200
+ where it is inert; it remains strictly tracked. Other Node versions with this
201
+ setting need review and stay unqualified. REDUE does not alter the setting.
202
+
203
+ ## Node settings
204
+
205
+ Since alpha.11 the direct recipe accepts these `NODE_*` settings:
206
+
207
+ - `NODE_OPTIONS`, when every token is one of `--max-old-space-size=<n>`,
208
+ `--max-semi-space-size=<n>`, `--use-openssl-ca`, `--use-bundled-ca`,
209
+ `--use-system-ca` or `--dns-result-order=ipv4first|ipv6first|verbatim`.
210
+ Any other flag, quotes, backslashes or tabs are refused.
211
+ - `NODE_EXTRA_CA_CERTS`.
212
+ - `NODE_PATH`.
213
+
214
+ `NODE_ENV` set to `production`, `test` or empty was already accepted. Every other non-empty
215
+ `NODE_*` setting withholds applicability. The values are part of the recorded
216
+ execution context: a run under one value is not reusable under another. A
217
+ `--require` in `NODE_OPTIONS` still runs inside REDUE's own process before REDUE
218
+ refuses it. The npm, pnpm and Yarn recipes still refuse `NODE_OPTIONS` and
219
+ `NODE_PATH`.