--- name: meta-host-routing version: 0.3.0 description: > 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, "заведи таски в ", "промоутни ". 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-`**, holding only `.wiki/`+`.tasks/` (no code)? That is its meta-host. Once synced, `projects-meta` tracks it as a project `/meta-` — 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-`, NOT ``** — per the `meta-out-of-repo` design: the bare `` name on Gitea must stay free for a possible code **mirror** of the github repo. (Local clone convention, if ever needed: `~/projects/.meta//`.) - **(b) Shared host (transitional).** No dedicated host yet → grep sibling Gitea repos, **start with `.common`** (`~/projects/.common/`), for the project name: ``` grep -ril "" ~/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 `/` (a dedicated host = `/meta-`; a shared host = e.g. `OpeItcLoc03/common`). On a shared host, namespace entries with a `-` 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-`** (meta-only, `auto_init:false`) via the API with the admin token (`~/.config/projects-mcp/auth.toml`). Do **not** use the bare `` 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` cache** → `tasks_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.