Add meta-repo skill to the 7Factor catalog#5
Conversation
Import the meta-repo skill as-is from the local global skills dir so it can be shared via the 7Factor catalog. TODO.md and __pycache__ are omitted per the skill's own publish checklist. Review edits follow in subsequent commits. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Applies review findings from the writing-great-skills + code-review pass: - SKILL.md: the engine fallback pointed at the author's absolute ~/.claude/skills/meta-repo/scripts path, which doesn't exist for teammates who install via `npx skills add`. Reworded to reference the copy bundled beside SKILL.md (the engine already self-locates via Path(__file__)). - REFERENCE.md: 'the global skill copy is canonical' misdescribed vendoring — heal refreshes from whichever engine is running (higher META_REPO_VERSION wins). Retitled 'Relationship to the installed skill' and reframed the catalog as source of truth. - README.md: list meta-repo under Available Skills. Engine (scripts/meta-repo.py) left byte-identical to the author's canonical copy; code-review findings reported separately for sign-off. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Test runs import the engine and generate scripts/__pycache__; keep it (and any .pyc) out of git. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes surfaced in the writing-great-skills + code-review pass, each pinned by a
new stdlib-only unittest suite (tests/test_meta_repo.py, 23 tests):
- C1: guard a missing `git` binary (clear error, not an uncaught traceback)
- H1: cmd_add detects a real-file name conflict BEFORE writing the roster
- H2: discover_symlinks matches only member-shaped links, so heal never deletes
a user's unrelated symlink
- H3: ensure_symlink compares normalized targets (no ../api vs ../api/ churn)
- M1: cmd_add upsert honors an explicit --role "" without clobbering unset fields
- M3: cmd_doctor reports a missing clone once, not doubled; drops a dead ternary
- M4: default_branch never leaks the detached-HEAD "HEAD" sentinel into the roster
META_REPO_VERSION 0.5.0 -> 0.6.0 so doctor/heal refresh vendored copies.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- drop the phantom `workspace.yaml` trigger (the real file is meta-repo.yaml) - collapse the -local convention to a one-liner pointing at REFERENCE.md Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Comport with the write-a-7f-skill portability standard: native Windows has no symlink privilege by default, so ensure_symlink now stops with an actionable 'run under WSL or a POSIX shell' message instead of an uncaught OSError traceback. Turns the Windows path into a declared, tested refuse-with-guidance branch rather than a silent crash. Covered by a new ensure_symlink test. META_REPO_VERSION 0.6.0 -> 0.7.0 so doctor/heal refresh vendored copies. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add the compatibility frontmatter field per write-a-7f-skill: POSIX hosts (macOS, Linux) and WSL, python3 >=3.8 and git, installs nothing; native Windows unsupported because the workspace model relies on POSIX relative symlinks. Note the platform boundary in the engine section so the agent sets expectations up front. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dumptruckman
left a comment
There was a problem hiding this comment.
This is an interesting case where a docker fallback very well might not work because of the reliance on symlinks and the potential for host paths that are in remote locations (i.e. not just siblings of the meta-repo).
| @@ -0,0 +1,131 @@ | |||
| --- | |||
| name: meta-repo | |||
| description: Create, maintain, and work inside meta-repos — lightweight git repositories that define and document a working set of several independent repos (a.k.a. workspace repository; formerly pseudo-monorepo), wired together with relative symlinks. Use when the user wants to set up or manage a multi-repo workspace, add/remove member repos, onboard a teammate to a multi-repo setup, audit symlinks or repo consistency, regenerate workspace docs (AGENTS.md/README), produce a cross-repo architecture summary, or asks about meta-repo.yaml, pseudo-monorepos, or "which repos belong to this project." Also use to decide whether a task is scoped to one member repo or the whole workspace. | |||
There was a problem hiding this comment.
This description is quite long. I wonder if there's a way to shorten it without losing the "hooks" so to speak.
There was a problem hiding this comment.
It really is. Yeah, for frontmatter it should be more concise. I'll definitely work on this.
| --- | ||
| name: meta-repo | ||
| description: Create, maintain, and work inside meta-repos — lightweight git repositories that define and document a working set of several independent repos (a.k.a. workspace repository; formerly pseudo-monorepo), wired together with relative symlinks. Use when the user wants to set up or manage a multi-repo workspace, add/remove member repos, onboard a teammate to a multi-repo setup, audit symlinks or repo consistency, regenerate workspace docs (AGENTS.md/README), produce a cross-repo architecture summary, or asks about meta-repo.yaml, pseudo-monorepos, or "which repos belong to this project." Also use to decide whether a task is scoped to one member repo or the whole workspace. | ||
| compatibility: POSIX hosts (macOS, Linux) and WSL. Requires python3 ≥3.8 and git; installs nothing on the host. Native Windows is unsupported — the workspace model relies on POSIX relative symlinks, which need Developer Mode/privilege there; run under WSL instead. |
There was a problem hiding this comment.
I actually wonder if it works with Git Bash on windows. I think that might support POSIX relative symlinks? Weirdly, I think Windows can follow POSIX relative symlinks, but it cannot create them. I could be wrong about this though.
There was a problem hiding this comment.
No idea. Honestly, if it's important I'd be happy for a windows developer to take a look and experiment with it eventually. This is a bit ... arcane and fiddly, though, still -- and I'd like some time with it in its infancy with my team to do some more testing of it before extending it to a different platform.
Would be nice for it to work cross platform eventually though.
| If `scripts/meta-repo.py` doesn't exist in the meta-repo yet, run the copy bundled with | ||
| this skill — `scripts/meta-repo.py` sitting beside this `SKILL.md`. `init`/`heal` then | ||
| vendor a copy into the meta-repo so the engine travels with the repo (zero install for | ||
| teammates — just `python3`). |
There was a problem hiding this comment.
Why not keep the script in the skill?
There was a problem hiding this comment.
I was surprised by this at first. And torn.
The intent is that with it in the repo, you can do basic management of it without needing claude or an AI at all.
Still torn whether this is a good thing or not. It's got a very contrived structure right now, and ensuring it's manageable outside of the skill might be a step too far. Still -- I also like the idea it can be managed without.
What do you think? Good idea? Too much?
| vendor a copy into the meta-repo so the engine travels with the repo (zero install for | ||
| teammates — just `python3`). | ||
|
|
||
| Needs a POSIX host or WSL (see `compatibility`): the engine wires members with relative |
There was a problem hiding this comment.
I wonder if the agent actually sees the frontmatter when it loads the skill?
| | Command | What it does | Acts? | | ||
| |---------|--------------|-------| | ||
| | `init [--name N --description D]` | Create a meta-repo in cwd; `git init`s the root if needed; **greedily adopts every** sibling symlink as an `active` member (curate the roster after) | writes | | ||
| | `add --name N [--path ../N \| --remote URL] [--role R] [--status S]` | Add a member (clones if `--remote` & missing); with only `--role`/`--status` on an existing member, **edits its metadata** (e.g. mark one `archived`) | writes | | ||
| | `remove N` | Drop from yaml + remove symlink. **Never deletes the real clone.** | writes | | ||
| | `sync` | Reconcile disk→yaml: clone missing from `remote`, fix symlinks | **acts** | | ||
| | `update [--switch]` | Fetch + fast-forward every member **and** the meta-repo to latest trunk (re-detects trunk fresh); skips dirty repos, stays on feature branches but flags them; `--switch` moves clean feature-branch members onto trunk | **acts** | | ||
| | `doctor` | Report health (`sync` / `heal` / needs-you) **plus an advisory list of loose root files**. Read-only | reports | | ||
| | `heal` | Fix safe hygiene (incl. `git init` if the root isn't a repo); **additive** to CLAUDE.md (never deletes) | acts | | ||
| | `manifest` | Roster + computed per-repo state as JSON (for you to consume) | reads | | ||
| | `docs [--force]` | Scaffold README/AGENTS/CLAUDE if absent, else report drift | writes-once | |
There was a problem hiding this comment.
The Acts? column is a bit confusing here. What is the difference between acts and writes? Why are some of the acts **acts** instead?
There was a problem hiding this comment.
Would really love this to be broken up into multiple files, maybe at least one per subcommand. Generally, would like clean code practices to apply. This is code we will maintain, so I think we need to make it easier to maintain.
Brings the meta-repo skill into the shared catalog so the team can use it. A meta-repo is a thin git repo that wires several independent repos together with relative symlinks for cross-repo navigation and coordinated change — not a monorepo, not submodules. Ships a stdlib-only Python engine that does all the mechanical work (roster in
meta-repo.yaml, symlink wiring, scaffolded docs); teammates need onlypython3.What's here
skills/meta-repo/—SKILL.md,REFERENCE.md, andscripts/meta-repo.py(engine v0.7.0), plus a stdlib-onlytests/suite (24 tests).How it was built
writing-great-skillsdiscipline + a code review, then hardened the engine against the findings — each fix pinned by a test written test-first:gitbinary and for OS-refused symlink creationdiscover_symlinksrestricted to member-shaped links sohealcan't delete unrelated symlinkssync)--role ""clears a role;doctorreports a missing clone once;default_branchnever leaks a detached-HEADHEADwrite-a-7f-skillstandard: added acompatibilitydeclaration (POSIX/macOS/Linux/WSL; native Windows unsupported by design) and made the engine fail with platform guidance rather than a traceback.Draft while I dogfood it locally before wider rollout.