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>
90 lines
7.7 KiB
Markdown
90 lines
7.7 KiB
Markdown
---
|
|
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, "заведи таски в <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` 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.
|