# using-projects-meta Runtime policy for the local `projects-meta-mcp` stdio server. Two responsibilities, one server: 1. **Cross-project task aggregation** — reads / writes `.tasks/STATUS.md` in any of the user's Gitea repos. 2. **Shared knowledge wiki** — query / ingest a single Gitea-backed wiki at `~/projects/projects-wiki/.wiki/` (clone root: `~/projects/projects-wiki/`, Gitea repo: `projects-wiki`). `using-projects-meta` governs *usage* of an installed server. Initial setup (clone, build, `auth.toml`, MCP registration) is owned by [`setup-projects-meta`](../setup-projects-meta/). Full server reference: `mcp__projects-meta__knowledge_get slug=packages/projects-meta-mcp`. ## When it triggers - User asks for cross-project state ("what's on the boards", "across all projects", "что у меня на досках", "по всем проектам"). - User wants to query / ingest the shared wiki ("check shared wiki", "search projects-wiki", "ingest into shared wiki", "общая вики", "заингесть в общую"). - User wants to create / update / close a task in *another* project from the current cwd ("заведи в проекте X задачу", "close task Y in project Z"). - User asks for sync diagnostics ("when did the cache last refresh", "are there sync errors"). - If `mcp__projects-meta__*` tools are missing, this skill delegates to [`setup-projects-meta`](../setup-projects-meta/) before doing anything else. ## Local-first rule (critical) For the **current** project — read disk directly (`.tasks/STATUS.md`, `.wiki/index.md`). The MCP cache: - May be stale (sync runs only when triggered). - Hides `🟢 done` by default. - May not contain unpushed projects. Use MCP only for **other** projects, **other** machines, or the **shared** wiki content. See the table below. | Question | Where to read | |---|---| | "What's the status of *this* project?" | local `.tasks/STATUS.md` | | "What's on all my boards?" | `mcp__projects-meta__tasks_aggregate` | | "Has *this* project's wiki got X?" | local `.wiki/index.md` | | "Has the **shared** wiki got X?" | `mcp__projects-meta__knowledge_search` | | "Sync state across machines?" | `mcp__projects-meta__meta_status` | ## Step 0 — Freshness gate (v1.1.0, mandatory pre-flight) `projects-meta` is a bus between machines — another host may have pushed minutes ago. Without this gate, reads return stale data and writes hit sha-based optimistic-lock 422s with no explanation. Before **any** `tasks_*` or `knowledge_*` call: 1. `mcp__projects-meta__meta_status` — probe cache age + errors. 2. If `cache_age_minutes` > 10 OR `errors_count` > 0 → `node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js`. 3. For shared-wiki **writes** (`knowledge_ingest`, `knowledge_promote`) → **also** `git -C ~/projects/projects-wiki pull --ff-only`. Unconditional. The MCP server uses sha-based optimistic locking on the wiki repo; without an up-to-date local SHA the commit is rejected with a 422. 4. For tasks-mutations (`tasks_create`/`update`/`close`) → sync via `dist/sync.js` is enough; there's no local clone of the target tasks repo. 5. If sync returns **401 / 403** → STOP. Token is dead. Send the user to `~/.config/projects-mcp/auth.toml` to rotate `gitea_token`. Don't pretend success, don't retry silently. **Don't sync unconditionally** on every call — overhead + 401-risk for casual reads. The 10-minute window is the chosen threshold. **Don't apply Step 0 to `meta_status` itself** — it's the probe. ## Two operation classes ### Read (no confirmation) `tasks_aggregate`, `tasks_search`, `tasks_get`, `knowledge_search`, `knowledge_get`, `knowledge_suggest_promote`, `meta_status` — all side-effect-free. Call directly, cite the result. ### Mutate (always two-step) `tasks_create`, `tasks_update`, `tasks_close`, `knowledge_ingest`, `knowledge_promote` — write to Gitea. Procedure: 1. Call **without** `confirm: true` → returns dry-run preview (proposed file diff + commit message). 2. Show the preview to the user. Wait for explicit "ok" / "go" / "поехали". 3. Re-call with `confirm: true` → committed. **Never inline `confirm: true` on the first call.** A trigger phrase is permission to plan, not to commit. ## Tool quick reference ### Read | Tool | Required args | Purpose | |---|---|---| | `mcp__projects-meta__tasks_aggregate` | — | All active tasks across cached projects | | `mcp__projects-meta__tasks_search` | `query` | Substring search across slug + next_action | | `mcp__projects-meta__tasks_get` | `project` | Raw STATUS.md of one project (cache snapshot) | | `mcp__projects-meta__knowledge_search` | `query`; opt `domain`, `limit` | Shared-wiki search; default domain auto-detected from cwd | | `mcp__projects-meta__knowledge_get` | `slug` | Full text of one wiki page | | `mcp__projects-meta__knowledge_suggest_promote` | — | Local `.wiki/concepts/` candidates for shared promotion | | `mcp__projects-meta__meta_status` | — | Sync diagnostics (cache age, project / page / error counts) | ### Mutate (need `write:repository` Gitea scope) | Tool | Required args | Effect | |---|---|---| | `mcp__projects-meta__tasks_create` | `target_project`, `slug`, `description`, `next_action` | Append block to target's `.tasks/STATUS.md` via Gitea commit | | `mcp__projects-meta__tasks_update` | `target_project`, `slug` + ≥1 mutable field | Sha-based optimistic lock; 422 on conflict | | `mcp__projects-meta__tasks_close` | `target_project`, `slug` (+ opt `note`) | Marks task 🟢 done with identity-footer | | `mcp__projects-meta__knowledge_ingest` | `target_project`, `type`, `slug`, `body` | Three commits: `/.md` + `index.md` + `log.md` | | `mcp__projects-meta__knowledge_promote` | `target_project`, `slug`, `body` | Move `raw/.md` → `sources/.md` | `type` ∈ `entities` / `concepts` / `packages` / `sources` / `raw`. `target_project` = Gitea repo name, or `_meta` (meta-tasks / meta-wiki repos from `auth.toml`). ## Common mistakes - **Reading current project's tasks via `tasks_get`.** Read `.tasks/STATUS.md` on disk; the MCP cache is for *other* projects. - **Inlining `confirm: true` on first call.** Always preview first; show user; only then `confirm: true`. - **Confusing the local `.wiki/` with the shared `projects-wiki`.** They are two different stores. `using-wiki` operates on the local one; `using-projects-meta` queries / ingests the shared one. - **Acting on stale `tasks_aggregate`.** If `meta_status.age_seconds` > 3600, either run `node dist/sync.js` (in `~/projects/.common/lib/projects-meta-mcp`) or warn the user about staleness. - **Vague `knowledge_search` queries.** "auth" returns noise. Multi-word, specific queries return targeted snippets. - **Wrong `type` on `knowledge_ingest`.** Mis-typed pages land in the wrong section and break `index.md`. Pick from the five canonical types. ## When NOT to use - The current project's own tasks — read `.tasks/STATUS.md`. - The current project's own wiki — read `.wiki/`. - Library / framework documentation — that's [`using-context7`](../using-context7/). - Repo-internal code search — that's `Glob` / `Grep`. - One-off git history questions — `git log`. ## Install From the repo root: ```bash bash scripts/install.sh using-projects-meta ``` Works on Windows under git-bash, Linux, macOS. ## See also - [`setup-projects-meta`](../setup-projects-meta/) — companion, owns server install + MCP registration. - [`using-context7`](../using-context7/) — sister skill for library docs (same using-X structure). - [`using-tasks`](../using-tasks/), [`using-wiki`](../using-wiki/) — per-project policies for in-repo `.tasks/` and `.wiki/`. Orthogonal to this skill; together they cover both per-project and cross-project state.