v0.2.0 wrongly said the dedicated meta-host shares the project's name. Per meta-out-of-repo design the convention is meta-<project> (e.g. OpeItcLoc03/meta-yt-tools), so the bare <project> name stays free for a code mirror. Fixed resolve step, example, and bootstrap instruction. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
7.7 KiB
name, version, description
| name | version | description |
|---|---|---|
| meta-host-routing | 0.3.0 | Use before any tasks_create / knowledge_ingest / brainstorm-promotion against a project — resolve WHERE that project's meta lives before writing. A github-hosted project (or any project projects-meta reports "not in cache") does NOT carry .tasks/.wiki in its own repo (meta-out-of-repo design: they'd leak on push/PR). Its meta lives in a sibling Gitea-tracked host repo — route MCP calls there, never into the github working tree, never guess. Triggers: "project not in cache" from projects-meta, promoting/creating tasks for a project with a github remote, "заведи таски в <github-проект>", "промоутни <github-проект>". Skip for a normal Gitea project already known to projects-meta — there the route is direct. |
meta-host-routing
A project's code repo is not always where its meta lives. Before writing tasks or wiki, resolve the meta-host. Github-hosted projects keep their
.tasks//.wiki/in a sibling Gitea repo — never in the github tree. Never guess the target.
When this runs
Before any mcp__projects-meta__tasks_create, mcp__projects-meta__knowledge_ingest, or brainstorm promotion, when either:
- the target project's local clone has a github remote, OR
projects-metareturns "project not in cache" for the target.
Both are signals that the project follows the meta-out-of-repo design: its meta is intentionally absent from its own repo.
Skip when the target is a normal Gitea project already known to projects-meta (meta_status lists it / a tasks_create dry-run succeeds) — there the route is direct, no resolution needed.
Why meta is out of the repo
Per the meta-out-of-repo design: .tasks/, .wiki/, .claude/ must not be committed into a repo that gets pushed to a public / shared / forked-upstream remote — the "kitchen" (notes, tasks, local skills, agent instructions) would leak. A global core.excludesFile ignores those paths, so github-hosted projects carry no meta in-tree by design. The meta still exists — it lives in a Gitea-tracked host repo and syncs through projects-meta.
Steps
-
Detect. Check the target's local remote (
git remote -v) and/or aprojects-metadry-run. Github remote OR "not in cache" → meta-out-of-repo project; continue. Otherwise → direct Gitea route, this skill does not apply. -
Resolve the meta-host, in priority order:
- (a) Dedicated meta-host (preferred). Is there a Gitea repo named
meta-<project>, holding only.wiki/+.tasks/(no code)? That is its meta-host. Once synced,projects-metatracks it as a project<owner>/meta-<project>— atasks_createdry-run against that resolves. Canonical example: codegithub.com/OpeItcLoc03/yt-tools→ meta-host GiteaOpeItcLoc03/meta-yt-tools. Naming ismeta-<project>, NOT<project>— per themeta-out-of-repodesign: the bare<project>name on Gitea must stay free for a possible code mirror of the github repo. (Local clone convention, if ever needed:~/projects/.meta/<project>/.) - (b) Shared host (transitional). No dedicated host yet → grep sibling Gitea repos, start with
.common(~/projects/.common/), for the project name:The host is whichever Gitea repo already holds that project's tasks/wiki.grep -ril "<project-name>" ~/projects/.common/.tasks/ ~/projects/.common/.wiki/ - (c) Neither → the project has no meta-host yet (Failure modes — STOP and ask, or bootstrap one per "Bootstrapping a new meta-host").
Note:
.commonwas yt-tools' shared host until 2026-05-27, when yt-tools graduated to its own dedicated host (OpeItcLoc03/meta-yt-tools)..commonnow holds only yt-tools' done-task archive. Prefer giving a maturing project its own host over piling onto.common. - (a) Dedicated meta-host (preferred). Is there a Gitea repo named
-
Route there. Send every
tasks_create/knowledge_ingestto the host's qualified<owner>/<repo>(a dedicated host =<owner>/meta-<project>; a shared host = e.g.OpeItcLoc03/common). On a shared host, namespace entries with a<project>-slug prefix. -
Never write
.tasks//.wiki/files into the github working tree, and never invent a target when resolution is ambiguous (Failure modes below).
Bootstrapping a new meta-host
When a project graduates to its own dedicated host (or a github project needs one):
- Create a Gitea repo named
meta-<project>(meta-only,auto_init:false) via the API with the admin token (~/.config/projects-mcp/auth.toml). Do not use the bare<project>name — keep it free for a code mirror. - Clone it, build canonical
.wiki/(CLAUDE.md, index.md, log.md, overview.md, raw/, concepts/, entities/, packages/, sources/) +.tasks/STATUS.md(emoji legend header). git add -f .wiki .tasks— the globalcore.excludesFile(~/.config/git/ignore) ignores.wiki//.tasks/. Existing hosts track them because they were added before that ignore existed; a fresh clone needs-forgit add -Asilently stages nothing. This is the one gotcha that will waste a commit if missed.- Commit, push.
projects-metapicks it up on its next sync (it may not be in cache until then — see Failure modes). - If migrating off a shared host: move open tasks + design concepts to the new host, leave the done-task archive behind under a relocation marker, and replace moved concept docs with pointer stubs so back-references don't dead-end.
Failure modes
- No Gitea repo tracks this project → STOP. Ask the user whether to bootstrap a dedicated host (preferred) or attach to a shared one. Do not default to writing into the github repo — that reintroduces the leak meta-out-of-repo exists to prevent.
- Just-created meta-host not yet in
projects-metacache →tasks_create/knowledge_ingestreturn "not in cache" until a sync runs. Either trigger a sync, or write the initial.tasks/STATUS.md/.wiki/content directly via git (as in Bootstrapping) and let the MCP pick it up next sync. - Multiple Gitea repos reference the project → STOP, ask which is canonical. Don't pick by guess.
- projects-meta cache stale ("not in cache" could be staleness, not meta-out-of-repo) → run a sync /
meta_statusfreshness check first (seeusing-projects-metaStep 0) before concluding the project is github-only.
Interaction with workshop-promote-brainstorm
workshop-promote-brainstorm's domain branch currently aborts on "project not in cache". With this skill active, that abort becomes a resolve step: find the meta-host, then promote into it. This skill is the routing primitive; promote-brainstorm (and ad-hoc tasks_create) consult it.
What NOT to do
- Don't write meta into a github working tree "because the project is right there" — that's the exact path-of-least-resistance leak meta-out-of-repo prevents.
- Don't treat "project not in cache" as "project doesn't exist" — it means "meta is hosted elsewhere," resolve it.
- Don't guess the meta-host when grep is ambiguous — ask.
- Don't apply this to normal Gitea projects already in
projects-meta— adds a pointless resolution step.
Cross-agent note
References Claude Code MCP tool names (mcp__projects-meta__*). On non-CC platforms substitute the projects-meta equivalents; the routing logic is platform-independent.
Why this exists
Codified 2026-05-27 after an agent, asked to promote a yt-tools feature, found yt-tools "not in cache" and started writing tasks directly into the github repo — instead of recalling that yt-tools' meta lives in .common. The meta-out-of-repo design existed only as an archived workshop concept doc (never triggers). This skill makes the routing rule fire at the moment of action.