Skip to content

Add meta-repo skill to the 7Factor catalog#5

Draft
goneflyin wants to merge 8 commits into
mainfrom
add-meta-repo-skill
Draft

Add meta-repo skill to the 7Factor catalog#5
goneflyin wants to merge 8 commits into
mainfrom
add-meta-repo-skill

Conversation

@goneflyin

Copy link
Copy Markdown
Contributor

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 only python3.

What's here

  • skills/meta-repo/SKILL.md, REFERENCE.md, and scripts/meta-repo.py (engine v0.7.0), plus a stdlib-only tests/ suite (24 tests).
  • README entry under Available Skills.

How it was built

  1. Imported verbatim from a personal skills dir (first commit is the pristine copy, so the review diff is clean).
  2. Reviewed with the writing-great-skills discipline + a code review, then hardened the engine against the findings — each fix pinned by a test written test-first:
    • graceful handling for a missing git binary and for OS-refused symlink creation
    • conflict detection before the roster is mutated
    • discover_symlinks restricted to member-shaped links so heal can't delete unrelated symlinks
    • normalized symlink comparison (idempotent sync)
    • --role "" clears a role; doctor reports a missing clone once; default_branch never leaks a detached-HEAD HEAD
  3. Aligned to the in-flight write-a-7f-skill standard: added a compatibility declaration (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.

goneflyin and others added 8 commits July 15, 2026 20:47
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 dumptruckman left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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).

Comment thread skills/meta-repo/SKILL.md
@@ -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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This description is quite long. I wonder if there's a way to shorten it without losing the "hooks" so to speak.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

It really is. Yeah, for frontmatter it should be more concise. I'll definitely work on this.

Comment thread skills/meta-repo/SKILL.md
---
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

Comment thread skills/meta-repo/SKILL.md
Comment on lines +24 to +27
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`).

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Why not keep the script in the skill?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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?

Comment thread skills/meta-repo/SKILL.md
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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I wonder if the agent actually sees the frontmatter when it loads the skill?

Comment thread skills/meta-repo/SKILL.md
Comment on lines +32 to +42
| 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 |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The Acts? column is a bit confusing here. What is the difference between acts and writes? Why are some of the acts **acts** instead?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

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.

2 participants