Repository navigation
fix: share the primary TypeSafe key across local secondmate homes - #42
Merged
Merged
Conversation
fm_typesafe_key now falls back from the process environment and the home .env to the .env of the top-most local home reached through the existing .fm-secondmate-parent record, so lane homes and their crews share one key without copies. The Jev guardrail, dispatch resolver, skill picker and bootstrap validation all use the same accessor. fm_firstmate_root_home moves to the parent-record library so the TypeSafe library can use it without the wake library's setup.
…l-time key bin/fm-jev-belay-hook.sh resolves the TypeSafe key with fm_typesafe_key and sets it only for the belay.mjs process it execs, so the key stays out of Claude's environment, files and argv. belay.mjs is read from a pinned clone under the primary home and runs only when its blob id matches the pin. bin/fm-spawn.sh registers the wrapper in the Stop group of each ship and scout worker's settings.local.json; other sessions are untouched.
…y-source fixtures
Owner
Author
Deviation from upstream hyper-jev
|
This was referenced Oct 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Intent
why do you think I need to continually re-enter my key???? we have an .env file. It is horrible engineering prctice to copy keys all over the place and makes management impossible.
Jev key is found under typesafe
Context: the captain wants Jev used across the fleet, using the references he provided as-is (https://github.com/valentynkit/jev-belay, https://github.com/kunchenguid/compact-adviser for compaction, https://github.com/disler/ten-levels-of-jev) and modified only where our codebase forces it. The main Firstmate home's .env (~/firstmate/.env) holds TYPESAFE_API_KEY. Today every Jev consumer in the 7 Vernant lane secondmate homes logs missing_key (57 guardrail picks, 0 Jev answers) because bin/fm-typesafe-lib.sh fm_typesafe_key reads only /.env, and the lane homes have no .env. Firstmate earlier asked the captain to re-enter the key and proposed copying it into each home; the captain rejected both.
What Changed
.env; use the shared resolver in bootstrap and Jev guardrails without copying keys.Risk Assessment
✅ Low: The changes reuse existing credential, parent-record, privacy-policy, and timeout boundaries, implement the recorded decisions, and revealed no substantiated material defect in the full source review.
Testing
The focused key-source and lifecycle regressions passed, and live CLI checks demonstrated seven-home key sharing without copies, precedence and rotation, confidential-request withholding, pinned-vendor safeguards, and completion publication before Claude’s deadline. Product transcripts, HTTP receipts, state observations, and regression logs were preserved; three native Claude attempts were blocked by TLS trust-chain errors, and all disposable resources were removed.
Evidence: Live product CLI transcripts and HTTP receipts
Source: Live product CLI transcripts and HTTP receipts
Evidence: Seven-home skill advice output
Source: Seven-home skill advice output
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 2 issues found → auto-fixed ✅
bin/fm-spawn.sh:4777- The already-approved Round 2 Stop correction is still absent from the reviewed source; this does not challenge that decision. The generated command still uses|| exit $?, skipping completion for every nonzero result, although only exit 2 rejects Stop. It also retains a 25-second host deadline while the wrapper permits upstream's ambient JEV_BELAY_TIMEOUT_MS. A worker configured with 60000 can edit without verification, encounter an unresponsive TypeSafe request, and have Claude cancel the hook before either completion write, leaving the completed worker classified as busy. Apply the authorized correction at this shared Stop boundary: preserve rejection only for exit 2 and internally bound execution so nonblocking failure completion runs before the host deadline. Related sites: bin/fm-spawn.sh:4782 (host timeout), bin/fm-jev-belay-hook.sh:48 (unbounded execution retaining upstream timeout configuration), bin/fm-jev-belay-policy.mjs:14-24 (synchronous policy child without a deadline), docs/configuration.md:1598 (completion contract), and tests/fm-busy-adapter-wiring.test.sh:314,330 (current coverage exercises only rejection 2 and acceptance 0)..agents/skills/hyper-jev/FIRSTMATE.md:2- The captain-authorized fallback sentence is correctly retained, but the accompanying required instruction remains unimplemented. The recorded decision requires: "add one line next to it ... recording this as a captain-ordered deviation from upstream SKILL.md lines 20-21 ... citing those two quoted captain statements." The changed overlay contains "TypeSafe direct first; fall back to OpenRouter when the direct call is unavailable or fails" without that provenance line. Add the required adjacent plain-dash sentence citing "it falls back to openrouter" and "regarding openrouter and Jev, I already indicated that openrouter is a fallback from directly using the typesafe api"; retain the authorized fallback behavior unchanged.🔧 Fix applied.
✅ Re-checked - no issues remain.
🔧 **Test** - 2 issues found → auto-fixed ✅
tests/fm-typesafe-key-source.test.sh:162- The targeted key-source regression exited 1 at "absent policy must allow both actual fetch requests". Its synthetic vendor suppresses fetch exceptions, and cleanup removed the failed request receipts, leaving the cause unresolved. A focused diagnostic subsequently completed both requests with successful policy children taking 671 ms and 249 ms; the real pinned belay integration also passed. These observations do not establish the original cause or justify ignoring the failure. Preserve the fetch exception and policy-child status/timing in the regression, then resolve whether this is fixture flakiness or unintended withholding. Evidence: fm-typesafe-key-source.log and policy-regression-diagnostic.json in the run evidence directory.bash tests/fm-typesafe-key-source.test.shwith worktree-local TMPDIR: failed the two-request assertion.bash tests/fm-busy-adapter-wiring.test.shwith worktree-local TMPDIR: passed, including rejection, nonblocking failures, and timeout completion.python3 .live-validation/consumers.py: executed the real guardrail, dispatch resolver, and skill adviser from seven lane homes and a nested descendant; exercised rotation, precedence, invalid ancestry, missing keys, and privacy withholding.curl -q -fsSL https://raw.githubusercontent.com/valentynkit/jev-belay/ef719db7eaadc56aa4def86c4da4ffff5bcbca35/belay.mjsfollowed bygit hash-object: obtained the unchanged upstream implementation and verified the required blob.python3 .live-validation/belay-live.py: executed generated Stop commands with the real pinned belay, busy-state writer, classifier, and loopback HTTPS transport.python3 .live-validation/credential-probe.py: observed actual external commands while forwarding execution unchanged; checked exported public/private credentials, precedence, and argv isolation.bash .live-validation/diagnose-policy.sh: diagnosed the failed two-request path with credential-free policy-child timing/status observations.python3 .live-validation/native-claude.py: attempted a real Claude print-mode primary on a private 120×40 tmux session, then retried with system CA trust and a disposable bundle of existing public system certificates.Stopped the disposable HTTPS service, tore down every private native-primary session and socket, and removed all worktree fixtures, including protected generated Git-hook directories.🔧 Fix applied.
✅ Re-checked - no issues remain.
bash tests/fm-typesafe-key-source.test.shwith workspace-contained TMPDIR; preserved the diagnostic regression output.bash tests/fm-busy-adapter-wiring.test.shwith workspace-contained TMPDIR.node bin/fm-jev-guardrail.mjs hook --host claudeacross seven isolated secondmate-shaped homes, plus nested, precedence, rotation, absent-key, remote, malformed, cyclic, and unreachable-parent cases.bin/fm-skill-suggest.sh --task-file <disposable-task> --catalog <disposable-public-catalog>across all seven homes using real curl against an isolated HTTPS service.bin/fm-dispatch-resolve.sh <disposable-task> --project disposable-pageracross all seven homes using an isolated HTTPS service and disposable quota dataset.bin/fm-jev-belay-hook.shwith the unmodified pinned upstream belay executable: rejection, verification, consecutive permitted requests, confidential task/final/check text, invalid and unreadable policy, HTTP failure, timeout, missing key/vendor, and vendor tampering.Generated actual Claude hook settings throughfm-spawn.sh, then executed their commands withsh -c: observed real busy state and turn-ended markers for rejection, accepted continuation, HTTP failure, request timeout, and stalled policy checking.Observed credential presence in wrapper utility children while executing the real pinned vendor; inspected generated configuration and persisted state for synthetic-key copies.Launched genuine Claude three times throughbin/fm-herdr-lab.shinfm-lab-native-stop-65931: default transport, retained machine proxies, and system-CA flags; captured API errors and lifecycle state.Tore down the owned Herdr session through the lab helper, shut down both local HTTPS fixtures, and removed all disposable worktree fixtures.✅ **Document** - passed
✅ No issues found.
🔧 **Lint** - 1 issue found → auto-fixed ✅
🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Push** - passed
✅ No issues found.