Install
$ agentstack add skill-ghostlygawd-recursive-harness-nested-repos ✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.
Security review
✓ PassedNo issues found. Passed automated security review. · v0.1.0 How review works →
- ✓ Prompt-injection patterns
- ✓ Secret / credential exfiltration
- ✓ Dangerous shell & filesystem operations
- ✓ Untrusted network calls
- ✓ Known-malicious package signatures
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ✓ Shell / process execution No
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
Verified badge
Passed review? Show it. Paste this badge into your README, it links to the public security report.
Reliability & compatibility
Declared compatibility
Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.
We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.
How agent discovery & health will work →About
Nested repos — one git repo living inside another
You have a self-contained sub-project (a plugin, a shared lib, a third-party skill, a repo with its own GitHub remote) and it must ALSO live inside this repo. There are four ways to wire that, and they are NOT interchangeable — the sharp differences are worktree auto-presence, who owns the history, and how you develop/update it. Two classic failures this skill exists to kill: reaching for git submodule by reflex (→ an empty dir in every fresh worktree), and assuming .worktreeinclude will carry a nested repo into a worktree (it will NOT — see leaf 3). Pick from the tree, don't default.
Decision tree — first match wins
- Third-party code you'll freeze + slim into THIS trunk (drop heavy media,
curate a snapshot)? → vendor-and-commit. This leaf already has a skill: use vendoring-skills for the full procedure (placement, slimming, provenance, the lint B3 allowlist). Don't re-derive it here.
- **Must be present in every worktree with ZERO setup, and you mainly CONSUME
it from upstream (rarely edit it in place)? → subtree**.
- You DEVELOP it in place as its own repo (push to its own remote), want it
in EVERY worktree, and the parent should track only a reviewed source ref? → gitignore + materialize-hook (register it in worktree-repos.json).
- Parent must pin an EXACT version and you bump deliberately, and a one-time
init step per worktree is acceptable? → submodule.
Discriminators at a glance:
| Option | Rides into new worktree automatically? | History owned by | In-place dev | |---|---|---|---| | submodule | No — empty until git submodule update --init | sub-repo (parent pins a SHA) | clean | | subtree | Yes (native tracked files) | parent (squashed in) | sync ceremony | | gitignore + materialize-hook | Yes (hook clones on EnterWorktree + SessionStart) | sub-repo (parent ignores it) | clean | | vendor-and-commit | Yes (native tracked files) | parent (snapshot) | re-vendor only |
The four options
submodule
Parent records a gitlink: .gitmodules (URL) + a pinned commit SHA. The sub-repo stays fully independent (own remote, own history).
- Update:
cd && git pull, then in the parent `git add &&
git commit` to record the new SHA. Deliberate, never automatic — that pin is the feature (reproducibility).
- Worktree gotcha:
git worktree adddoes NOT check out submodules (Claude
Code uses default git worktree logic per the live docs), so the path is EMPTY in a fresh worktree until git submodule update --init --recursive. Storage is shared via .git/modules, so the init is fast — but it IS a per-worktree step.
- Pick when: exact-version pinning matters and the init step is acceptable.
subtree
The sub-repo's files become REAL tracked files in the parent — no nested .git, no gitlink.
- Update:
git subtree pull --prefix= --squash(and
git subtree push … to send parent-side edits upstream).
- Worktree: present natively everywhere, zero setup.
- Pick when: you consume from upstream and want frictionless worktree
presence; you accept subtree-command sync instead of plain git push.
gitignore + materialize-hook ← the way to ride a NESTED REPO into worktrees
The sub-repo stays a LIVE nested repo on disk (its own .git), .gitignored so it's out of the parent's history.
.worktreeincludedoes NOT work for this. It copies gitignored files,
and git does not recurse into a nested-repo boundary, so a nested-repo dir enumerates as nothing to copy. Verified 2026-06-20 (prediction 55b1735b miss — brand-foundry never rode in, twice). Single gitignored files ride fine; a nested repo never does. Do not reach for .worktreeinclude here.
- Instead, REGISTER it. At the repo root, add a
{path, remote, ref}entry
to worktree-repos.json, where ref is the reviewed full 40-character commit SHA. hooks/materialize_worktree_repos.py (wired to SessionStart
- PostToolUse[EnterWorktree]) clones any missing entry into the worktree —
from the local primary checkout if present (fast, offline), else the remote, checks out that exact detached commit, verifies it, then points origin at the remote. No-op in the primary checkout; never clobbers an existing dir; fails open. A mutable local experiment may explicitly set development: true, but that mode is not reproducible or distribution-safe and must not ship unnoticed.
- Update: develop/
git pullin place exactly as a standalone repo. - Worktree: cloned in automatically on
EnterWorktree(verified end-to-end
2026-06-20 — a real EnterWorktree auto-fired the hook and cloned brand-foundry in) and on claude --worktree launch (SessionStart wiring; same engine, not separately live-fired). Subagent isolation:worktree worktrees fire neither trigger — minor edge; clone manually if a subagent needs it.
- Pick when: you develop it in place as its own repo, want it in EVERY
worktree, and the parent should track a reviewed source revision without absorbing the sub-repo's files/history. This is what brand-foundry uses.
vendor-and-commit
Slim a clone and commit a snapshot into the trunk at `. → **skill vendoring-skills`** owns this procedure; go there. Native in every worktree; updates = re-vendor (never hand-edit, or you lose upstream-trackability).
Worked example — brand-foundry (this harness, 2026-06-20)
skills/brand-foundry/ is its own repo (github.com/GhostlyGawd/brand-foundry), developed in place; no separate clone exists on disk. Goal: develop in place + ride into every worktree, without the trunk owning its history. → tree node 3: gitignore skills/brand-foundry/ (keeps it out of the trunk) + register its remote and reviewed commit in worktree-repos.json; the materialize hook clones and verifies that commit in each worktree. The FIRST attempt used .worktreeinclude and failed — it can't carry a nested-repo dir (prediction 55b1735b miss). Submodule was rejected (empty in fresh worktrees
- trunk-coupling); subtree was rejected (would break in-place own-repo dev).
Packaging a MULTI-skill distributable — use the plugin format
The decision tree picks the git-NESTING mechanism; this picks the PACKAGING when the sub-project is a bundle of several skills (plus its own commands/agents) meant to be distributed and invoked as a unit. Package it as a Claude Code plugin, not as skills hand-nested under one skills// dir:
- Give it a
.claude-plugin/plugin.jsonmanifest (nameis the only field the
validator REQUIRES; it only WARNS on missing version/description/author, so add those for a release-quality plugin). Put its skills at /skills//SKILL.md, and use ${CLAUDE_PLUGIN_ROOT} for any path a component references inside itself. Validate with claude plugin validate .
- A plugin's skills are invoked namespaced as
:(e.g.
prospector:validate). The namespacing is mandatory and isolating — a plugin skill is NOT merged into the bare top-level skill namespace. (Verified against the Claude Code plugins reference, 2026-06-23.)
- To ALSO develop the plugin in place as its own repo and ride it into every
worktree, combine this with decision-tree node 3 (gitignore + materialize-hook via worktree-repos.json) — packaging and nesting are orthogonal choices.
(session 16494681, 2026-06-20: placing the 5-skill prospector bundle needed a dedicated claude-code-guide agent to recover the plugin spec from scratch, because no skill covered multi-skill packaging.)
Rules
- Name the discriminator out loud before picking: worktree auto-presence?,
who owns history?, develop-in-place or consume? — those decide it.
- Don't reach for submodule just because "repo inside a repo" sounds like one;
it's the only option that does NOT auto-populate a worktree.
- Never use
.worktreeincludeto carry a NESTED REPO — it's for gitignored
files only. Use the registry + materialize hook.
- This skill is the chooser. Mechanics live elsewhere:
vendoring-skills
(vendor-and-commit), worktree (.worktreeinclude for gitignored files), and worktree-repos.json + hooks/materialize_worktree_repos.py (nested repos).
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: GhostlyGawd
- Source: GhostlyGawd/recursive-harness
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet, be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.