@redue/cli 0.1.0-alpha.2 → 0.1.0-alpha.21

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 (60) hide show
  1. package/CHANGELOG.md +491 -0
  2. package/README.md +107 -2
  3. package/bin/redue.mjs +132 -50
  4. package/docs/README.md +2 -1
  5. package/docs/user/agents.md +299 -15
  6. package/docs/user/configuration.md +28 -2
  7. package/docs/user/direct-typescript.md +209 -0
  8. package/docs/user/getting-started.md +23 -2
  9. package/docs/user/json.md +2 -0
  10. package/docs/user/node-script.md +154 -0
  11. package/docs/user/npm-launcher-notice.md +42 -0
  12. package/docs/user/pilot.md +146 -0
  13. package/docs/user/receipt-selection-notice.md +60 -0
  14. package/docs/user/supported-projects.md +56 -23
  15. package/docs/user/tests-direct.md +132 -0
  16. package/package.json +4 -3
  17. package/src/agent-integration.mjs +388 -0
  18. package/src/agent-policy.md +28 -0
  19. package/src/cached-state.mjs +46 -8
  20. package/src/claude-hook.mjs +449 -0
  21. package/src/cli.mjs +263 -40
  22. package/src/daemon.mjs +433 -94
  23. package/src/decision-profile.mjs +15 -1
  24. package/src/decision-validation.mjs +10 -0
  25. package/src/declared-plan.mjs +29 -6
  26. package/src/direct-run-certificate.mjs +252 -0
  27. package/src/direct-typescript-probe.mjs +24 -0
  28. package/src/direct-typescript.mjs +185 -0
  29. package/src/glob.mjs +8 -0
  30. package/src/history-worker.mjs +21 -13
  31. package/src/index.mjs +72 -19
  32. package/src/installed-inputs.mjs +7 -1
  33. package/src/linux-inotify.py +39 -10
  34. package/src/node-onboarding.mjs +172 -53
  35. package/src/node-script.mjs +364 -0
  36. package/src/npm-integrity.mjs +124 -0
  37. package/src/npm-typecheck-environment.mjs +36 -0
  38. package/src/npmrc.mjs +16 -0
  39. package/src/observation.mjs +34 -12
  40. package/src/path-identity.mjs +8 -0
  41. package/src/plan-worker.mjs +17 -17
  42. package/src/pnpm-inputs.mjs +114 -54
  43. package/src/pnpm-shim-templates.json +180 -0
  44. package/src/pnpm-shims.mjs +54 -0
  45. package/src/pnpm-typecheck-probe.mjs +11 -6
  46. package/src/presentation.mjs +9 -1
  47. package/src/probe-deadline.mjs +37 -0
  48. package/src/probe-result.mjs +7 -3
  49. package/src/project-location.mjs +34 -0
  50. package/src/run-recorder.cjs +91 -0
  51. package/src/state-store.mjs +37 -1
  52. package/src/test-direct.mjs +560 -0
  53. package/src/test-recorder.cjs +406 -0
  54. package/src/typescript-contract-probe.mjs +4 -187
  55. package/src/typescript-input-facts.mjs +92 -0
  56. package/src/typescript-invocation.mjs +92 -0
  57. package/src/typescript-list.mjs +108 -13
  58. package/src/typescript-qualification.mjs +29 -49
  59. package/src/workspace-manifests.mjs +24 -0
  60. 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, query ordinary `status --json` first and decide whether
16
+ synchronization is worthwhile. Ordinary status 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,283 @@ 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` also adds a PreToolUse hook and a
78
+ SessionStart hook to `.claude/settings.local.json`. Both run
79
+ `redue agent hook claude`, which needs a local REDUE install, so they are
80
+ per-developer; keep that file out of commits. Other settings in the file are kept,
81
+ but the file is rewritten as 2-space JSON. `.claude/settings.json` is not touched.
82
+ `redue agent remove claude --apply` removes only the entries REDUE added.
83
+
84
+ When a session starts, resumes, clears or compacts, the SessionStart hook starts
85
+ this project's observer if none is running. It launches `redue start` in the
86
+ background and returns at once, and prints nothing, so it adds nothing to the
87
+ agent's context. Until the observer's first index is done, checks are
88
+ UNVERIFIED and run as typed. An observer you stopped with `redue stop` starts
89
+ again with the next session; remove the hook to prevent that. Setups from
90
+ alpha.15 or earlier get the hook by running `redue agent setup claude --apply`
91
+ again.
92
+
93
+ The hook skips an exact rerun of a configured typecheck (a check with
94
+ `kind: "typecheck"` or named `typecheck`) or direct test check. It matches
95
+ these commands, run from the project root:
96
+
97
+ - `redue run CHECK`, or `redue --config FILE run CHECK` when the config is not
98
+ `redue.config.json`
99
+ - the check's script through the project's package manager: `npm run SCRIPT`
100
+ (and `npm test`), `pnpm SCRIPT`, `pnpm run SCRIPT`, `yarn SCRIPT` or
101
+ `yarn run SCRIPT`. The short form is left out when the script is named like
102
+ one of the package manager's own commands.
103
+ - the tool the check runs: `npx tsc ARGS` (and `pnpm exec tsc ARGS` with pnpm)
104
+ for a direct TypeScript check, or the runner's command, alone or after `npx`,
105
+ for a direct test check
106
+ - the check's `command`, when it has no `@` tokens
107
+ - for a workspace package's check: `pnpm --filter NAME SCRIPT` (also
108
+ `--filter=NAME`, `-F NAME`, and with `run`), `yarn workspace NAME SCRIPT`, or
109
+ `npm run SCRIPT -w NAME` (also `--workspace NAME`, `--workspace=NAME` and
110
+ `npm -w NAME run SCRIPT`). After `cd` into the package's directory, the
111
+ package-manager script forms and tool forms match that check.
112
+
113
+ A `turbo run TASK` (or `turbo TASK`, alone or after `npx` or `pnpm exec`) or,
114
+ in a pnpm project, `pnpm -r TASK` (`--recursive`, with or without `run`) that
115
+ runs a checked task in every workspace package is skipped only when every check
116
+ it would run is CURRENT, PASS and `reuse_eligible`. Every package with the
117
+ task's script must have a check. turbo must define the task, with `dependsOn`
118
+ listing at most `^TASK`, no `with`, no `PACKAGE#TASK` entries and no package
119
+ `turbo.json`; `pnpm -r` must not include the workspace root. A root script
120
+ whose text is such a command counts as that command, unless it has pre- or
121
+ post-scripts. In every other case the command runs as typed: turbo caches its
122
+ own results, so the hook never rewrites it. Filters (`--filter`) and nx are not
123
+ matched.
124
+
125
+ For a typecheck check that runs the compiler, the script's forms act only when
126
+ the script in package.json still has exactly the configured runs: one `tsc`
127
+ run per check with the same arguments, and no pre- or post-script. Otherwise
128
+ the command runs as typed. A script that chains `tsc` runs with `&&` has one
129
+ check per run, `typecheck.1`, `typecheck.2` and so on (see
130
+ [direct TypeScript](direct-typescript.md#script-forms)); each run's own
131
+ `npx tsc ...` form matches its check. The hook skips the script when all its
132
+ runs are CURRENT, PASS and `reuse_eligible`, and otherwise rewrites it to
133
+ `redue run` of the runs that are not, in the script's order, joined by `&&`.
134
+ In a turbo or `pnpm -r` fan-out, a package's script counts only the same way.
135
+
136
+ Each form may end with `2>&1` and then one `| tail -n N`, `| head -n N`,
137
+ `| tail -N` or `| head -N`. It may also be the first command of a `;` or `&&`
138
+ chain. Nothing else matches. Each form has its own `if` rule, so other Bash
139
+ commands never start the hook. The installed skill lists these exact commands,
140
+ so the agent uses forms the hook recognizes.
141
+
142
+ On a match, the hook runs `redue status --sync --json`. It waits up to half the
143
+ duration of the check's last completed run, at most 10 seconds, so waiting never
144
+ costs more than half a run. With no completed run it waits 2 seconds. A check
145
+ that takes a few hundred milliseconds is therefore rarely skipped; skipping it
146
+ would save almost nothing, and the hook does not rewrite it to `redue run`
147
+ either. Claude Code's own limit for the hook is 15 seconds.
148
+ It blocks the command only when the check is CURRENT, PASS and
149
+ `reuse_eligible: true`. The message names the check and the receipt's run ID. Every
150
+ other result allows the command: STALE, UNVERIFIED, FAILED, a timeout, an error, or
151
+ a missing `redue`. A command that starts with `REDUE_FORCE=1` always runs. A
152
+ blocked chain runs none of its commands; the message names the rest of the chain
153
+ so the agent can run it on its own.
154
+
155
+ When the check is not CURRENT but the observer answered for it, the hook rewrites
156
+ the command to `redue run CHECK` and allows it, keeping any `2>&1` and
157
+ `| tail`/`| head` suffix. It adds `--config FILE` when the config is not
158
+ `redue.config.json`. The run is recorded, so the next identical command can be
159
+ skipped. Without a healthy answer (timeout, error, no observer) the command runs
160
+ as typed. Claude Code still applies deny and ask rules to the rewritten command.
161
+ A chain is never rewritten: the rewrite is allowed without a prompt, and that
162
+ would also skip the prompt for the rest of the chain.
163
+
164
+ Limits:
165
+
166
+ - The hook judges its own environment, which Claude Code passes to it. The Bash
167
+ tool can add variables from your shell profile. The hook cannot see those.
168
+ - Commands run from a session that started in a subdirectory, after a `cd`
169
+ outside the project, or combined with `||`, `&` or other pipes, are not
170
+ matched. After a `cd` into any other directory than the root or a checked
171
+ package's, nothing matches.
172
+ - A skip writes nothing. If a typecheck command also emits files, later
173
+ commands see the files from its last run.
174
+ - Only the Bash tool is covered, not PowerShell.
175
+ - Run setup again after you rename a check or script.
176
+ - The rewrite is allowed without a permission prompt, even where the original
177
+ command would have prompted.
178
+
179
+ ## Update an existing connection
180
+
181
+ Installing a newer package does **not** rewrite project instructions. From the
182
+ same project and installation, stop every observer using that installation before
183
+ replacing it. Keep the original config and state selection; do not create a second
184
+ config or delete receipts. Example for a default npm installation/config:
185
+
186
+ ```sh
187
+ redue --config redue.config.json stop
188
+ npm install --global @redue/cli@alpha
189
+ redue --config redue.config.json agent setup codex --dry-run
190
+ redue --config redue.config.json agent setup codex --apply
191
+ redue --config redue.config.json start
192
+ redue --config redue.config.json status --sync --json
193
+ ```
194
+
195
+ Use the **same `--prefix`** as the existing npm installation when it has a custom
196
+ prefix, and invoke its corresponding `redue` binary. Keep your actual config path
197
+ on every command. For Claude, select `claude` in both setup commands. Preserve any
198
+ existing `--state-dir` on lifecycle/status commands; setup does not embed custom
199
+ state locations, so retain the documented generic instruction path if your agent
200
+ workflow needs an explicit custom state. PowerShell may use the existing
201
+ `npm.cmd`/`redue.cmd` shims without changing script policy.
202
+
203
+ Review the preview before applying. Intact owned content updates; unrelated text
204
+ is preserved. Edited managed content is refused, not overwritten. If refused,
205
+ review/reconcile those edits deliberately; do not remove ownership records to force
206
+ an update. Restart the observer with its original selection even if you postpone
207
+ updating instructions, then start a **fresh agent session** after a successful
208
+ update. Setup creates no verification receipt.
209
+
210
+ Managed project metadata can itself be an observed input. Prior receipts remain
211
+ historical evidence, but setup may make them STALE or UNVERIFIED. Reassess normally
212
+ and run required checks; an upgrade is not a promise that existing receipts remain
213
+ CURRENT. Do not suppress that invalidation or reset state.
214
+
215
+ Codex gets a short managed section in project `AGENTS.md` that points to
216
+ `.agents/skills/redue-verification/SKILL.md`. Claude Code gets one in `CLAUDE.md`
217
+ that names the typecheck command the hook matches and says what a skip means,
218
+ plus `.claude/skills/redue-verification/SKILL.md`. The skill holds the reuse
219
+ rules and the exact commands for the selected config. When the hook matches a
220
+ typecheck, the `CLAUDE.md` section does not point to the skill: the hook does
221
+ the work, and the skill is there for agents that look for it. Small
222
+ ownership records in `.redue/agents/` support safe updates/removal. These are
223
+ portable project files, not receipts; review and commit them if the team wants
224
+ this integration. Do not ignore just the ownership records while committing the
225
+ managed files.
226
+
227
+ Existing instruction text is retained. Review it in the preview: setup cannot
228
+ prove arbitrary natural-language policies are consistent. Conflicts such as a
229
+ root `AGENTS.override.md` or an alternative `.claude/CLAUDE.md` are reported
230
+ instead of silently outranked. Global/managed policies, nested instructions,
231
+ Codex instruction-size limits, skill disabling, and host-specific exclusions
232
+ still apply. Complete the host's ordinary trust/permission prompts yourself;
233
+ REDUE never grants tool permission. Sandboxed hosts may need owner-approved access
234
+ to the checkout, owned state directory and local observer socket. A healthy daemon
235
+ does not establish that the agent can reach it; doctor reports control access
236
+ separately. Do not disable sandbox protections to make this work. Do not use a mode that disables project
237
+ instructions and expect automatic activation.
238
+
239
+ Control access is not simply file-read permission. The observer can reconcile and
240
+ write its owned index, run the trusted configuration's probes in its own process
241
+ context, reload receipts, and stop. Approve only the intended checkout/state and
242
+ endpoint, accounting for that authority. Doctor sends only a bounded metrics
243
+ request; it does not synchronize or run these probes.
244
+
245
+ `agent doctor [codex|claude] --json` is read-only. It distinguishes command lookup,
246
+ config resolution, cached observer health, a bounded read-only control-access probe,
247
+ managed-file integrity, detected host
248
+ version, and loading guidance. `behavior_verified: false` is deliberate: intact
249
+ files do not prove the agent followed them. For Claude, doctor reports whether the
250
+ typecheck hook is installed. Doctor neither
251
+ executes checks nor starts observers, reconciles inputs, or installs a host.
252
+
253
+ Doctor separates missing/unreadable state, a missing or refused endpoint, an
254
+ explicit EPERM/EACCES access denial, and timeout/invalid response. A denial does
255
+ not identify whether OS permissions or host policy caused it. A live PID and
256
+ healthy cached observation do not prove control access. An older cached response
257
+ without receipt-selection validation gets stop/start guidance. Windows command
258
+ shims whose target has not been established are reported as unknown, not a
259
+ proven installation mismatch.
260
+
261
+ Codex CLI 0.160.1 on macOS can use the approved exact observer-socket route while
262
+ other sockets and direct network access remain denied. Its independent sessions
263
+ receive different proxy values. Ordinary npm invocation is **not** equivalent
264
+ across arbitrary notifier state: REDUE withholds automatic npm-launcher
265
+ reuse. Do not change proxy settings or permissions to get green evidence.
266
+
267
+ The separate opt-in [direct local compiler recipe](direct-typescript.md) does not
268
+ run npm. Its reviewed compiler implementation does not consume npm/proxy settings;
269
+ a digest preserves their observed provenance without treating them as compiler
270
+ inputs. Other execution context remains strict, and cached status still cannot
271
+ assert caller eligibility. An explicit user request for `npm run typecheck` still
272
+ requires npm execution; direct compiler evidence is not a substitute.
273
+
274
+ Before model trials, run `redue agent doctor --json` and
275
+ `redue status --sync --json` inside the agent's actual command boundary. The
276
+ contributor helper `test/acceptance/codex-preflight.mjs --config FILE --check CHECK`
277
+ performs the same bounded, read-only decision check and exits 2 when reuse is not
278
+ eligible. It neither executes verification nor grants access; synchronization
279
+ may run configured probes. A successful outside-shell result is insufficient.
280
+
281
+ Use the same setup command after an upgrade; it updates intact managed
282
+ content idempotently. Changed skill text or a changed managed block causes a
283
+ conflict instead of an overwrite. Review your edits before retrying.
284
+
285
+ ```sh
286
+ redue agent remove codex --dry-run
287
+ redue agent remove codex --apply
288
+ redue agent remove claude --apply
289
+ ```
290
+
291
+ Removal deletes only intact REDUE-owned content for that host. Unrelated text,
292
+ other integrations, project config, receipts and installed dependencies remain.
293
+ User edits outside the managed section survive. Modified managed content is left
294
+ intact with a diagnostic; compare it with a preview and resolve manually. Empty
295
+ parent directories may remain. If the selected config has been deleted, restore
296
+ it or manually remove only the marked REDUE section, that host's skill, and its
297
+ `.redue/agents/HOST.json` ownership record after review. Do not delete an entire
298
+ instruction file containing user content.
299
+
300
+ ## Project identity and generic agents
301
+
302
+ Commands from nested directories search toward the nearest Git root. If more than
303
+ one configuration applies, select one with `--config FILE`; REDUE refuses to guess.
304
+ The generated skill names its project-relative configuration and gives the exact
305
+ status and run commands for it. External configs or custom machine-local `--state-dir`
306
+ setups should use a reviewed generic instruction instead of committing absolute
307
+ paths. Other worktrees and remote containers have separate local evidence.
308
+
309
+ For another agent, put a short instruction in its documented project mechanism:
310
+ “Before deciding whether configured verification needs repeating, read REDUE's
311
+ agent policy, identify the selected recipe and use its decision query for the intended config.
312
+ Apply the schema/health/reuse rules.” Supply this document and the
313
+ [JSON contract](json.md) as the detailed policy. Review the agent's actual tool
314
+ trace before calling activation verified. A local npm installation does not install
315
+ REDUE in a remote container; that environment needs its own CLI, checkout,
316
+ 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,209 @@
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)):
11
+
12
+ ```sh
13
+ redue init --recipe typescript-direct --check typecheck --dry-run
14
+ redue init --recipe typescript-direct --check typecheck
15
+ redue start
16
+ redue run typecheck
17
+ redue status --sync
18
+ ```
19
+
20
+ The preview shows the discovered script and recorded direct invocation. Nothing
21
+ executes during init. package.json, environment and dependencies remain unchanged.
22
+ A generated check contains:
23
+
24
+ ```json
25
+ {
26
+ "name": "typecheck",
27
+ "script": "typecheck",
28
+ "kind": "typecheck",
29
+ "command": ["@node", "@typescript-compiler:.", "--noEmit"],
30
+ "cwd": ".",
31
+ "qualification": "npm-typescript-direct-v1",
32
+ "inputs": ["package.json", "package-lock.json", "tsconfig.json", "**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs,json,jsonc}", "!node_modules/**", "!.git/**"]
33
+ }
34
+ ```
35
+
36
+ `script` identifies the reviewed source recipe; `command` is what actually runs:
37
+ the resolved Node executable and local TypeScript implementation, with exact argv
38
+ and no shell. The entry is `lib/_tsc.js` where the package has one (5.7 and
39
+ later), without its outer compile-cache-enabling shim, and `lib/tsc.js`
40
+ otherwise. No compiler is fetched or bundled.
41
+
42
+ ## Compiler identity
43
+
44
+ The entire installed `node_modules/typescript` must be an official package,
45
+ byte for byte, in one of two ways:
46
+
47
+ - TypeScript 5.5.2, 5.6.3, 5.9.3, 6.0.2 or 6.0.3: its files match the digest
48
+ REDUE ships for that release.
49
+ - Any other TypeScript 5.x or 6.0 release: package-lock.json records the
50
+ registry's `typescript` package at the installed version (no alias, an
51
+ `https` tarball URL, not a file or git source) with an integrity (sha512,
52
+ or sha1 where a registry records only sha1), npm's cache holds the tarball
53
+ under that integrity, and the installed files are exactly the tarball's
54
+ files. REDUE reads the cache only; it never downloads. The cache is the one
55
+ npm uses: `npm_config_cache`, else `cache` in the project's `.npmrc`, then
56
+ the user's, else `~/.npm` (`%LocalAppData%\npm-cache` on Windows); the
57
+ global npmrc is not read. `npm-shrinkwrap.json` is not read on this path.
58
+ `npm ci` fills the cache. When the tarball is missing the check stays
59
+ recording-only with the reason `npm-tarball-uncached`; `npm cache add
60
+ typescript@VERSION` adds it. The check's compiler identity is then the
61
+ lockfile integrity, so a lockfile change re-probes.
62
+
63
+ CI runs the same contract suite against the last release of each minor from
64
+ 5.0 to 5.8 that the reviewed releases do not cover. Later minors (6.1 and up)
65
+ wait until CI covers them. TypeScript 7 (the native compiler) is not
66
+ supported.
67
+
68
+ ## Script forms
69
+
70
+ A typecheck script qualifies when it is one or more `tsc` runs joined by `&&`,
71
+ each with `--noEmit` and only these arguments, in any order: `-p`/`--project`
72
+ with a config file or directory inside the project, `--skipLibCheck`, and
73
+ `--pretty` (optionally `true` or `false`). For example
74
+ `tsc -p tsconfig.app.json --noEmit` or
75
+ `tsc --noEmit && tsc --noEmit -p tsconfig.node.json`. `tsc -b`, `--watch`,
76
+ other options, quotes, variables and other commands keep the script
77
+ recording-only.
78
+
79
+ A chain gets one check per run, named `typecheck.1`, `typecheck.2` and so on,
80
+ each with the script's name and that run's arguments in its command. Each run
81
+ is checked as its own program against its own config, and is reused only while
82
+ the script still has as many runs as the config has checks for it, one of them
83
+ with exactly those arguments. Adding or removing a run, or a pre- or
84
+ post-script, makes every check of the script not reusable until `init` runs
85
+ again. The script as a whole
86
+ (`npm run typecheck`) is skipped only when its current runs and the configured
87
+ checks correspond one to one and all are CURRENT (see [agents](agents.md)).
88
+
89
+ With no typecheck script and a root `tsconfig.json`, init proposes a
90
+ `tsc --noEmit` check with no `script` field, unless a script already runs a
91
+ TypeScript checker in another form (`tsc -b`, `vue-tsc`, `svelte-check`,
92
+ `tsgo`, `astro check`, `nuxi typecheck`). package.json is not changed. The
93
+ check is written only when the contract holds; otherwise no typecheck check is
94
+ added. The pnpm contract does the same for each workspace package with a
95
+ `tsconfig.json` and no typecheck script.
96
+
97
+ Existing configs are never overwritten. To compare choices, use a new project-local
98
+ `--config redue.direct.config.json` with init; this explicitly selects separate
99
+ state. To replace an existing check deliberately, preview JSON, stop its observer,
100
+ review/edit that check's config, and restart using the same config/state. Existing
101
+ npm receipts remain historical; the new command/interpretation needs a fresh run.
102
+ Do not delete receipts. `redue run` always executes the configured command.
103
+
104
+ ## Existing npm configuration: deliberate replacement
105
+
106
+ First upgrade through the [alpha.4 containment](npm-launcher-notice.md), stopping
107
+ observers before the installation change and restarting with the same config/state.
108
+ The old npm check becomes recording-only; its receipts remain historical.
109
+ To opt into the direct recipe afterward:
110
+
111
+ 1. Stop the observer, install the selected released version into the same prefix,
112
+ and keep the original `redue.config.json` and any explicit `--state-dir` selection.
113
+ 2. Run `redue init --recipe typescript-direct --check typecheck --dry-run --json`
114
+ using that config selection. Inspect `proposed_config.checks` and the recorded
115
+ invocation. This does not write anything, even when the config already exists.
116
+ 3. In your editor, replace only the intended check object with the reviewed proposed
117
+ object. Preserve its name, the top-level project configuration, and every other
118
+ check. Do not replace the whole config with a one-check preview. Keep a local
119
+ backup outside observed inputs if desired.
120
+ 4. Run `redue start` with the same config/state. `redue status --sync --json` must
121
+ not treat the old npm receipt as eligible compiler evidence.
122
+ 5. Run `redue run typecheck`, then `redue status --sync --json`. A qualified success
123
+ now records the direct compiler recipe with a new run ID. Old npm runs remain
124
+ immutable history. Other check definitions are unchanged.
125
+
126
+ Substitute the actual selected check name throughout. Repeating plain `init`
127
+ does **not** migrate an existing config. A deliberately separate `--config` file
128
+ is useful for comparison, but has separate state by design. Do not create one
129
+ accidentally when intending to preserve the original selection.
130
+
131
+ Pre/post scripts, compound commands, wrappers, environment assignments, workspace
132
+ projects and unsupported compiler versions are not automatically converted.
133
+ Init retains the original script with a reason. Development-mode source-map helpers,
134
+ Node preloads/loaders/compile-cache settings, `TS_ETW_MODULE_PATH` (including empty or case aliases), unsupported compiler plugins, a
135
+ `composite` root tsconfig, a program that uses a referenced project's files,
136
+ outside-root inputs and uncertain observation withhold applicability. Extra custom probes cannot inherit this recipe's context
137
+ exception. Relevant source, declaration, config, membership and installed-content
138
+ changes invalidate or withdraw applicability normally. Installed files are observed
139
+ by identity, so reinstalling identical packages or restoring an installed file's
140
+ bytes also needs one rerun (see [configuration](configuration.md)).
141
+
142
+ A root tsconfig with `incremental: true` is supported. tsc reads and writes
143
+ its build-info file (`tsBuildInfoFile`, or the default next to the config) on
144
+ each run, so REDUE leaves that file out of the inputs and lets the run write
145
+ only that file and the directories it needs; any other write makes the run
146
+ non-reusable. The result is what your own incremental tsc reports, so it
147
+ trusts TypeScript's build-info cache, which TypeScript discards after a
148
+ compiler or option change. The file must be inside the checkout and named
149
+ `*.tsbuildinfo`, with no glob characters in its path.
150
+ `assumeChangesOnlyAffectDirectDependencies` is refused: with it, the result
151
+ depends on earlier runs. REDUE reads the setting when the observer starts:
152
+ after turning `incremental` on or moving the file, restart the observer;
153
+ status says so until then. On Linux, a run that creates the build-info directory is an
154
+ observation gap, so the first run after that is not reusable.
155
+
156
+ A root tsconfig may reference other configs (`references`), for example a
157
+ composite `tsconfig.node.json`. Plain `tsc --noEmit` reads those configs but
158
+ does not build them, so REDUE treats them as configuration. If the program
159
+ uses a referenced project's sources or built outputs, the check is not
160
+ qualified.
161
+
162
+ On macOS and Linux, `redue run` records which files the compiler looked up and
163
+ compares them with what the observer's last probe saw. The probe only builds the
164
+ program. With `declaration: true`, tsc also resolves the project's dependencies
165
+ while it checks declarations, so the run looks up files the probe never did,
166
+ some outside the checkout, and reads those dependencies' `package.json`. The
167
+ receipt keeps the run's answers to those existence, `realpath` and
168
+ `package.json` lookups as run facts. Before every CURRENT answer, status asks
169
+ each one again; a cached `redue status` asks them again when it is read. If any
170
+ now answers differently, the check is STALE and the reason names the path. Any
171
+ other file the run read, or a directory it listed, that the probe never did
172
+ still makes the run non-reusable, as do more than 10,000 run facts. Receipts
173
+ with run facts use a new format, so earlier observers do not reuse them. A
174
+ direct receipt recorded before run facts is UNVERIFIED until the check runs
175
+ again. Windows does not record direct runs, so it has no run facts: there, a
176
+ lookup only declaration checks make is not checked again.
177
+
178
+ The versioned `npm-direct-typescript@1` interpretation retains relevant Node context
179
+ and identity. Reviewed compiler code does not parse npm settings or proxy variables;
180
+ these remain untouched in the child environment and are recorded only as a digest
181
+ of observed provenance. This is not an environment ignore option for arbitrary
182
+ commands or other providers. No remote service equivalence is claimed. Ordinary
183
+ cached status remains conservative; synchronize deliberately when worth the cost.
184
+
185
+ Explain/JSON report `verification_recipe: "npm-direct-typescript@1"` for receipts
186
+ recorded with this recipe. Report compiler evidence as compiler evidence. A user's
187
+ explicit request for `npm run typecheck` is not satisfied by this different command.
188
+
189
+ The injected `NODE_USE_ENV_PROXY=1` setting is admitted only on Node 22.13.0,
190
+ where it is inert; it remains strictly tracked. Other Node versions with this
191
+ setting need review and stay unqualified. REDUE does not alter the setting.
192
+
193
+ ## Node settings
194
+
195
+ Since alpha.11 the direct recipe accepts these `NODE_*` settings:
196
+
197
+ - `NODE_OPTIONS`, when every token is one of `--max-old-space-size=<n>`,
198
+ `--max-semi-space-size=<n>`, `--use-openssl-ca`, `--use-bundled-ca`,
199
+ `--use-system-ca` or `--dns-result-order=ipv4first|ipv6first|verbatim`.
200
+ Any other flag, quotes, backslashes or tabs are refused.
201
+ - `NODE_EXTRA_CA_CERTS`.
202
+ - `NODE_PATH`.
203
+
204
+ `NODE_ENV` set to `production`, `test` or empty was already accepted. Every other non-empty
205
+ `NODE_*` setting withholds applicability. The values are part of the recorded
206
+ execution context: a run under one value is not reusable under another. A
207
+ `--require` in `NODE_OPTIONS` still runs inside REDUE's own process before REDUE
208
+ refuses it. The npm, pnpm and Yarn recipes still refuse `NODE_OPTIONS` and
209
+ `NODE_PATH`.
@@ -57,6 +57,14 @@ prefix. Uninstalling the package does not remove local verification evidence;
57
57
  `redue remove-state` is a separate, explicit action. Alpha.1 remains available as
58
58
  historical software and is superseded for package identity, not a runtime defect.
59
59
 
60
+ ## Upgrading REDUE
61
+
62
+ Stop every observer using the installation before upgrading, then restart each
63
+ with the same config/state selection. See [the npm launcher notice](npm-launcher-notice.md)
64
+ for exact commands. Do not remove state or delete receipts. Existing agent connections require a separate
65
+ [preview/apply policy update](agents.md#update-an-existing-connection); installing
66
+ the package alone does not update project instructions.
67
+
60
68
  ## First project
61
69
 
62
70
  From the project root:
@@ -74,7 +82,10 @@ Use a check actually printed by `init`. For a workspace:
74
82
  `redue init --workspace @example/package --check typecheck`.
75
83
  Initialization previews detected commands and qualification confidence before writing
76
84
  `redue.config.json`. An existing config is never overwritten. No checks are run and
77
- no dependencies installed. A missing/unsupported boundary is explained.
85
+ no dependencies installed. A missing/unsupported boundary is explained. `init` tries
86
+ the strict recipes first and uses the [general recipe](node-script.md) for a root
87
+ typecheck or lint script none of them takes. Test scripts use the
88
+ [direct test recipe](tests-direct.md).
78
89
 
79
90
  “Ready to qualify” means REDUE has a supported recipe whose prerequisites will be
80
91
  validated. It is not a receipt. “Recording-only” can record PASS/FAIL without claiming
@@ -82,7 +93,9 @@ reusability. Qualification can change when configuration or installation changes
82
93
 
83
94
  `run` streams normal output and preserves execution environment and cancellation.
84
95
  For the narrow pnpm TypeScript contract, `init` explicitly shows the direct installed
85
- compiler invocation it selects; other scripts run through the package manager.
96
+ compiler invocation it selects, and for npm the
97
+ [local compiler recipe](direct-typescript.md). General checks and other scripts
98
+ run through the package manager. No existing configuration is silently migrated.
86
99
  Only use configs and probes from trusted repositories: these execute local code.
87
100
 
88
101
  `status` is cached and conservative. `status --sync` and `explain` revalidate caller
@@ -125,3 +138,11 @@ all observed roots; its basename must start with `redue-` or legacy `vstate-`.
125
138
  For a removed checkout, `redue --state-dir /your/owned/redue-project-state remove-state`
126
139
  still works without rebuilding its compiler/configuration. Ownership/active-run conflicts
127
140
  are actionable errors, never resolved merely by deleting an old lock.
141
+
142
+ ## Connect an agent explicitly
143
+
144
+ After initialization, use `redue agent setup codex --dry-run` (or `claude`) to
145
+ review project-local instructions, then repeat with `--apply`. Start a fresh host
146
+ session. `redue agent doctor` checks prerequisites without running verification.
147
+ See [agent activation](agents.md) for loading rules, generic agents, and removal.
148
+ For a fixed build and ordinary development evaluation, use the [opt-in pilot guide](pilot.md).
package/docs/user/json.md CHANGED
@@ -30,6 +30,8 @@ Stable-enough-for-alpha fields:
30
30
  | `result` | Historical `PASS`, `FAIL`, or null. A failed invocation is not green even with CURRENT applicability. |
31
31
  | `freshness` | `CURRENT`, `STALE`, or `UNVERIFIED`, independent of result. |
32
32
  | `reuse_eligible` | True only for qualified, applicable passing evidence. Never derive permission to reuse from outcome alone. Missing means false. |
33
+ | `run_facts` | Number of lookups outside the discovery certificate that the receipt's run made (direct TypeScript recipe). Status asks each again before answering CURRENT. Absent when there are none. |
34
+ | `probe_deadline_ms` | Top level. How long the full state probes of one decision may take in total: each check's deadline (5 s to 60 s, from earlier probes and runs) times its probe count, summed. Callers wait at least this long plus 10 s for a synchronized answer. |
33
35
  | `reason` | Human explanation; not a stable machine enum. Do not parse it to authorize reuse. |
34
36
  | `changed_inputs` | Known changed relevant paths when available, possibly only the first difference; empty/missing is not proof of no changes. |
35
37
  | `invocation` | Null without a receipt; otherwise run ID, completion `status`, duration, exit code/signal when known. Status distinguishes exited, interrupted, and start/capture failure. |