Skip to content

feat(harness): cloud session boot + mandatory karpathy/btoo priming + shared volume#16

Open
FlexNetOS wants to merge 1 commit intomainfrom
claude/tender-lewin-81f793
Open

feat(harness): cloud session boot + mandatory karpathy/btoo priming + shared volume#16
FlexNetOS wants to merge 1 commit intomainfrom
claude/tender-lewin-81f793

Conversation

@FlexNetOS
Copy link
Copy Markdown
Owner

@FlexNetOS FlexNetOS commented May 3, 2026

Summary

Three coordinated additions land in one shippable change:

  • Cloud session boot — new scripts/setup.js orchestrator: materializes .env, runs install, pre-warms MCP, populates the shared volume, runs verify. Wired as both initializeCommand (host-side) and postCreateCommand (container-side) so a fresh clone boots in one command.
  • Mandatory standards priming — new UserPromptSubmit hook (scripts/hooks/btoo-directives.js) injects /karpathy-guidelines (4 rules) and the Boil-the-Ocean completeness standard (verbatim user phrasing) on every turn as additionalContext. Profile-gated via ECC_HOOK_PROFILE / ECC_DISABLED_HOOKS. Stop-gate auditing remains owned by PromptNexus.
  • Cross-container shared volumeclaude-shared-state docker named volume mounts at /mnt/claude-shared (lives on the WSL2 .vhdx). scripts/lib/shared-volume.js populates it from a reachable PromptNexus clone. Sibling containers see the same hooks, schemas, and verdict history.

Files

  • New (11): scripts/setup.js, scripts/lib/{mcp-prewarm,shared-volume}.js, scripts/hooks/btoo-directives.js, commands/karpathy-guidelines.md, docs/{STANDARDS-ENFORCEMENT,CONTAINER-PERSISTENCE}.md, plus 4 test files.
  • Edited (11): .devcontainer/{devcontainer.json,postCreate.sh}, .env.example, hooks/hooks.json, agent.yaml, CLAUDE.md, AGENTS.md, README.md, README.zh-CN.md, docs/zh-CN/{AGENTS,README}.md (catalog count 68 to 69).

Architecture decisions

  • Stop-gate is NOT vendored into agent_harness. PromptNexus owns enforcement (Haiku-flagged auditor); agent_harness consumes via the shared volume. Avoids drift; cross-container access solves the reachability problem.
  • Named volume over host bind-mount. Bind-mounts fail in cloud sessions where the host has no prompt_hub clone; named volumes are portable.
  • Priming visibility: when the shared volume is unpopulated, the directive injection says `Stop-gate: inactive` so Claude knows audit is not running — no silent half-shipping.

Test plan

  • `node tests/run-all.js` — 2255 pass / 5 fail. All 5 failures are pre-existing (build-opencode, opencode-plugin-hooks, npm-publish-surface, resolve-formatter on Windows). Verified by running tests with my changes stashed: baseline was 2222/6, after this PR is 2255/5. Net: +33 passing, -1 failing, 0 new failures. (The -1 is validators.test.js, which the catalog:sync this PR runs actually fixes.)
  • All 31 new tests pass individually and via run-all.
  • node scripts/ci/validate-hooks.js — 27 matchers OK
  • node scripts/ci/validate-commands.js — 69 OK
  • node scripts/ci/validate-no-personal-paths.js — clean
  • node scripts/ci/check-unicode-safety.js — clean
  • npm run catalog:sync — counts in sync
  • markdownlint — new docs clean
  • End-to-end smoke: `echo '{}' | node scripts/hooks/run-with-flags.js user-prompt-submit:btoo-directives scripts/hooks/btoo-directives.js standard,strict` produces JSON envelope with Karpathy + Boil-the-Ocean text.
  • `node scripts/setup.js --init-env-only` exits 0 and idempotently materializes .env.
  • Devcontainer end-to-end (deferred until host Docker repair completes per existing project memory).
  • Cross-container verdict round-trip (deferred to post-host-repair; runbook in CONTAINER-PERSISTENCE.md).

Out of scope

  • No changes to PromptNexus.
  • No changes to ~/.claude/settings.json.
  • No CI wiring (hooks are session-time only).

🤖 Generated with Claude Code


Open in Devin Review

… cross-container shared volume

Three coordinated additions land in one shippable change:

1. Cloud session boot (scripts/setup.js)
   - Idempotent orchestrator: materializes .env from .env.example, runs
     yarn install, pre-warms MCP servers from .mcp.json, populates the
     cross-container shared volume, runs npm run verify --skip-mcp.
   - Exposed as both a host-side initializeCommand (--init-env-only flag)
     and a container postCreate step.
   - postCreate.sh shrinks from 59 to ~15 lines by delegating.

2. Mandatory standards priming (scripts/hooks/btoo-directives.js)
   - New UserPromptSubmit hook injects /karpathy-guidelines (4 rules) and
     the Boil-the-Ocean completeness standard (verbatim user phrasing) on
     every turn as additionalContext.
   - Profile-gated via ECC_HOOK_PROFILE / ECC_DISABLED_HOOKS so it can be
     muted for diagnostics but is on by default.
   - Stop-gate enforcement remains in PromptNexus (Haiku-flagged auditor);
     this hook reports its availability so Claude knows whether the audit
     loop is active. Slash command /karpathy-guidelines surfaces the same
     content on demand.

3. Cross-container shared volume (claude-shared-state)
   - .devcontainer/devcontainer.json mounts a docker named volume at
     /mnt/claude-shared, which lives on the WSL2 .vhdx disk.
   - scripts/lib/shared-volume.js populates it from a reachable PromptNexus
     clone (PROMPT_NEXUS_PATH env var or standard fallbacks). Idempotent
     and gracefully no-ops when no source is present.
   - Lets sibling containers (prompt_hub, agent_harness, future projects)
     read the same hooks, schemas, and verdict history.

Tests: 31 new tests across 4 files, all passing.
- tests/lib/mcp-prewarm.test.js (7)
- tests/lib/shared-volume.test.js (9)
- tests/scripts/setup.test.js (5)
- tests/hooks/btoo-directives.test.js (10)

Validators green: 27 hook matchers, 69 commands, agent.yaml + catalog
in sync (README/AGENTS counts updated to 69).

Docs:
- docs/STANDARDS-ENFORCEMENT.md - two-tier enforcement design
- docs/CONTAINER-PERSISTENCE.md - shared-volume architecture and ops
- CLAUDE.md, AGENTS.md - cloud session + mandatory standards sections

Reused (not duplicated): scripts/hooks/run-with-flags.js (canonical
wrapper), scripts/lib/utils.js, schemas/hooks.schema.json, the existing
node-e plugin-root bootstrap pattern from hooks/hooks.json.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 82c0d68e74

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/setup.js
Comment on lines +206 to +208
if (!args.skipVerify) {
runVerify();
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Propagate verify failures as setup exit errors

main() always exits with 0 even when runVerify() reports a failed npm run verify, so provisioning can be marked successful while the harness is actually broken. This is a functional regression for any automation or devcontainer flow relying on scripts/setup.js exit status to detect readiness; currently the failure is only logged as a warning and then ignored.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 6 potential issues.

Open in Devin Review

Comment thread scripts/setup.js
Comment on lines +206 to +211
if (!args.skipVerify) {
runVerify();
}

log(`Done. Try: 'npm run verify' or 'claude mcp list'. Created .env: ${envResult.created}.`);
process.exit(0);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 setup.js ignores runVerify() return value, always exits 0 despite documented contract

The main() function in scripts/setup.js ignores the return value of runVerify() and unconditionally calls process.exit(0) at line 211. This contradicts the JSDoc at scripts/setup.js:14-15 which states "Exits 0 on success, 1 on hard failure (deps missing, verify fails)" and the caller .devcontainer/postCreate.sh:14-16 which says "It exits non-zero only on hard failures (deps missing, verify fails)." As a result, postCreate.sh:19's warning message ("WARN: scripts/setup.js exited non-zero") can never fire on verify failures, silently hiding boot-time verification problems.

Suggested change
if (!args.skipVerify) {
runVerify();
}
log(`Done. Try: 'npm run verify' or 'claude mcp list'. Created .env: ${envResult.created}.`);
process.exit(0);
if (!args.skipVerify) {
const verifyOk = runVerify();
if (!verifyOk) {
log('WARN: verify failed. Exiting non-zero so the caller can surface the issue.');
process.exit(1);
}
}
log(`Done. Try: 'npm run verify' or 'claude mcp list'. Created .env: ${envResult.created}.`);
process.exit(0);
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread hooks/hooks.json
Comment on lines +4 to +14
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node -e \"const p=require('path');const r=(()=>{var e=process.env.CLAUDE_PLUGIN_ROOT;if(e&&e.trim())return e.trim();var p=require('path'),f=require('fs'),h=require('os').homedir(),d=p.join(h,'.claude'),q=p.join('scripts','lib','utils.js');if(f.existsSync(p.join(d,q)))return d;for(var s of [[\\\"ecc\\\"],[\\\"ecc@ecc\\\"],[\\\"marketplace\\\",\\\"ecc\\\"],[\\\"everything-claude-code\\\"],[\\\"everything-claude-code@everything-claude-code\\\"],[\\\"marketplace\\\",\\\"everything-claude-code\\\"]]){var l=p.join(d,'plugins',...s);if(f.existsSync(p.join(l,q)))return l}try{for(var g of [\\\"ecc\\\",\\\"everything-claude-code\\\"]){var b=p.join(d,'plugins','cache',g);for(var o of f.readdirSync(b,{withFileTypes:true})){if(!o.isDirectory())continue;for(var v of f.readdirSync(p.join(b,o.name),{withFileTypes:true})){if(!v.isDirectory())continue;var c=p.join(b,o.name,v.name);if(f.existsSync(p.join(c,q)))return c}}}}catch(x){}return d})();const s=p.join(r,'scripts/hooks/plugin-hook-bootstrap.js');process.env.CLAUDE_PLUGIN_ROOT=r;process.argv.splice(1,0,s);require(s)\" node scripts/hooks/run-with-flags.js user-prompt-submit:btoo-directives scripts/hooks/btoo-directives.js standard,strict"
}
],
"description": "Inject /karpathy-guidelines and Boil-the-Ocean completeness standard as additionalContext on every user prompt. Mute via ECC_HOOK_PROFILE=minimal or ECC_DISABLED_HOOKS=user-prompt-submit:btoo-directives.",
"id": "user-prompt-submit:btoo-directives"
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 UserPromptSubmit hook entry lacks matcher field unlike all other non-tool hooks

The new UserPromptSubmit entry in hooks/hooks.json:4-14 does not include a "matcher" field. Every other non-tool-specific hook in the file (SessionStart, PreCompact, Stop, SessionEnd) includes "matcher": "*". Without access to the Claude Code hook schema (referenced at the top of hooks.json), it's unclear whether omitting matcher is valid for UserPromptSubmit events or if it would cause the hook to silently not fire. The existing pattern strongly suggests "matcher": "*" should be added for consistency and safety.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines 9 to 11
echo "[postCreate] Activating yarn 4.9.2 via corepack..."
corepack enable
corepack prepare yarn@4.9.2 --activate
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: postCreate.sh runs corepack twice — once directly, once via setup.js

Lines 9-11 of postCreate.sh call corepack enable and corepack prepare yarn@4.9.2 --activate directly. Then line 18 invokes node scripts/setup.js, which calls activateYarn() at scripts/setup.js:93-106 doing the exact same corepack commands again. This is idempotent and harmless but adds ~2-5 seconds of redundant work on every devcontainer build. The bash calls could be removed since setup.js now handles them, but the comment at line 3-5 suggests postCreate.sh intentionally keeps corepack setup in bash as a fallback in case setup.js fails before reaching that phase.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +22 to +27
const ASSETS_TO_COPY = [
{ type: 'dir', rel: 'hooks' },
{ type: 'file', rel: path.join('evals', 'verdict.schema.json') },
{ type: 'dir', rel: 'commands' },
{ type: 'dir', rel: 'evals/principles' }
];
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: ASSETS_TO_COPY uses inconsistent path construction

In scripts/lib/shared-volume.js:22-27, the ASSETS_TO_COPY array mixes path.join('evals', 'verdict.schema.json') on line 24 with a hardcoded forward-slash 'evals/principles' on line 26. While both work correctly because path.join normalizes forward slashes on all platforms, this inconsistency is a code smell. The convention in this file (and per AGENTS.md's cross-platform principle) would be to use path.join('evals', 'principles') for line 26 as well.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread scripts/setup.js
Comment on lines +82 to +91
function checkRequiredKeys() {
const env = readEnvKeys(ENV_PATH);
const missing = REQUIRED_KEYS.filter(k => !env[k] || env[k].length === 0);
if (missing.length === 0) {
log('Required keys present.');
return { missing: [] };
}
log(`WARN: required keys empty: ${missing.join(', ')}. MCP / API features will fail until set.`);
return { missing };
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: checkRequiredKeys only reads .env file, not process.env

The checkRequiredKeys() function at scripts/setup.js:82-91 reads the .env file on disk and checks if ANTHROPIC_API_KEY and GITHUB_TOKEN have values. It does not check process.env, so keys injected via the container environment (e.g., Docker secrets, CI variables, or --env-file in devcontainer.json) will still trigger the warning. Since this is a non-fatal warning (not a hard failure), and the .env file is the primary configuration mechanism for the devcontainer flow, this is acceptable behavior. The warning just might be confusing for users who set keys via other mechanisms.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

"SESSION_SCRIPT": "./session-start.sh",
"CONFIG_FILE": "./mcp-config.json",
"ENABLE_VERBOSE_LOGGING": "false"
"ENABLE_VERBOSE_LOGGING": "false",
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 initializeCommand requires Node.js on the host machine

The initializeCommand in .devcontainer/devcontainer.json:32 runs node scripts/setup.js --init-env-only && (docker volume create claude-shared-state || true) on the host before the container builds. If the host doesn't have Node.js installed, this command fails, and the && prevents the docker volume from being created. The volume is referenced in the mounts array, so a missing volume could cause a container start failure. This is a known devcontainer limitation — the initializeCommand runs in the host environment. Users of cloud-based devcontainers (Codespaces, Cowork) typically have Node.js available, but local Docker Desktop users might not.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant