Files
claude-skills/skills/meta-host-routing/SKILL.md
vitya 4355c34c18 feat(skills): meta-host-routing v0.2.0 — dedicated-host resolve + bootstrap
Resolve order now prefers a dedicated same-name Gitea meta-host (e.g.
OpeItcLoc03/yt-tools) over a shared host (.common). Adds Bootstrapping a
new meta-host section incl. the git add -f gotcha (global core.excludesFile
ignores .wiki/.tasks in fresh clones). yt-tools relocated to its own host
2026-05-27.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 13:33:51 +03:00

7.4 KiB

name, version, description
name version description
meta-host-routing 0.2.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 with the same name as the project, holding only .wiki/+.tasks/ (no code)? That is its meta-host. Once synced, projects-meta tracks it as a project of that name — meta_status / a tasks_create dry-run against <owner>/<project> resolves. Canonical example: code github.com/OpeItcLoc03/yt-tools → meta-host Gitea OpeItcLoc03/yt-tools (a meta-only repo, same name, code on github).
    • (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/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>/<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 after the project (meta-only, auto_init:false) via the API with the admin token (~/.config/projects-mcp/auth.toml).
  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.