0xray 4.0.25 → 4.0.27

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "description": "0xRay suit for Grok, Hermes, OpenClaw, OpenCode: mill+inspect, Codex, 7 MCP servers. Costume 45/42 is opt-in foundry, not the default wear.",
5
5
  "author": {
6
6
  "name": "0xRay AI",
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
62
62
 
63
63
  ## Lead cadence (syncopation)
64
64
 
65
- The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`.
65
+ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
66
66
 
67
67
  Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
68
68
 
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
76
76
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
77
77
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
78
78
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
79
- - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
- - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen when the diary contains that signal's name or a local clause of four definition content words; two definition words are not a hit; the same words scattered through a long diary are not a hit; a weak session score is not lifted to 0.55 and a sample below 0.55 is not recorded. Constructing the organ does not append workspace samples. Hero names: `heat-is-not-conviction`, `inference-cycle-invariant`, `governance-vote-invariant`, `thin-dispatch-invariant`. Repertoire mergeStackOverlay refreshes a changed stack definition and keeps observation stats. A floor observation count does not change a route. Feedback moves conviction by a tenth, and a failure can leave 0.55. learned-conviction.json beside dest restores that average when a wake flattens it to 0.55. It does not store the observation count.
79
+ - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
+ - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
81
81
  - **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
82
82
  - **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
83
83
 
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
96
96
 
97
97
  Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
98
98
  - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
99
- - **Board:** critic Strict comments; forge implements; lead stays main thread.
99
+ - **Board:** critic Strict comments; the implementer implements; lead stays main thread.
100
100
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
101
- - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
101
+ - **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
102
102
  - **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
96
96
  ```markdown
97
97
  ## What Next?
98
98
 
99
- - Related Codex terms: [codex.json](../../../../.xray/codex.json)
99
+ - Related Codex terms: [codex.json](../../../.xray/codex.json)
100
100
  - Next story to write: [suggestion]
101
101
  ```
102
102
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",
package/AGENTS.md CHANGED
@@ -12,7 +12,7 @@ Quick reference for the xray AI orchestration framework (**4.0**).
12
12
 
13
13
  Before other work, Read `.xray/state/STATION.md`. Compaction and host change are the same cut. Continue the card. Do not restart the job. Grok does not inject the card (OpenCode does) — this Read is the Grok contract. Do not thicken the Grok exo.
14
14
 
15
- **Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`LEAD-CADENCE.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`. Playbook: `orchestrator` skill.
15
+ **Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`grok-bot/OP-PROC.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`). Playbook: `orchestrator` skill.
16
16
 
17
17
  ## What is xray?
18
18
 
package/README.md CHANGED
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
52
52
  | Version | Highlights |
53
53
  |---------|------------|
54
54
  | **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
55
+ | **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Not published. |
55
56
  | **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
56
57
  | **4.0.0** | Exo + temperament. Constitution always on; ceremony by host. Repertoire organ on (vendored 0.2). Station card survives compact/host-swap. **On npm.** [vision](docs-site/docs/architecture/v4-vision.md) · [now](docs-site/docs/architecture/v4-now.md) |
57
58
  | **3.4.1** | Unified `install-bridges.cjs` on postinstall — OpenCode, Grok, Hermes, OpenClaw in one pass. All 7 MCPs servers via `npx -y 0xray mcp <cmd>` (no `dist/` paths). Canonical `release.mjs` pipeline. |
package/SKILLS.md CHANGED
@@ -76,7 +76,7 @@ xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) as the **costume /
76
76
 
77
77
  | Skill | Agent | Description |
78
78
  |-------|-------|-------------|
79
- | `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads SEATS; ship matrix A–D in `LEAD-CADENCE.md`) |
79
+ | `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads `grok-bot/OP-PROC.md`; ship matrix A–D in `grok-bot/OP-PROC.md`; team specifics live in `house/`) |
80
80
  | `xray-orchestrator` | — | xray orchestration skill (MCP orchestrator surface) |
81
81
  | `processor-pipeline` | — | Data processing pipeline management |
82
82
  | `boot-orchestrator` | — | Framework boot orchestration |
package/dist/AGENTS.md CHANGED
@@ -12,7 +12,7 @@ Quick reference for the xray AI orchestration framework (**4.0**).
12
12
 
13
13
  Before other work, Read `.xray/state/STATION.md`. Compaction and host change are the same cut. Continue the card. Do not restart the job. Grok does not inject the card (OpenCode does) — this Read is the Grok contract. Do not thicken the Grok exo.
14
14
 
15
- **Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`LEAD-CADENCE.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`. Playbook: `orchestrator` skill.
15
+ **Lead cadence:** a peer wearing this file + Station + Repertoire continues without a command stream. Dummy bodies test `SKILLS.md`. Same-sess bodies wear the suit and keep a Station card. Always branch + worktree + PR. Ship when mill-gate D + `foundry gate` PASS (`grok-bot/OP-PROC.md` Decision matrix) — green CI is not ship. npm OTP in a browser, then poll the new version before moving on. Loop until Station is done. Live ticks and moving workstreams — not idle pacers. Same critic (resume only). Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`). Playbook: `orchestrator` skill.
16
16
 
17
17
  ## What is xray?
18
18
 
package/dist/CHANGELOG.md CHANGED
@@ -41,6 +41,48 @@ The format is based on [Conventional Commits](https://www.conventionalcommits.or
41
41
  - Archive root `integrations/` costume SKILL dump → `docs/archive/integrations-costume/`. Live wear is `src/integrations`.
42
42
  - Archive root `commands/` stale copy → `docs/archive/commands-copy/`. Live wear is `src/opencode/commands`.
43
43
 
44
+ ## [4.0.27] - 2026-09-25
45
+
46
+ Next patch after npm `4.0.26`. Released 2026-09-26.
47
+
48
+ A counted host compact needs a non-empty generation id and a numeric `context_usage_percent`. That hook line and per-session receipt are written on the suit mill and mirrored onto nested consumer wear roots. Memory scoring rules live in `docs/memory-scoring.md`. The orchestrator links that file and does not copy the rules. Companion package `@0xray/grok-bot@0.1.6`: one general operating page, a `house/` overlay that is not in that npm pack, `templates/house/` in the pack, `grok-bot house init` (copy, refuse to overwrite), and doctor lookup via `GROK_BOT_HOUSE` or a walk-up for `house/HOUSE.md`.
49
+
50
+ ### 🔄 Changes
51
+
52
+ ### 🐛 Bug Fixes
53
+ - fix: a host compact proof requires a non-empty generation id and a numeric context_usage_percent (d869cbf79)
54
+ - fix: mirror preCompact proof to nested consumer wear roots (16b7481af)
55
+
56
+ ### 📚 Documentation
57
+ - feat(grok-bot): house init and shared house lookup (#128) (0f93687f2)
58
+ - General operating page for grok-bot, with a fill-in house (#124) (17e02c5a7)
59
+ - docs: orchestrator links memory-scoring (#127) (bca04dba8)
60
+ - docs: add ben-proof suited compaction bench harness (13284b9d8)
61
+ - docs: core audit fixes and a readable memory-scoring doc (#126) (23b370d1e)
62
+ - docs: point 0xray at grok-bot/OP-PROC.md (#125) (53b1889dc)
63
+
64
+ ### 🔎 Other Changes
65
+ - docs(grok-bot): OP-PROC amendment (Blaze 10:31) + moltbook push allow (#123) (a2abed78c)
66
+ - docs(grok-bot): OP-PROC one-page front door + WAVEBOARD/ATTENTION_STATE mirror (#122) (519b2dae0)
67
+
68
+ ---
69
+
70
+ ## [4.0.26] - 2026-09-25
71
+
72
+ ### 🔄 Changes
73
+
74
+ ### 🐛 Bug Fixes
75
+ - fix: store a lesson when the task matches no signal (e3c75b43d)
76
+ - fix: prove a Cursor compact cut with a session log and per-session receipt (bb3a1c68f)
77
+ - fix: mill check accepts a published version; mcp:status runs (a8bd79e23)
78
+
79
+ ### 🔎 Other Changes
80
+ - Merge pull request #116 from 0xRayAI/cursor/mill-ci-mcp-status-fbe0 (ba94508d2)
81
+ - Merge pull request #120 from 0xRayAI/cursor/lesson-recall-fbe0 (8f4a5a62a)
82
+ - Merge pull request #119 from 0xRayAI/cursor/compact-receipt-proof-fbe0 (a911fd17b)
83
+
84
+ ---
85
+
44
86
  ## [4.0.25] - 2026-09-24
45
87
 
46
88
  `0xray@4.0.25` ships the plate schematics in the package. `docs-site/docs/plates/` is on the npm `files` list. A worn suit resolves `memory-recall` and `processor` from `dist/integrations/hooks/plates.cjs`.
package/dist/README.md CHANGED
@@ -52,6 +52,7 @@ Docs: [guides/autonomy-command](docs-site/docs/guides/autonomy-command.md) · Sk
52
52
  | Version | Highlights |
53
53
  |---------|------------|
54
54
  | **Unreleased** | Fasten is **foundry-plant/0**: builtin plant is mill+inspect only. `foundry.json` `"plant": "@0xray/blip"` (aliases `"plant": "blip"` / `"plant": "sound"`) fastens whatever that mill declares (looker / vibe / mixer live in the mill). Nested mill `@0xray/foundry@0.1.12`. CLI shims `foundry blip\|sound` remain (0.1.11+). Shop plant first-class (`shop-extract`, `shop-witness`, `shop-pin` + `foundry.json` `shopPlant`). |
55
+ | **4.0.27** | Host compact proof needs a generation id and a numeric usage percent, and the same preCompact receipt is mirrored to nested consumer wear roots. Memory scoring: [docs/memory-scoring.md](docs/memory-scoring.md) (orchestrator links it). Companion `@0xray/grok-bot` 0.1.6: general page vs `house/` overlay, `templates/house/`, `grok-bot house init`, doctor `GROK_BOT_HOUSE` or walk-up. Not published. |
55
56
  | **4.0.9** | Mill target: postinstall does not mill npm global prefix or `_npx` as a consumer. Isolated HOME skips machine `~/.grok`. |
56
57
  | **4.0.0** | Exo + temperament. Constitution always on; ceremony by host. Repertoire organ on (vendored 0.2). Station card survives compact/host-swap. **On npm.** [vision](docs-site/docs/architecture/v4-vision.md) · [now](docs-site/docs/architecture/v4-now.md) |
57
58
  | **3.4.1** | Unified `install-bridges.cjs` on postinstall — OpenCode, Grok, Hermes, OpenClaw in one pass. All 7 MCPs servers via `npx -y 0xray mcp <cmd>` (no `dist/` paths). Canonical `release.mjs` pipeline. |
package/dist/SKILLS.md CHANGED
@@ -76,7 +76,7 @@ xray ships 45 knowledge skills (`src/skills/<name>/SKILL.md`) as the **costume /
76
76
 
77
77
  | Skill | Agent | Description |
78
78
  |-------|-------|-------------|
79
- | `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads SEATS; ship matrix A–D in `LEAD-CADENCE.md`) |
79
+ | `orchestrator` | @orchestrator | Multi-agent coordination + **lead-dev mode** (codex 67–68) + lead cadence (dispatch four lines; critic Reads `grok-bot/OP-PROC.md`; ship matrix A–D in `grok-bot/OP-PROC.md`; team specifics live in `house/`) |
80
80
  | `xray-orchestrator` | — | xray orchestration skill (MCP orchestrator surface) |
81
81
  | `processor-pipeline` | — | Data processing pipeline management |
82
82
  | `boot-orchestrator` | — | Framework boot orchestration |
@@ -1,3 +1,15 @@
1
+ export type McpInstallerAction = {
2
+ kind: "list" | "status" | "help";
3
+ } | {
4
+ kind: "install" | "remove";
5
+ name?: string;
6
+ } | {
7
+ kind: "unknown";
8
+ command: string;
9
+ };
10
+ /** Colon and hyphen forms documented on `npx 0xray` map to the bare dispatcher verbs. */
11
+ export declare function normalizeMcpInstallerToken(command: string | undefined): string | undefined;
12
+ export declare function classifyMcpInstallerArgs(args: readonly string[]): McpInstallerAction;
1
13
  export declare function listMCPsCommand(): void;
2
14
  export declare function showMCPStatusCommand(): void;
3
15
  export declare function installMCPCommand(name: string): Promise<void>;
@@ -1,6 +1,7 @@
1
1
  import { existsSync, readFileSync, writeFileSync, mkdirSync, rmSync } from "fs";
2
- import { join, dirname } from "path";
2
+ import { join, dirname, resolve } from "path";
3
3
  import { execSync } from "child_process";
4
+ import { fileURLToPath } from "url";
4
5
  import { getConfigDir } from "../../core/config-paths.js";
5
6
  function getMCPConfigPath() {
6
7
  return join(process.cwd(), ".xray", "mcp-registry.json");
@@ -186,9 +187,44 @@ function removeMCP(name) {
186
187
  saveInstalledMCPs(installed);
187
188
  console.log(`\n✅ Removed ${name}`);
188
189
  }
190
+ const MCP_INSTALLER_ALIASES = {
191
+ "mcp:list": "list",
192
+ "mcp-list": "list",
193
+ "mcp:status": "status",
194
+ "mcp-status": "status",
195
+ "mcp:install": "install",
196
+ "mcp-install": "install",
197
+ "mcp:remove": "remove",
198
+ "mcp-remove": "remove",
199
+ };
200
+ /** Colon and hyphen forms documented on `npx 0xray` map to the bare dispatcher verbs. */
201
+ export function normalizeMcpInstallerToken(command) {
202
+ if (command === undefined)
203
+ return undefined;
204
+ return MCP_INSTALLER_ALIASES[command] ?? command;
205
+ }
206
+ export function classifyMcpInstallerArgs(args) {
207
+ const raw = args[0];
208
+ const command = normalizeMcpInstallerToken(raw);
209
+ if (command === undefined || command === "status")
210
+ return { kind: "status" };
211
+ if (command === "list")
212
+ return { kind: "list" };
213
+ if (command === "help" || command === "--help" || command === "-h")
214
+ return { kind: "help" };
215
+ if (command === "install" || command === "remove") {
216
+ const name = args[1];
217
+ return name === undefined ? { kind: command } : { kind: command, name };
218
+ }
219
+ return { kind: "unknown", command: raw ?? command };
220
+ }
221
+ const isDirectRun = process.argv[1] !== undefined &&
222
+ resolve(process.argv[1]) === fileURLToPath(import.meta.url);
189
223
  async function main() {
224
+ if (!isDirectRun)
225
+ return;
190
226
  const args = process.argv.slice(2);
191
- const command = args[0];
227
+ const command = normalizeMcpInstallerToken(args[0]);
192
228
  switch (command) {
193
229
  case "list":
194
230
  listMCPs();
@@ -25,7 +25,7 @@ Copy the consumer template from `src/integrations/cursor/hooks/hooks.json` and t
25
25
 
26
26
  `preCompact` labels `event_class`:
27
27
 
28
- - `cursor-host-precompact` — Cursor actually fired the hook
28
+ - `cursor-host-precompact` — Cursor actually fired the hook. The event must carry a non-empty `generation_id` and a numeric `context_usage_percent`, plus the hook name or trigger. A token count or `trigger: auto` alone stays synthetic and does not write `cursor-hook.log` or `cursor-receipts/<sessionId>.json`.
29
29
  - `cursor-precompact-synthetic` — script invoked with `--event-class=cursor-precompact-synthetic` (Path C fallback)
30
30
  - `cursor-host-precompact-FAIL` — HOST-FIRE fill ran; host did not spawn `preCompact` (see `RECEIPT-HOST-PRECOMPACT.md`, `-2.md`, `-3.md`)
31
31
  - First live host fire (Arm S): `examples/killer-dual/RECEIPT-HOST-PRECOMPACT.md`
@@ -40,7 +40,11 @@ Do **not** prove window pressure with UTF-8 chars÷4. `src/integrations/cursor/h
40
40
  | `cursor-cloud` `run-info` / `get-events` / dashboard (model, bc-id, window) | yes — token MISS is honest |
41
41
  | chars÷4, fill-only, `fillBytes` | **forbidden** (`ok: false`) |
42
42
 
43
- Host `preCompact` fire is counted from `.xray/state/cursor-hook-invoke.log` (`event=preCompact`). Do not hand-invoke `pre-compact.js` to mint that Y.
43
+ Host `preCompact` fire is counted from `.xray/state/cursor-hook-invoke.log` (`event=preCompact`). Do not hand-invoke `pre-compact.js` to mint that Y. That invoke log has no session id.
44
+
45
+ A cut counts only when `.xray/state/cursor-receipts/<sessionId>.json` exists **and** `.xray/state/cursor-hook.log` contains a line with that same session id (timestamp, `context_tokens`, `context_usage_percent`, `context_window_size`, `generation_id`). `probeLogExists` is true only when that append succeeded. `.xray/state/cursor-usage-receipt.json` and `cursor-precompact.json` keep only the newest event. That single latest json is not enough — the next arm overwrites it.
46
+
47
+ Nested consumer benches under `examples/` (e.g. `examples/ben-proof/suited` with local `node_modules/0xray`) receive the same hook log line and per-session receipt as the mill — `preCompact` has no Read paths, so those wear roots are discovered from the suit mill at compact time.
44
48
 
45
49
  Arm S landscape + receipt: `examples/killer-dual/`.
46
50
 
@@ -53,6 +53,11 @@ export {
53
53
  FORBIDDEN_USAGE_METHODS,
54
54
  invokeProbeLogPath,
55
55
  cursorUsageReceiptPath,
56
+ cursorHookLogPath,
57
+ sanitizeSessionReceiptId,
58
+ cursorSessionReceiptPath,
59
+ appendCursorCompactProofLog,
60
+ writeCursorSessionReceipt,
56
61
  parseInvokeProbeLog,
57
62
  hostUsageFromPreCompactEvent,
58
63
  classifyUsageCite,
@@ -182,6 +187,73 @@ export function cursorHeatRoots(event = {}) {
182
187
  return out;
183
188
  }
184
189
 
190
+ function isNestedConsumerWearRoot(root, millRoot) {
191
+ if (!root || !millRoot) return false;
192
+ const resolved = path.resolve(String(root));
193
+ const millResolved = path.resolve(String(millRoot));
194
+ if (resolved === millResolved) return false;
195
+ if (!heatRootHasCard(resolved) || !isHeatRootWritable(resolved)) return false;
196
+ const wornRay = path.join(resolved, 'node_modules', '0xray', 'package.json');
197
+ if (!fs.existsSync(wornRay)) return false;
198
+ if (!resolved.startsWith(millResolved + path.sep)) return false;
199
+ return true;
200
+ }
201
+
202
+ /**
203
+ * Nested consumer benches (e.g. examples/ben-proof/suited) wear 0xray locally.
204
+ * preCompact stdin has no Read paths, so cursorHeatRoots never visits those dirs.
205
+ */
206
+ export function discoverNestedConsumerWearRoots(millRoot) {
207
+ const millResolved = path.resolve(String(millRoot));
208
+ if (packageNameAt(millResolved) !== '0xray') return [];
209
+ const out = [];
210
+ const seen = new Set();
211
+ const queue = [path.join(millResolved, 'examples')];
212
+ let steps = 0;
213
+ while (queue.length > 0 && steps < 500) {
214
+ steps += 1;
215
+ const dir = queue.shift();
216
+ if (!dir || !fs.existsSync(dir)) continue;
217
+ let entries;
218
+ try {
219
+ entries = fs.readdirSync(dir, { withFileTypes: true });
220
+ } catch {
221
+ continue;
222
+ }
223
+ for (const ent of entries) {
224
+ if (!ent.isDirectory()) continue;
225
+ if (ent.name === 'node_modules' || ent.name === '.git' || ent.name === 'dist') continue;
226
+ const full = path.join(dir, ent.name);
227
+ if (isNestedConsumerWearRoot(full, millResolved) && !seen.has(full)) {
228
+ seen.add(full);
229
+ out.push(full);
230
+ }
231
+ queue.push(full);
232
+ }
233
+ }
234
+ return out;
235
+ }
236
+
237
+ /** Mill heat roots plus nested consumer wear sites that share the same compact proof. */
238
+ export function cursorCompactProofRoots(event = {}) {
239
+ const seen = new Set();
240
+ const out = [];
241
+ for (const root of cursorHeatRoots(event)) {
242
+ const resolved = path.resolve(String(root));
243
+ if (seen.has(resolved)) continue;
244
+ seen.add(resolved);
245
+ out.push(resolved);
246
+ if (packageNameAt(resolved) !== '0xray') continue;
247
+ for (const worn of discoverNestedConsumerWearRoots(resolved)) {
248
+ const wornResolved = path.resolve(String(worn));
249
+ if (seen.has(wornResolved)) continue;
250
+ seen.add(wornResolved);
251
+ out.push(wornResolved);
252
+ }
253
+ }
254
+ return out;
255
+ }
256
+
185
257
  function packageNameAt(root) {
186
258
  try {
187
259
  const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
@@ -204,6 +276,7 @@ export function cursorGateRoot(heatRoots, eventRoot) {
204
276
  export function cursorSessionId(event = {}) {
205
277
  return (
206
278
  event.conversation_id ||
279
+ event.conversationId ||
207
280
  event.session_id ||
208
281
  event.sessionId ||
209
282
  process.env.CURSOR_CONVERSATION_ID ||
@@ -258,13 +331,15 @@ export function classifyPreCompactEvent(event = {}, argv = process.argv) {
258
331
  if (fromEvent) return fromEvent;
259
332
 
260
333
  const named = event.hook_event_name || event.hookEventName || event.hook;
261
- const looksHost =
262
- named === 'preCompact' ||
263
- named === 'pre_compact' ||
264
- event.trigger === 'auto' ||
265
- event.trigger === 'manual' ||
266
- typeof event.context_tokens === 'number' ||
267
- typeof event.context_usage_percent === 'number';
334
+ const hookNamed = named === 'preCompact' || named === 'pre_compact';
335
+ const triggerNamed = event.trigger === 'auto' || event.trigger === 'manual';
336
+ const generation = event.generation_id || event.generationId;
337
+ const hasGeneration = typeof generation === 'string' && generation.trim().length > 0;
338
+ const hasPercent = typeof event.context_usage_percent === 'number';
339
+ // A token count or trigger alone is not a host fire. The 2026-09-25 20:28
340
+ // line had context_tokens 120000 and window 200000 with no generation id,
341
+ // no usage percent, and no preCompact invoke.
342
+ const looksHost = (hookNamed || triggerNamed) && hasGeneration && hasPercent;
268
343
  return looksHost ? EVENT_CLASS_HOST : EVENT_CLASS_SYNTHETIC;
269
344
  }
270
345
 
@@ -28,6 +28,70 @@ export function cursorUsageReceiptPath(root) {
28
28
  return path.join(root, '.xray', 'state', 'cursor-usage-receipt.json');
29
29
  }
30
30
 
31
+ /** Proof log. A cut is greppable here; cursor-hook-invoke.log has no session id. */
32
+ export function cursorHookLogPath(root) {
33
+ return path.join(root, '.xray', 'state', 'cursor-hook.log');
34
+ }
35
+
36
+ function logToken(value) {
37
+ if (value == null) return '';
38
+ return String(value).replace(/[\r\n]+/g, '');
39
+ }
40
+
41
+ /**
42
+ * Safe filename segment for `.xray/state/cursor-receipts/<id>.json`.
43
+ * Empty when the id cannot be kept inside that directory.
44
+ */
45
+ export function sanitizeSessionReceiptId(sessionId) {
46
+ const raw = typeof sessionId === 'string' ? sessionId.trim() : '';
47
+ if (!raw) return '';
48
+ const safe = raw
49
+ .replace(/\0/g, '')
50
+ .replace(/[/\\]/g, '_')
51
+ .replace(/\.\./g, '_')
52
+ .replace(/[^A-Za-z0-9._-]+/g, '_')
53
+ .replace(/^[._]+/, '')
54
+ .replace(/[._]+$/g, '');
55
+ if (!safe || safe === '.' || safe === '..') return '';
56
+ return safe.slice(0, 180);
57
+ }
58
+
59
+ export function cursorSessionReceiptPath(root, sessionId) {
60
+ const safe = sanitizeSessionReceiptId(sessionId);
61
+ if (!safe) return null;
62
+ return path.join(root, '.xray', 'state', 'cursor-receipts', `${safe}.json`);
63
+ }
64
+
65
+ /**
66
+ * Append one preCompact proof line. True only when the append landed and
67
+ * the file contains that session id (grep of *.log can find the cut).
68
+ */
69
+ export function appendCursorCompactProofLog(root, fields = {}) {
70
+ const sessionId = logToken(fields.sessionId);
71
+ const timestamp = logToken(fields.timestamp) || new Date().toISOString();
72
+ const line = [
73
+ `ts=${timestamp}`,
74
+ `session_id=${sessionId}`,
75
+ `context_tokens=${logToken(fields.context_tokens)}`,
76
+ `context_usage_percent=${logToken(fields.context_usage_percent)}`,
77
+ `context_window_size=${logToken(fields.context_window_size)}`,
78
+ `generation_id=${logToken(fields.generation_id)}`,
79
+ ].join(' ');
80
+ const dest = cursorHookLogPath(root);
81
+ try {
82
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
83
+ fs.appendFileSync(dest, `${line}\n`);
84
+ } catch {
85
+ return false;
86
+ }
87
+ if (!sessionId) return false;
88
+ try {
89
+ return fs.readFileSync(dest, 'utf8').includes(`session_id=${sessionId}`);
90
+ } catch {
91
+ return false;
92
+ }
93
+ }
94
+
31
95
  export function parseInvokeProbeLog(root) {
32
96
  const dest = invokeProbeLogPath(root);
33
97
  const counts = { preToolUse: 0, preCompact: 0, afterFileEdit: 0, unknown: 0 };
@@ -228,7 +292,7 @@ export function buildCursorUsageReceipt(root, input = {}) {
228
292
  preToolUseCount: probe.counts.preToolUse,
229
293
  afterFileEditCount: probe.counts.afterFileEdit,
230
294
  eventClass,
231
- probeLogExists: probe.exists,
295
+ probeLogExists: input.probeLogExists === true,
232
296
  },
233
297
  usage,
234
298
  repertoire,
@@ -299,3 +363,32 @@ export function writeCursorUsageReceipt(root, input = {}) {
299
363
  return null;
300
364
  }
301
365
  }
366
+
367
+ /**
368
+ * Per-session copy of the latest precompact + usage receipts.
369
+ * The next arm overwrites cursor-precompact.json and cursor-usage-receipt.json.
370
+ */
371
+ export function writeCursorSessionReceipt(root, sessionId, paths = {}) {
372
+ const dest = cursorSessionReceiptPath(root, sessionId);
373
+ if (!dest) return null;
374
+ if (!paths.precompactPath && !paths.usagePath) return null;
375
+ try {
376
+ const payload = {
377
+ sessionId: typeof sessionId === 'string' ? sessionId : null,
378
+ precompact: null,
379
+ usage: null,
380
+ };
381
+ if (paths.precompactPath && fs.existsSync(paths.precompactPath)) {
382
+ payload.precompact = JSON.parse(fs.readFileSync(paths.precompactPath, 'utf8'));
383
+ }
384
+ if (paths.usagePath && fs.existsSync(paths.usagePath)) {
385
+ payload.usage = JSON.parse(fs.readFileSync(paths.usagePath, 'utf8'));
386
+ }
387
+ if (!payload.precompact && !payload.usage) return null;
388
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
389
+ fs.writeFileSync(dest, JSON.stringify(payload, null, 2));
390
+ return dest;
391
+ } catch {
392
+ return null;
393
+ }
394
+ }
@@ -10,15 +10,18 @@ import {
10
10
  buildSessionBootPayload,
11
11
  classifyPreCompactEvent,
12
12
  cursorGenerationId,
13
- cursorHeatRoots,
13
+ cursorCompactProofRoots,
14
14
  cursorSessionId,
15
+ EVENT_CLASS_HOST,
15
16
  cursorWorkspaceRoot,
16
17
  readStdinJson,
17
18
  writeCursorPrecompactReceipt,
18
19
  writeSessionBoot,
19
20
  } from './cursor-hook-utils.js';
20
21
  import {
22
+ appendCursorCompactProofLog,
21
23
  hostUsageFromPreCompactEvent,
24
+ writeCursorSessionReceipt,
22
25
  writeCursorUsageReceipt,
23
26
  } from './cursor-usage-receipt.js';
24
27
 
@@ -122,7 +125,7 @@ async function main() {
122
125
  } catch {
123
126
  plates = null;
124
127
  }
125
- for (const root of cursorHeatRoots(event)) {
128
+ for (const root of cursorCompactProofRoots(event)) {
126
129
  const payload = buildSessionBootPayload(root, '0xray/cursor-compact', {
127
130
  host: 'cursor',
128
131
  hookEvent: 'pre_compact',
@@ -132,6 +135,20 @@ async function main() {
132
135
  });
133
136
  bootPath = writeSessionBoot(root, payload);
134
137
  stationLine = payload.stationLine;
138
+ const stampedAt = new Date().toISOString();
139
+ const hostProof = eventClass === EVENT_CLASS_HOST;
140
+ const proofLogged = hostProof
141
+ ? appendCursorCompactProofLog(root, {
142
+ sessionId,
143
+ timestamp: stampedAt,
144
+ context_tokens: typeof event.context_tokens === 'number' ? event.context_tokens : null,
145
+ context_usage_percent:
146
+ typeof event.context_usage_percent === 'number' ? event.context_usage_percent : null,
147
+ context_window_size:
148
+ typeof event.context_window_size === 'number' ? event.context_window_size : null,
149
+ generation_id: generationId,
150
+ })
151
+ : false;
135
152
  receiptPath = writeCursorPrecompactReceipt(root, {
136
153
  event_class: eventClass,
137
154
  hookEvent: 'pre_compact',
@@ -145,13 +162,20 @@ async function main() {
145
162
  messages_to_compact:
146
163
  typeof event.messages_to_compact === 'number' ? event.messages_to_compact : null,
147
164
  bootPath,
148
- timestamp: new Date().toISOString(),
165
+ timestamp: stampedAt,
149
166
  });
150
167
  usagePath = writeCursorUsageReceipt(root, {
151
168
  eventClass,
152
169
  sessionId,
170
+ probeLogExists: proofLogged,
153
171
  usage: hostUsageFromPreCompactEvent(event),
154
172
  });
173
+ if (hostProof) {
174
+ writeCursorSessionReceipt(root, sessionId, {
175
+ precompactPath: receiptPath,
176
+ usagePath,
177
+ });
178
+ }
155
179
  if (plates) {
156
180
  try {
157
181
  const named = plates.recallPlate(payload.intent || intent || '');
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -4,13 +4,18 @@ export interface LessonInput {
4
4
  taskId: string;
5
5
  assignedAgent: string;
6
6
  sessionId: string;
7
- /** Signals the finished task already named. When set, text matching is not used. */
7
+ /**
8
+ * Signals the finished task already named. When set, text matching is not used.
9
+ * An empty list with a lesson still stores that lesson under a name taken from the task.
10
+ */
8
11
  signals?: string[];
9
12
  /** Approaches, solutions, or the wrong turn from the sessions that named the law. */
10
13
  lesson?: string;
11
14
  }
12
15
  /**
13
16
  * A finished task names the signals its text actually matched and says
14
- * whether the outcome was good. That is the one-tenth step. No match, no write.
17
+ * whether the outcome was good. That is the one-tenth step.
18
+ * A lesson with no matched signal is stored under a hyphenated name from the
19
+ * task, so the same task text recalls it. No lesson and no match, no write.
15
20
  */
16
21
  export declare function recordLesson(input: LessonInput): string[];
@@ -1,14 +1,48 @@
1
1
  import { ensureMemoryRoutingProviderSync } from "./provider-registry.js";
2
+ /**
3
+ * Hyphenated phrase whose spaced form is still inside the task.
4
+ * A later routing read of that same task hits the name.
5
+ */
6
+ function signalNameForUnmatchedLesson(task) {
7
+ const words = task
8
+ .toLowerCase()
9
+ .split(/[^a-z0-9]+/)
10
+ .filter((word) => word.length >= 3);
11
+ const normalized = task.toLowerCase();
12
+ const kept = [];
13
+ for (const word of words) {
14
+ const next = [...kept, word];
15
+ const phrase = next.join(" ");
16
+ const hyphen = next.join("-");
17
+ if (!normalized.includes(phrase) || hyphen.length > 120)
18
+ break;
19
+ kept.push(word);
20
+ }
21
+ if (kept.length === 0)
22
+ return null;
23
+ return kept.join("-");
24
+ }
2
25
  /**
3
26
  * A finished task names the signals its text actually matched and says
4
- * whether the outcome was good. That is the one-tenth step. No match, no write.
27
+ * whether the outcome was good. That is the one-tenth step.
28
+ * A lesson with no matched signal is stored under a hyphenated name from the
29
+ * task, so the same task text recalls it. No lesson and no match, no write.
5
30
  */
6
31
  export function recordLesson(input) {
7
32
  const provider = ensureMemoryRoutingProviderSync();
8
33
  if (provider.id === "null" || !provider.ingestFeedback)
9
34
  return [];
10
- const named = input.signals ?? provider.buildRoutingContext(input.operation).matchedSignals;
11
- const names = [...new Set(named.filter((name) => name.length > 0))];
35
+ const lesson = (input.lesson ?? "").trim();
36
+ const supplied = input.signals;
37
+ const named = supplied !== undefined
38
+ ? supplied
39
+ : provider.buildRoutingContext(input.operation).matchedSignals;
40
+ let names = [...new Set(named.filter((name) => name.length > 0))];
41
+ if (names.length === 0 && lesson.length > 0) {
42
+ const coined = signalNameForUnmatchedLesson(input.operation);
43
+ if (coined)
44
+ names = [coined];
45
+ }
12
46
  if (names.length === 0)
13
47
  return [];
14
48
  provider.ingestFeedback({
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
62
62
 
63
63
  ## Lead cadence (syncopation)
64
64
 
65
- The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`.
65
+ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
66
66
 
67
67
  Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
68
68
 
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
76
76
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
77
77
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
78
78
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
79
- - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
- - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen when the diary contains that signal's name or a local clause of four definition content words; two definition words are not a hit; the same words scattered through a long diary are not a hit; a weak session score is not lifted to 0.55 and a sample below 0.55 is not recorded. Constructing the organ does not append workspace samples. Hero names: `heat-is-not-conviction`, `inference-cycle-invariant`, `governance-vote-invariant`, `thin-dispatch-invariant`. Repertoire mergeStackOverlay refreshes a changed stack definition and keeps observation stats. A floor observation count does not change a route. Feedback moves conviction by a tenth, and a failure can leave 0.55. learned-conviction.json beside dest restores that average when a wake flattens it to 0.55. It does not store the observation count.
79
+ - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
+ - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
81
81
  - **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
82
82
  - **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
83
83
 
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
96
96
 
97
97
  Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
98
98
  - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
99
- - **Board:** critic Strict comments; forge implements; lead stays main thread.
99
+ - **Board:** critic Strict comments; the implementer implements; lead stays main thread.
100
100
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
101
- - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
101
+ - **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
102
102
  - **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
96
96
  ```markdown
97
97
  ## What Next?
98
98
 
99
- - Related Codex terms: [codex.json](../../../../.xray/codex.json)
99
+ - Related Codex terms: [codex.json](../../../.xray/codex.json)
100
100
  - Next story to write: [suggestion]
101
101
  ```
102
102
 
package/llms.txt CHANGED
@@ -8,7 +8,10 @@ Default consumer wear is **mill plant** (`mill` + `inspect`), not a 45-skill / 4
8
8
 
9
9
  ## Wear (what a stranger gets)
10
10
 
11
- - `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw) plus Cursor `.cursor/hooks.json`, overlays their plant. Grok last-mile dest is project `.grok/plugins/0xray`. Shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`. Isolated HOME must not write the machine plugin. Does **not** write consumer-root `SKILLS.md`. Lead cadence: `grok-bot/ops/LEAD-CADENCE.md` — a peer continues from Station + Repertoire; dummy tests `SKILLS.md`; same-sess wear; branch/PR; OTP then poll; loop until Station; live ticks, not idle pacers.
11
+ - `npm install 0xray` — postinstall fastens mill+inspect, writes 7 MCP `.mcp.json`, four host bridges (OpenCode, Grok, Hermes, OpenClaw) plus Cursor `.cursor/hooks.json`, overlays their plant. Grok last-mile dest is project `.grok/plugins/0xray`. Shared HOME does not last-wins clobber machine `~/.grok/plugins/0xray`. Isolated HOME must not write the machine plugin. Does **not** write consumer-root `SKILLS.md`. Lead cadence: `grok-bot/OP-PROC.md` (team specifics live in `house/`) — a peer continues from Station + Repertoire; dummy tests `SKILLS.md`; same-sess wear; branch/PR; OTP then poll; loop until Station; live ticks, not idle pacers.
12
+ - Memory scoring rules: [docs/memory-scoring.md](docs/memory-scoring.md). The orchestrator links that file. It does not copy the rules.
13
+ - Host `preCompact` writes the hook line and per-session receipt on the suit mill and on nested consumer wear roots (a bench with local `node_modules/0xray`). A counted cut needs a non-empty generation id and a numeric usage percent.
14
+ - `@0xray/grok-bot`: the general page is `grok-bot/OP-PROC.md`. The team overlay is `house/` and is not in that npm pack. `templates/house/` ships. `grok-bot house init` copies the template and refuses to overwrite. Doctor uses `GROK_BOT_HOUSE` when set, otherwise walks up from the working directory for `house/HOUSE.md`.
12
15
 
13
16
  - `npx @0xray/foundry mint --skip-live` — re-fasten mill plant, then inspect.
14
17
  - `npx @0xray/foundry inspect --skip-live` — plant-vs-worn, receipt, CI. Chat is not a receipt.
@@ -58,5 +61,6 @@ Not an 8th `xray-*` server. **Repertoire is preferred** — vendored 0.2.8 ships
58
61
  - [SKILLS.md](SKILLS.md) — catalog (costume / self-plant, not default sync)
59
62
  - [Foundry](docs-site/docs/architecture/v4-foundry.md) — mill vs exo, foundry-plant/0, shopPlant
60
63
  - [Features since 3.1](docs-site/docs/guides/features-since-3.1.md)
64
+ - [Memory scoring](docs/memory-scoring.md)
61
65
 
62
66
  Playwright / UI: n/a. This mill is CLI.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "0xray",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "description": "Multi-agent orchestration and Codex governance for OpenCode, Hermes, Grok Build, and OpenClaw",
5
5
  "readme": "README.md",
6
6
  "license": "MIT",
@@ -80,8 +80,9 @@
80
80
  "test:code-analysis": "npm test -- src/__tests__/unit/codebase-context-analyzer.test.ts src/__tests__/unit/dependency-graph-builder.test.ts src/__tests__/unit/rule-enforcer.test.ts src/__tests__/unit/codex-parser.test.ts src/__tests__/unit/codex-injector.test.ts",
81
81
  "test:processors": "npm test -- src/__tests__/unit/processor-activation.test.ts src/__tests__/unit/typescript-compilation-processor.test.ts",
82
82
  "test:miscellaneous": "npm test -- src/__tests__/unit/blocked-test.test.ts",
83
+ "test:grok-bot": "npm test -- src/__tests__/unit/grok-bot-seat-doctor.test.ts src/__tests__/unit/grok-bot-op-proc-map.test.ts src/__tests__/unit/lead-cadence.test.ts src/__tests__/unit/grok-bot-auto-review-policy.test.ts",
83
84
  "test:quick": "npm test -- src/__tests__/integration/boot-orchestrator.integration.test.ts src/__tests__/unit/config-loader.test.ts src/__tests__/unit/state-manager.test.ts",
84
- "test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts",
85
+ "test:comprehensive": "npm run typecheck && npm run test:unit && npm run test:core-framework && npm run test:security && npm run test:performance && npm run test:session-management && npm run test:code-analysis && npm run test:processors && npm run test:miscellaneous && npm test -- src/__tests__/unit/llm-governance-provider.test.ts src/__tests__/unit/mcp-server-smoke.test.ts src/__tests__/unit/cursor-hooks.test.ts src/__tests__/unit/host-vs-mill-score.test.ts && npm run test:grok-bot",
85
86
  "test:integration-all": "npm test -- src/__tests__/integration/",
86
87
  "test:performance-all": "npm test -- src/__tests__/performance/ src/__tests__/unit/performance-system.test.ts src/__tests__/unit/benchmark.test.ts src/__tests__/unit/analytics.test.ts",
87
88
  "test:agents-all": "echo 'Legacy agents test entry retired'",
@@ -11,7 +11,9 @@
11
11
  * npx @0xray/foundry reconcile patch --apply
12
12
  *
13
13
  * --apply writes package.json and the package-lock.json version fields.
14
- * --check fails when the lock does not match package.json.
14
+ * --check passes when package.json is equal to the registry (already published)
15
+ * or greater (the pre-publish bump). It fails when package.json is behind npm,
16
+ * or when the lock does not match package.json.
15
17
  */
16
18
 
17
19
  import { execSync } from "child_process";
@@ -91,6 +93,21 @@ function fail(msg) {
91
93
  process.exit(1);
92
94
  }
93
95
 
96
+ /**
97
+ * Registry gate for --check.
98
+ * Equal to npm is a shipped release. Greater is the pre-publish bump.
99
+ * Only a package.json behind the registry fails.
100
+ * @param {string} local
101
+ * @param {string} npmVersion
102
+ * @returns {string | null}
103
+ */
104
+ export function publishedVersionCheckError(local, npmVersion) {
105
+ if (compare(local, npmVersion) < 0) {
106
+ return `package.json (${local}) must be >= npm (${npmVersion}). Run: npx @0xray/foundry reconcile patch --apply`;
107
+ }
108
+ return null;
109
+ }
110
+
94
111
  function main() {
95
112
  const local = readLocalVersion();
96
113
  const npm = readPublishedVersion();
@@ -138,9 +155,12 @@ function main() {
138
155
  return;
139
156
  }
140
157
 
141
- // Strict checks for release gate / pre-tag
142
- if (compare(local, npm) <= 0) {
143
- fail(`package.json (${local}) must be > npm (${npm}). Run: npx @0xray/foundry reconcile patch --apply`);
158
+ // Strict checks for release gate / pre-tag.
159
+ // `local` is the version read before --apply. Apply still writes
160
+ // bumpVersion(max(npm, tag)) and is not this gate.
161
+ const behindNpm = publishedVersionCheckError(local, npm);
162
+ if (behindNpm) {
163
+ fail(behindNpm);
144
164
  }
145
165
 
146
166
  const pkgVersion = readLocalVersion();
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xray-pre-tool",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "description": "0xRay constitution + temperament PreToolUse for OpenClaw",
@@ -62,7 +62,7 @@ Config: `features.json` → `multi_agent_orchestration.lead_dev_mode`
62
62
 
63
63
  ## Lead cadence (syncopation)
64
64
 
65
- The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/ops/LEAD-CADENCE.md`.
65
+ The seven rules are the engine. The cadence is the time signature. Disk SSOT: `grok-bot/OP-PROC.md` (team specifics live in `house/`).
66
66
 
67
67
  Jargon is not the job. Review and cadence ask whether the change works. Do not spend the loop reciting dest names, mill liturgy, or host mantras.
68
68
 
@@ -76,8 +76,8 @@ Jargon is not the job. Review and cadence ask whether the change works. Do not s
76
76
  - **Peer boot:** four-line dispatch. They Read Station + this cadence and install without a command novel. Not a twin critic.
77
77
  - **Live tick, not pacer:** `/loop` runs work now. Keep workstreams moving. Do not idle-wait 12 minutes. **Clean ticks every cycle** — unsubscribe then resubscribe so the prompt matches metal. Name-dedupe does not rewrite. A stale prompt (waiting URL after live, Hold after strip) is dirty: rewrite, do not act. **If the card and WAVEBOARD are idle, unsubscribe and do not resubscribe.**
78
78
  - **Board clock:** PR events + resume the same critic. Not two idle pacers. Merge after PASS+CI (gate A). Publish only after mill-gate D + `foundry gate`.
79
- - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `SEATS.md` Reviewer. Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
- - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Capture priority: a law is an invariant you would otherwise re-read the source to relearn. One law per subsystem bone. Heat touches last_seen and does not append a confidence sample, so more hits do not raise conviction. Heat touches last_seen when the diary contains that signal's name or a local clause of four definition content words; two definition words are not a hit; the same words scattered through a long diary are not a hit; a weak session score is not lifted to 0.55 and a sample below 0.55 is not recorded. Constructing the organ does not append workspace samples. Hero names: `heat-is-not-conviction`, `inference-cycle-invariant`, `governance-vote-invariant`, `thin-dispatch-invariant`. Repertoire mergeStackOverlay refreshes a changed stack definition and keeps observation stats. A floor observation count does not change a route. Feedback moves conviction by a tenth, and a failure can leave 0.55. learned-conviction.json beside dest restores that average when a wake flattens it to 0.55. It does not store the observation count.
79
+ - **Dispatch:** ticket + PR URLs + “Wear, then review.” The critic Reads `grok-bot/OP-PROC.md` (team specifics live in `house/`). Do not paste a command novel. When a law is spoken twice, encode it this wake.
80
+ - **Cascade:** Chat is not the brain. A cascade that must survive compaction is a named repertoire signal on the stack overlay, hydrated onto the project law list. NOTES holds the same cascade for the second Read. Station stays the ticket. A reflection is not this capture. Memory scoring rules: [docs/memory-scoring.md](https://github.com/0xRayAI/xray/blob/main/docs/memory-scoring.md).
81
81
  - **Cold brief:** a new critic or any new subagent that does not already have this thread gets the latest commit SHA on the branch under review (fetch it; do not reuse an earlier SHA from a previous pass) and the Station card (`.xray/state/STATION.md`: intent, plan, git). If the card is missing, give branch + HEAD + what just changed. If the branch moves after you brief them, send the new SHA before they verdict.
82
82
  - **Control:** The lead keeps control. Do not assume the subagent has the context. Give the duty, the latest SHA, the Station card, and the laws that apply. The subagent wears the applicable 0xRay suit before it works: the tree under review, built and installed. An older published package is not that suit. The lead checks the result.
83
83
 
@@ -96,7 +96,7 @@ This suite is the engine that builds the engine. When a seat sees OP-PROC, write
96
96
 
97
97
  Operating planes: code, OP-PROC, model, suit, mill, host, and test/ship. Test/ship is the critical OP-PROC plane. Test then ship is the hero. Ship without that proof is the catastrophe. Long-term memory is the project law list. Each wake refreshes a changed stack definition and keeps observation stats. Heat writes the matched names onto Station, the short-term card that survives compaction. Reactive decisions move out of TypeScript into OP-PROC as the model improves. That move is why the mill and the suit exist. It is not fully proved. Once a version is live, the stamper strips every present-tense patch pin from shipped guides and shipped OP-PROC, or reconcile advances the next cut. The stamper does not edit Station, NOTES, dest, or node_modules. It does not publish. Do not freeze the live cut.
98
98
  - **Close:** loop until Station is done. Compact: Station survives the cut. Overlay dest names are OP-PROC — reload `repertoire-working.json` `opProcNames`, not Station.
99
- - **Board:** critic Strict comments; forge implements; lead stays main thread.
99
+ - **Board:** critic Strict comments; the implementer implements; lead stays main thread.
100
100
  - **Codex 69:** rewire this skill and existing ops. Do not add a new `SKILL.md` to hold the cadence.
101
- - **Ship matrix:** `LEAD-CADENCE.md` Decision matrix — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
101
+ - **Ship matrix:** `grok-bot/OP-PROC.md` Decision matrix (team specifics live in `house/`) — A PR+CI · B pack · C `release:docs-check` (`reconcile --check`; no patch stamps on guides) · D `foundry release --i-mean-it`. Green CI is not ship. Spend / credentials stay Ask-first. Patch number lives in `package.json` + CHANGELOG.
102
102
  - **Metamorphosis:** LLM → OP-PROC is in-context worn seats (same critic, same dummy, resume only). Not more bots.
@@ -96,7 +96,7 @@ codex_terms: [5, 7, 32] # Related Codex term numbers
96
96
  ```markdown
97
97
  ## What Next?
98
98
 
99
- - Related Codex terms: [codex.json](../../../../.xray/codex.json)
99
+ - Related Codex terms: [codex.json](../../../.xray/codex.json)
100
100
  - Next story to write: [suggestion]
101
101
  ```
102
102
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "$schema": "./features.schema.json",
3
- "version": "4.0.25",
3
+ "version": "4.0.27",
4
4
  "description": "0xRay Framework - Unified Feature Configuration",
5
5
  "suit_temperament": {
6
6
  "profile": "auto",