Files
claude-skills/skills/meta-host-routing/SKILL.md
vitya b065496deb fix(skills): meta-host-routing v0.3.0 — naming is meta-<project>, not <project>
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>
2026-05-27 13:33:52 +03:00

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-meta returns "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

  1. Detect. Check the target's local remote (git remote -v) and/or a projects-meta dry-run. Github remote OR "not in cache" → meta-out-of-repo project; continue. Otherwise → direct Gitea route, this skill does not apply.

  2. 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-meta tracks it as a project <owner>/meta-<project> — a tasks_create dry-run against that resolves. Canonical example: code github.com/OpeItcLoc03/yt-tools → meta-host Gitea OpeItcLoc03/meta-yt-tools. Naming is meta-<project>, NOT <project> — per the meta-out-of-repo design: 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:
      grep -ril "<project-name>" ~/projects/.common/.tasks/ ~/projects/.common/.wiki/
      
      The host is whichever Gitea repo already holds that project's tasks/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: .common was yt-tools' shared host until 2026-05-27, when yt-tools graduated to its own dedicated host (OpeItcLoc03/meta-yt-tools). .common now holds only yt-tools' done-task archive. Prefer giving a maturing project its own host over piling onto .common.

  3. Route there. Send every tasks_create / knowledge_ingest to 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.

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

  1. 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.
  2. Clone it, build canonical .wiki/ (CLAUDE.md, index.md, log.md, overview.md, raw/, concepts/, entities/, packages/, sources/) + .tasks/STATUS.md (emoji legend header).
  3. git add -f .wiki .tasks — the global core.excludesFile (~/.config/git/ignore) ignores .wiki//.tasks/. Existing hosts track them because they were added before that ignore existed; a fresh clone needs -f or git add -A silently stages nothing. This is the one gotcha that will waste a commit if missed.
  4. Commit, push. projects-meta picks it up on its next sync (it may not be in cache until then — see Failure modes).
  5. 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-meta cachetasks_create/knowledge_ingest return "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_status freshness check first (see using-projects-meta Step 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.