Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
plugins/session-relay/bin/relay-* binary
31 changes: 21 additions & 10 deletions docs/plans/active/session-relay-rust-port.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
---
title: Port session-relay to a single Rust binary (zero-runtime, both tools)
goal: Replace session-relay's Node payload with one static Rust `relay` binary (4 committed arches + sh launcher) so a Codex host needs no Node, enabling kernel flock locking.
status: blocked
status: in_review
created: "2026-07-01T15:56:09-03:00"
updated: "2026-07-01T19:26:34-03:00"
updated: "2026-07-01T20:12:14-03:00"
started_at: "2026-07-01T17:56:26-03:00"
assignee: claude
blocked_reason: "waiting on maintainer: merge explore/rust-port-and-okf to main, then dispatch build-binaries.yml (workflow_dispatch only lists workflows present on the DEFAULT branch) and hand the 4 artifacts to step 7"
blocked_since: "2026-07-01T19:26:34-03:00"
tags: [rust, session-relay, plugin, cross-tool, build, ci]
affected_paths:
- plugins/session-relay/rust/
Expand All @@ -28,11 +26,14 @@ affected_paths:
- .github/AGENTS.md
- .gitattributes
- scripts/lib/plugins.mjs
- scripts/lib/rust-bin.mjs
- scripts/AGENTS.md
- scripts/ci.mjs
- scripts/release.mjs
- .gitignore
related_plans: [session-relay-cross-tool-bus, session-relay-auto-discovery]
review_status: null
review_status: partial
in_review_since: "2026-07-01T20:07:05-03:00"
planned_at_commit: "7ee6a0de28bdae9109282cfba3acc5803df69242"
---

Expand Down Expand Up @@ -74,7 +75,7 @@ Replace session-relay's five store-touching Node `.mjs` files with **one statica
```sh
#!/bin/sh
# relay — arch-dispatch launcher for the session-relay Rust binary.
d=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
d=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
case "$(uname -sm)" in
'Darwin arm64') exec "$d/relay-aarch64-apple-darwin" "$@" ;;
'Darwin x86_64') exec "$d/relay-x86_64-apple-darwin" "$@" ;;
Expand Down Expand Up @@ -115,16 +116,16 @@ Replace session-relay's five store-touching Node `.mjs` files with **one statica
| 4 | Port the rest preserving every tested invariant: `discover.rs` (stat-then-content, `UUID_RE` gate, cwd-from-content, Codex `session_meta`, `READ_CAP=65536`, root env resolution), `cli.rs` wake (`--` fencing, UUID gate on `--id` AND resolved-name, refuse-if-dir-missing), `hook.rs` (`<session-relay-mail>` fence + `defuse()`), `bus.rs` (JSON-RPC lifecycle, 6 tools, `2025-06-18`, `RELAY_PROJECT_DIR` fallback, **stdout purity: ONLY JSON-RPC frames on stdout, ALL diagnostics to stderr** — normative MCP-stdio MUST; mirrors `bus.mjs:21,138` — AND the send/discover hint strings formerly at `bus.mjs:111,130` — now pointing at `<plugin>/bin/relay wake`) | `plugins/session-relay/rust/src/{discover,cli,hook,bus}.rs`, `src/main.rs`, `rust/tests/bus_smoke.rs` (added: black-box MCP lifecycle smoke) | 3 | done |
| 5 | Wire the toolchain: session-relay descriptor gains a build capability; `ci.mjs`'s Rust leg runs `cargo fmt --check` + `cargo clippy --all-targets -- -D warnings` + builds ONLY the host leg (`cargo build --release --locked` → `bin/relay-<hostTarget>`) and verifies committed `SHA256SUMS` BEFORE the self-test — **skipping that check with a printed notice while `bin/` holds no committed binaries** (they land in step 7, so the gate stays green between steps 5 and 7); `release.mjs` does **not** build darwin — it asserts all 4 committed binaries exist + `sha256sum -c` passes, then bumps+tags. Implemented as a `rust: { dir, bin, binName, targets }` descriptor capability + shared `scripts/lib/rust-bin.mjs` (`rustHostTarget`/`findCargo`/`verifySha256Sums` — Node-crypto verify, no `sha256sum` dep); release also asserts the launcher + exec bits; confirmed locally that the musl host leg builds with only `rustup target add` (static-pie, no musl-gcc needed) | `scripts/lib/plugins.mjs`, `scripts/lib/rust-bin.mjs`, `scripts/ci.mjs`, `scripts/release.mjs`, `scripts/AGENTS.md` | 3, 4 | done |
| 6 | Rewrite the tests + docs against the host-leg binary (manifests still on Node — nothing consumer-facing flips yet): self-test black-box subset spawns `bin/relay` (host leg from step 5) — seed the cwd→id marker by piping a synthesized SessionStart event into `bin/relay hook`, seed **named** registrations via the `relay register` CLI subcommand; white-box store internals + the 8×10 cross-process stress move to `cargo test`; add read-only `relay peek <id>` for the remaining store assertions; rewrite ALL `SKILL.md` path strings (`:32,40,46,59,76,97,98,126` — every `relay.mjs` and `mcp/bus.mjs` mention, including the `codex mcp add` example) + rebump `content_hash` via `node scripts/skills/content-hash.mjs --backfill`. Done: 39-check selftest all through the binary (skip-with-notice if `bin/` empty on a cargo-less box); the `## Verify` line (`node test/selftest.mjs`) intentionally unchanged — the selftest stays a Node *harness* driving the binary; `list` awk example field `$3`→`$4` (Rust list interposes `[tool]`) | `test/selftest.mjs`, `rust/src/{cli,main}.rs` (`peek`), `skills/productivity/session-relay/SKILL.md` | 4, 5 | done |
| 7 | Land the consumer-facing flip in ONE atomic commit: add the `bin/relay` sh launcher; commit the 4 arch binaries from `build-binaries.yml` artifacts + `SHA256SUMS` (all five `bin/` entries **mode 100755**); add the repo-root `.gitattributes` line; flip ALL FOUR manifests **per the Interfaces table** — Claude `plugin.json` MCP + `hooks.json` (exec form) on `${CLAUDE_PLUGIN_ROOT}`, `codex-hooks.json` shell form, `bus.mcp.json` on **native `${PLUGIN_ROOT}`** | `bin/{relay,relay-*,SHA256SUMS}`, `.gitattributes`, the 4 manifests | 6 | planned |
| 8 | Delete the now-unreferenced Node payload and finalize: `git rm` the five superseded `.mjs`; run the full gate | `git rm plugins/session-relay/{mcp/bus.mjs,lib/store.mjs,lib/discover.mjs,hooks/session-start.mjs,skills/productivity/session-relay/scripts/relay.mjs}` | 7 | planned |
| 7 | Land the consumer-facing flip in ONE atomic commit: add the `bin/relay` sh launcher; commit the 4 arch binaries from `build-binaries.yml` artifacts + `SHA256SUMS` (all five `bin/` entries **mode 100755**); add the repo-root `.gitattributes` line; flip ALL FOUR manifests **per the Interfaces table** — Claude `plugin.json` MCP + `hooks.json` (exec form) on `${CLAUDE_PLUGIN_ROOT}`, `codex-hooks.json` shell form, `bus.mcp.json` on **native `${PLUGIN_ROOT}`** . Done: binaries from build-binaries run 28552485456 (all 4 transit checksums OK); launcher shellcheck-linted (SC1007 fix: `CDPATH=''`) and smoke-tested (dispatches to the musl leg); exec bits verified in the git INDEX (Write had staged the launcher 100644 — the exact EACCES gotcha; re-chmodded) | `bin/{relay,relay-*,SHA256SUMS}`, `.gitattributes`, the 4 manifests, `scripts/{ci.mjs,lib/rust-bin.mjs,lib/plugins.mjs,AGENTS.md}` | 6 | done |
| 8 | Delete the now-unreferenced Node payload and finalize: `git rm` the five superseded `.mjs`; run the full gate | `git rm plugins/session-relay/{mcp/bus.mjs,lib/store.mjs,lib/discover.mjs,hooks/session-start.mjs,skills/productivity/session-relay/scripts/relay.mjs}` | 7 | done |

## Acceptance criteria

- **Build (host):** `cargo build --release --locked --manifest-path plugins/session-relay/rust/Cargo.toml` exits 0.
- **Lint (Rust):** `cargo fmt --check --manifest-path plugins/session-relay/rust/Cargo.toml` → exit 0, no diff; `cargo clippy --all-targets --manifest-path plugins/session-relay/rust/Cargo.toml -- -D warnings` → exit 0.
- **All 4 arches committed:** `ls plugins/session-relay/bin/` shows `relay` + `relay-x86_64-unknown-linux-musl` + `relay-aarch64-unknown-linux-musl` + `relay-x86_64-apple-darwin` + `relay-aarch64-apple-darwin` + `SHA256SUMS`.
- **Integrity:** `cd plugins/session-relay/bin && sha256sum -c SHA256SUMS` → every line `OK` (integrity of the committed set; reproducibility is a separate criterion below).
- **Reproducible host leg:** rebuilding the host target with the `rust-toolchain.toml`-pinned compiler + `--locked` + `--remap-path-prefix` yields a digest identical to the committed `relay-<hostTarget>` line in `SHA256SUMS` (tamper-evidence, not just self-consistency — achievable because toolchain, deps, and `codegen-units=1` are all pinned).
- **Reproducible host leg (CI-enforced):** `ci.mjs` rebuilds the host target (pinned toolchain, `--locked`) and compares digests against the committed binary: byte-identity is a **FAIL in CI** (`process.env.CI` — the runner shares the producer workflow's image) and a warn locally. Empirically (2026-07-01): CI musl digest `56ba41…` vs local `79e08e…` — binaries embed build paths + host-linker output, so cross-machine byte-identity is unachievable without `--remap-path-prefix` AND an identical linker; the CI-side check delivers the tamper-evidence where it is authoritative. The committed binary is never overwritten by the gate.
- **Full gate:** `node scripts/ci.mjs` → exits 0, ends `✔ All ci.mjs checks passed`.
- **Rust tests:** `cargo test --manifest-path plugins/session-relay/rust/Cargo.toml` → `test result: ok`, including the cross-process lock race test.
- **Ported self-test:** `node plugins/session-relay/test/selftest.mjs` → `PASS` over the black-box subset enumerated in Step 6, exit 0, spawning `bin/relay` (grep the file: no `spawnSync('node'` and no `import .*lib/store`).
Expand Down Expand Up @@ -201,7 +202,17 @@ Red-team caught and fixed: (1) **no producer for the two darwin binaries** — r

## Review

(filled by plan-review on completion)
- **Goal met:** partial — every headless acceptance criterion passes: `cargo build --release --locked`, `cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, and `cargo test` (incl. the cross-process `concurrent_writers_no_lost_or_torn_writes` lock race + `legacy_lock_dir_is_migrated_to_a_file`) all exit 0; `node scripts/ci.mjs` is green; the 39-check selftest PASSes through `bin/relay` (no `spawnSync('node')`, no `import lib/store`); all four manifests are flipped per the Interfaces table (Claude `plugin.json`/​`hooks.json` on `${CLAUDE_PLUGIN_ROOT}`, Codex `bus.mcp.json` on native `${PLUGIN_ROOT}` with zero `CLAUDE_PLUGIN_ROOT`, no `command:"node"`); all 4 arch binaries + launcher are committed `100755` with `sha256sum -c` all OK; the five Node `.mjs` are deleted with no live code references (only plan-doc + Rust `// port of …` mentions remain); tag-CI glob broadened to `*--v*`. Two criteria are inherently un-runnable headlessly and remain OPEN: the **live cross-tool round-trip** on real Claude+Codex sessions, and the **Codex `${PLUGIN_ROOT}` command-field substitution on a real install** (carries a STOP condition) — clear both on live sessions before ship.
- **Regressions:** none — no code/gate criterion failed; the local host-rebuild digest mismatch is the plan's designed CI-only byte-identity gate (warn locally, enforced only under `process.env.CI`), not a regression.
- **CI:** pass — `node scripts/ci.mjs` exits 0, ends `✔ All ci.mjs checks passed — 2 plugin(s) + repo-wide; safe to release.`
- **Follow-ups:** session-relay-binary-commit-bot, context-tree-nudge-rust-port, session-relay-windows-arch, session-relay-tag-time-arch-verify
- Filed by: plan-review (completion review, in_review) on 2026-07-01T20:12:14-03:00

## Mistakes & Dead Ends

- **2026-07-01T20:05-03:00**: Expected local host rebuild to match CI's committed binary byte-for-byte (pinned toolchain + `--locked` + `codegen-units=1`) → digests differ (`56ba41…` CI vs `79e08e…` local): binaries embed absolute build/registry paths and the distro linker's output → don't chase cross-machine reproducibility with `--remap-path-prefix` (linker still differs); enforce byte-identity only in CI (same image as producer) and warn locally.
- **2026-07-01T20:05-03:00**: Launcher used the classic `CDPATH= cd` idiom → shellcheck SC1007 warning failed the gate (launcher is now linted via `shellHooks`) → use the explicit `CDPATH=''` empty-string form.
- **2026-07-01T20:10-03:00**: Wrote the launcher with the Write tool and staged it → landed `100644` in the index (the plan's own EACCES gotcha) → always verify `git ls-files -s`, not `ls -l`, after creating executables.

## Sources

Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
---
title: Adopt LLM-Wiki Lint checklist + OKF/Karpathy prior-art citations
goal: Fold Karpathy's LLM-Wiki Lint checks into context-tree audit + skill-maintenance drift, and cite OKF + Karpathy LLM-Wiki as convergent prior art — no vendoring.
status: in_review
status: finished
created: "2026-07-01T15:56:09-03:00"
updated: "2026-07-01T17:36:35-03:00"
updated: "2026-07-01T19:42:16-03:00"
in_review_since: "2026-07-01T17:34:39-03:00"
started_at: "2026-07-01T17:31:29-03:00"
assignee: claude
Expand All @@ -15,6 +15,7 @@ affected_paths:
- plugins/docks/skills/productivity/write-skill/SKILL.md
related_plans: []
review_status: passed
ship_commit: "9e7a7329080ef2b52058ef2c09de8527b9d44494"
planned_at_commit: "7ee6a0de28bdae9109282cfba3acc5803df69242"
---

Expand Down Expand Up @@ -116,11 +117,11 @@ Red-team caught and fixed: (1) acceptance criterion 1's Lint grep false-passed o

## Review

- **Goal met: yes** — work commit `4303561` lands both slices: the LLM-Wiki graph Lint (5 checks) in `context-tree audit` (op row L36, workflow bullet L103, Graph Lint table in `references/conflict-resolution.md`) plus the two per-skill drift rows in `skill-maintenance` (intra-skill contradiction + stale-claim), and the OKF/Karpathy prior-art citations in `write-skill:184` + `context-tree:13`. All 5 acceptance criteria pass (five per-check Lint greps exit 0; citations grep matches both files; `never writes` present + audit op-row `Writes? = no` + no write-verb on audit; no `upstream:` blocks). Scope clean: `git show 4303561 --stat` touches only the 3 skills' 4 files; CSO `description:` frontmatter unchanged; graph-only checks kept out of `skill-maintenance`; nothing vendored.
- **Regressions:** none — no source-anchored claim in the touched skills failed reproduction; `content_hash` re-synced on all three skills.
- **CI:** pass — `node scripts/ci.mjs` exits 0, including `docks skill content_hash in sync` and `docks skill frontmatter valid`.
- **Goal met: yes** — completion re-review after HEAD moved to `9e7a732` (rust-port commits landed on the branch). The scoped diff `7ee6a0d..HEAD` for this plan's four paths is intact and unchanged from work commit `4303561`: the LLM-Wiki graph Lint (5 checks) in `context-tree audit` (op row L36, workflow bullet L103, Graph Lint table in `references/conflict-resolution.md`), the two per-skill drift rows in `skill-maintenance` (intra-skill contradiction + stale-claim), and the OKF/Karpathy prior-art citations in `write-skill:184` + `context-tree:13`. All 5 acceptance criteria re-run and pass (five per-check Lint greps exit 0; citations grep matches both files; `never writes` present + audit op-row `Writes? = no` + no write-verb on audit; no `upstream:` blocks). `content_hash` re-synced on all three skills; CSO `description:` frontmatter unchanged.
- **Regressions:** none — the newer rust-port commits (`9e7a732`, `f1795c7`, `4495b29`, `08c400e`, `20c2ee8`, …) are scoped to `plugins/session-relay/rust`, `scripts/`, `.github/`, and plan files; disjoint from this plan's four files. Scoped `git diff --stat 7ee6a0d..HEAD` still touches only the 3 skills' 4 files.
- **CI:** pass — `node scripts/ci.mjs` exits 0, including `docks skill content_hash in sync` and `docks skill frontmatter valid`; the session-relay Rust leg (`cargo fmt --check` / `clippy -D warnings`) is clean, and the only warn-skip is the not-yet-committed `plugins/session-relay/bin/SHA256SUMS` checksum verify (binaries land via `build-binaries.yml`) — out of this plan's scope, not a regression.
- **Follow-ups:** none.
- **Filed by:** plan-review (completion) 2026-07-01T17:36:35-03:00
- **Filed by:** plan-review (completion re-review, HEAD moved) 2026-07-01T19:38:33-03:00

## Sources

Expand Down
4 changes: 2 additions & 2 deletions plugins/session-relay/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
"hooks": "./hooks/hooks.json",
"mcpServers": {
"bus": {
"command": "node",
"command": "${CLAUDE_PLUGIN_ROOT}/bin/relay",
"args": [
"${CLAUDE_PLUGIN_ROOT}/mcp/bus.mjs"
"bus"
],
"env": {
"RELAY_PROJECT_DIR": "${CLAUDE_PROJECT_DIR}"
Expand Down
4 changes: 2 additions & 2 deletions plugins/session-relay/.codex-plugin/bus.mcp.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
{
"mcpServers": {
"bus": {
"command": "node",
"args": ["${CLAUDE_PLUGIN_ROOT}/mcp/bus.mjs"]
"command": "${PLUGIN_ROOT}/bin/relay",
"args": ["bus"]
}
}
}
4 changes: 4 additions & 0 deletions plugins/session-relay/bin/SHA256SUMS
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
9599a0fb9f30683bba04cd0e2f5413a2e3d1acbbe940d4be850f818b3f0a9f54 relay-aarch64-apple-darwin
692ff0e7f254d770b51d50ebcb1c14e9bf234167143f99f29c36a13c8783d779 relay-aarch64-unknown-linux-musl
7bd8ecffd2fdf520a8fe30b7916bf7a1377cd20ec5e2e7274b0f229ecb2ba38a relay-x86_64-apple-darwin
56ba414130d756a2aacbf5e03f42ccfb23a1ef883c77b9dcb8cee9c901024504 relay-x86_64-unknown-linux-musl
10 changes: 10 additions & 0 deletions plugins/session-relay/bin/relay
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/bin/sh
# relay — arch-dispatch launcher for the session-relay Rust binary.
d=$(CDPATH='' cd -- "$(dirname -- "$0")" && pwd)
case "$(uname -sm)" in
'Darwin arm64') exec "$d/relay-aarch64-apple-darwin" "$@" ;;
'Darwin x86_64') exec "$d/relay-x86_64-apple-darwin" "$@" ;;
'Linux aarch64') exec "$d/relay-aarch64-unknown-linux-musl" "$@" ;;
'Linux x86_64') exec "$d/relay-x86_64-unknown-linux-musl" "$@" ;;
*) echo "session-relay: unsupported platform $(uname -sm)" >&2; exit 1 ;;
esac
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion plugins/session-relay/hooks/codex-hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\" codex",
"command": "\"${CLAUDE_PLUGIN_ROOT}/bin/relay\" hook codex",
"statusMessage": "session-relay: registering + draining inbox"
}
]
Expand Down
3 changes: 2 additions & 1 deletion plugins/session-relay/hooks/hooks.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"hooks": [
{
"type": "command",
"command": "node \"${CLAUDE_PLUGIN_ROOT}/hooks/session-start.mjs\"",
"command": "${CLAUDE_PLUGIN_ROOT}/bin/relay",
"args": ["hook"],
"statusMessage": "session-relay: registering + draining inbox"
}
]
Expand Down
Loading