Skip to content

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) - #151

Merged
robercano-ghbot merged 2 commits into
mainfrom
feat/issue-128-vendor-runtime
Jul 17, 2026
Merged

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128)#151
robercano-ghbot merged 2 commits into
mainfrom
feat/issue-128-vendor-runtime

Conversation

@robercano-ghbot

Copy link
Copy Markdown
Collaborator

What

Makes /orchestrator:setup and /orchestrator:sync vendor the runtime harness (agents/, commands/, hooks/, scripts/, skills/) into a consumer repo's local .claude/, and adds a consumer settings.json template whose hooks resolve to $CLAUDE_PROJECT_DIR/.claude/scripts/… instead of ${CLAUDE_PLUGIN_ROOT}/…. The orchestrator plugin then becomes the install/update channel only and no longer has to stay enabled on the session-start critical path — exactly how reCode itself already runs.

Why (#128)

In a plugin-consumer repo (reDeploy, reDeFi) the enabled orchestrator plugin is loaded from the marketplace at every session start (~18s), which breaches claude remote-control's ~20-30s spawn-ack window and kills headless / Routine / loop-fired sessions (the parent declares the still-alive child dead; abandoned children die of SIGPIPE). Running the consumer off vendored local files removes the per-session plugin load from the critical path.

How

  • scaffold.sh / sync.sh: vendor the runtime subtrees into .claude/, gated by a single top-level marker .claude/.orchestrator-vendor (@orchestrator-managed runtime-vendor vN) reusing the existing managed_version_of behind/never-downgrade/conflict ladder. Copy is prune-then-copy of directory contents (rm -rf dest && cp -a src/. dest/) so restamps are idempotent and prune upstream-removed files (no nested skills/setup/setup). The arm-loop.sh carve-out (its own dedicated MANAGED_FILES row) is preserved via backup-before-prune / restore-after-copy, so it stays singly-managed.
  • New user-owned settings.json template (create-if-absent, never clobbered): hooks reference local $CLAUDE_PROJECT_DIR/.claude/scripts/…, no enabledPlugins / extraKnownMarketplaces.
  • Docs (GETTING_STARTED.md, USAGE.md), MANIFEST.md, and both SKILL.md files updated to the vendored-runtime / plugin-as-updater model.
  • New offline test .claude/scripts/vendor-runtime.test.sh (10 scenarios / 38 checks), auto-discovered by .claude/self/checks.sh: fresh-vendor, idempotent re-run, restamp (asserts no nesting + subdir content actually refreshed), never-downgrade (byte-identical tree), conflict paths (asserts installed bytes untouched), arm-loop carve-out.

Gates

build / lint / test / test_affected all green (self-adapter GATES_FILE=.claude/self/gates.json), including smoke-fanout.sh and the new 38-check test.

Review

Correctness (opus) + tests (sonnet) both APPROVE, consensus=all. Reviewers reconstructed the pre-fix buggy copy and confirmed the new tests catch the directory-nesting regression.

Closes #128

robercano and others added 2 commits July 17, 2026 08:10
)

An enabled plugin loads (and pays its ~18s load cost) on every session
start regardless of how its hooks are wired, which blows claude
remote-control's ~20-30s spawn-ack window for headless driver sessions in
consumer repos. Make the vendored local .claude/ files the runtime path
instead: scaffold.sh now copies the plugin's own agents/, commands/,
hooks/, scripts/, and skills/ subtrees wholesale into the consumer repo,
gated as one unit by a single .claude/.orchestrator-vendor marker reusing
the existing managed-file marker ladder, and creates a settings.json
(user-owned, create-if-absent) that wires the runtime hooks to
$CLAUDE_PROJECT_DIR/.claude/scripts/... instead of the plugin's
hooks/hooks.json. sync.sh mirrors the re-vendor on plugin upgrades with
the same behind/conflict/never-downgrade semantics as every other managed
row. .claude/scripts/arm-loop.sh is excluded from the whole-tree copy
since it already has its own dedicated managed-file row with a different
canonical template, avoiding two divergent sources of truth for the same
destination. Once vendored, the plugin only needs to stay enabled to run
/orchestrator:setup or /orchestrator:sync, not for everyday sessions.
Updates MANIFEST.md, both skill docs, and the GETTING_STARTED/USAGE
passages that described the old plugin-stays-loaded-at-runtime model.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…(issue #128)

copy_vendor_dirs in scaffold.sh and sync.sh used `cp -a "$entry" "$dst/$base"`
per top-level entry, which nests into an already-existing destination on any
restamp — skills/ is the only vendored dir with subdirectories, so a real
version bump produced duplicate nests (.claude/skills/setup/setup,
.claude/skills/sync/sync) and left the real files stale, permanently
diverging the tree and making every later /orchestrator:sync report a false
conflict. Switch to prune-then-copy of directory CONTENTS (rm -rf dest, then
cp -a src/. dest/) so restamps are idempotent and prune files removed
upstream, while explicitly backing up and restoring .claude/scripts/arm-loop.sh
around the scripts/ prune so its own MANAGED_FILES row/template stays the
sole source of truth for that file.

Strengthen vendor-runtime.test.sh: assert no nesting and genuine content
refresh on restamp (fails against the old cp -a form, passes after the fix),
add never-downgrade coverage for both scripts, prove conflict paths leave
the tree untouched by grepping the injected local marker back out of the
file (not just the log line), and trim plugin-root fixtures to only the
entries the vendor step reads instead of copying the whole .claude/ tree.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

6 similar comments
@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot

Copy link
Copy Markdown
Collaborator Author

fix(harness): vendor runtime harness into consumers so the plugin drops off session-start critical path (#128) (not yet reviewed)

@robercano-ghbot
robercano-ghbot merged commit ed1ec90 into main Jul 17, 2026
9 checks passed
@robercano-ghbot
robercano-ghbot deleted the feat/issue-128-vendor-runtime branch July 17, 2026 07:17
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.

Headless sessions in plugin-consumer repos always die: session-start plugin load breaches remote-control's spawn-ack timeout

2 participants