feat(hermes): mvp-coverage — 9 skills converted to Hermes format

- mapping.yaml: 7 pending → auto (setup-tasks, using-tasks, setup-wiki,
  using-wiki, using-projects-meta, using-context7, project-bootstrap,
  recommend-dont-menu). pending count now 0.

- dist-hermes/ populated:
  software-development: project-bootstrap (+ assets)
  productivity: recommend-dont-menu, setup-tasks, using-tasks
  research: setup-wiki, using-wiki
  mcp: using-context7, using-projects-meta

- active-platform replace-rule verified: Windows+PowerShell → Linux+bash
  in body SKILL.md (frontmatter description unchanged by design).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-07 09:21:56 +03:00
parent 27026c5e0e
commit 82f82a2036
19 changed files with 2738 additions and 48 deletions

View File

@@ -0,0 +1,119 @@
---
name: using-context7
version: 1.0.0
description: Use when answering questions about a specific library, framework, SDK, API, or CLI tool — including setup/install, config, API syntax, version-specific behavior, migration between versions, or library-specific errors. Training data is often stale; context7 returns current docs. Skip for general programming concepts, refactoring, business-logic debugging, or when the codebase already answers the question.
---
# Using the context7 MCP server
## Overview
`context7` is an MCP server that fetches **current** documentation for named libraries and frameworks. Two tools: `mcp__context7__resolve-library-id` (name → library ID) and `mcp__context7__query-docs` (library ID + question → doc snippets).
Your training data has a cutoff. Library APIs change. If a question names a library, **reach for context7 before answering from memory**, even for libraries you "know" — your recall may be one or two majors behind.
## Prerequisites
This skill assumes `mcp__context7__resolve-library-id` and `mcp__context7__query-docs` are available. If they aren't (the tools are missing from the session, or calls fail with a connection error), the context7 MCP server isn't running for this session. Trigger the **`setup-context7`** skill to install/configure the official plugin (`context7@claude-plugins-official`) and inject the user's API key. It's a one-time procedure with confirmation gates.
## When to use
Use when the user asks about any of these in the context of a specific library:
- Install / setup / init commands
- Config file shape (`nuxt.config.ts`, `next.config.mjs`, `tsconfig.json` extends, `vite.config`, etc.)
- API / component / hook / composable syntax
- Migration between versions (v3 → v4, v14 → v15)
- Library-specific errors / warnings
- CLI flags
- Feature availability ("does X support Y?")
- Plugin / module ecosystem questions
Common triggers: "how do I …", "what's the right way to … in <lib>", "is there a <lib> way to …", any error message containing a library's name, any config file snippet.
**Prefer context7 over WebSearch / WebFetch for library docs** — it returns curated snippets, not rendered marketing pages.
## When NOT to use
- General programming concepts (closures, concurrency, algorithms)
- Refactoring / code review / business-logic debugging
- Writing new code from scratch where the stack isn't named
- Questions the current codebase answers (read the repo first)
- Your own prior-conversation context (use wiki / memory instead)
## Workflow
```
1. Identify the library (and version, if the user mentioned one)
2. resolve-library-id → pick best match by name + reputation + snippet count
3. query-docs with the ID + a specific question
4. Cite what you found; fall back only if context7 returned nothing useful
```
**Budget: 3 calls per question, max.** After 3, use what you have — don't loop.
If the user already gave a library ID in `/org/project` or `/org/project/version` form, skip step 2 and go straight to `query-docs`.
## Tool quick reference
| Tool | Required args | Purpose |
|---|---|---|
| `mcp__context7__resolve-library-id` | `libraryName`, `query` | Name → `/org/project` ID. Use official casing ("Next.js", not "nextjs"). |
| `mcp__context7__query-docs` | `libraryId`, `query` | ID → doc snippets. `query` must be specific. |
Library ID format: `/org/project` (e.g. `/vercel/next.js`) or `/org/project/version` (e.g. `/vercel/next.js/v14.3.0`).
## Good vs bad queries
**`resolve-library-id` — pick official names:**
```
libraryName: "Nuxt" query: "Nuxt 4 config and route rules" ✅
libraryName: "nuxt4" query: "nuxt" ❌ (wrong casing, vague query)
```
**`query-docs` — be specific:**
```
query: "How to set up @nuxtjs/i18n with prefix_except_default and ru default locale in Nuxt 4" ✅
query: "i18n" ❌
query: "How to configure YooKassa payment provider in Medusa v2 core flows" ✅
query: "payments" ❌
```
A specific query returns targeted snippets; a vague one returns a grab bag you'll ignore.
## Example
User: "How do `routeRules` work in Nuxt 4?"
```
1. mcp__context7__resolve-library-id
libraryName: "Nuxt"
query: "Nuxt 4 routeRules hybrid rendering"
→ /nuxt/nuxt (or /nuxt/nuxt/v4.x.x if version known)
2. mcp__context7__query-docs
libraryId: "/nuxt/nuxt"
query: "routeRules for hybrid rendering: ssr, prerender, isr, swr — syntax and examples"
→ doc snippets
3. Answer using the snippets. Cite the library + version.
```
## Common mistakes
| Mistake | Fix |
|---|---|
| Answering from memory on a library question | Run `resolve-library-id` first. Your training data is stale. |
| Calling `query-docs` without resolving first | Required unless user already gave `/org/project` ID. |
| Vague queries ("auth", "hooks", "config") | Include the specific task, version, and constraints. |
| Looping until you find the "perfect" answer | 3-call hard cap. Take the best result and move on. |
| Using context7 for codebase questions | Read the code. context7 doesn't know your repo. |
| Using context7 for general concepts | Answer from training data. context7 is for libraries. |
## Red flags
- "I already know this library" → your recall may be one major behind. Resolve anyway if the user is about to act on your answer.
- "This will take too many calls" → you have 3. Use them.
- "The error message looks obvious" → error messages that include a library name are a strong context7 signal.

View File

@@ -0,0 +1,170 @@
# 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: `<type>/<slug>.md` + `index.md` + `log.md` |
| `mcp__projects-meta__knowledge_promote` | `target_project`, `slug`, `body` | Move `raw/<slug>.md``sources/<slug>.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.

View File

@@ -0,0 +1,236 @@
---
name: using-projects-meta
version: 1.1.0
description: Use when working across multiple projects on one or many machines — cross-project task aggregation (`mcp__projects-meta__tasks_*`), shared Gitea-backed wiki query / ingest (`mcp__projects-meta__knowledge_*`), or sync diagnostics (`mcp__projects-meta__meta_status`). Triggers on phrases like "across all projects", "what's on the boards", "check shared wiki", "search projects-wiki", "ingest into shared wiki", "что у меня на досках", "по всем проектам", "общая вики", "cross-project status", or any time the user wants to see / mutate state in another repo than the current cwd. v1.1.0 mandates a Step 0 freshness gate (probe `meta_status`, sync if stale, pull `projects-wiki` before shared-wiki writes) — see SKILL body. Mutation tools require two-step preview → confirm. Skip for the **current** project's tasks/wiki — those live on disk in `.tasks/` / `.wiki/`.
---
# Using the projects-meta MCP server
## Overview
`projects-meta-mcp` is a local stdio MCP server. Two responsibilities:
1. **Cross-project task aggregation** — parses `.tasks/STATUS.md` from every repo on the user's Gitea, caches them in `~/.cache/projects-mcp/tasks.json`. Read tools (`tasks_aggregate`, `tasks_search`, `tasks_get`) hit the cache. Mutations (`tasks_create`, `tasks_update`, `tasks_close`) commit back to Gitea with sha-based optimistic lock.
2. **Shared knowledge wiki** — single Gitea repo (`projects-wiki`) cloned at `~/projects/projects-wiki/` with content at `~/projects/projects-wiki/.wiki/`, structured as packages / concepts / entities / sources / raw. `knowledge_search` + `knowledge_get` for queries, `knowledge_ingest` + `knowledge_promote` for writes.
Source of truth: Gitea (`https://git.kzntsv.site`, owner `OpeItcLoc03`). Cache and clone are local convenience.
Full reference: `mcp__projects-meta__knowledge_get slug=packages/projects-meta-mcp`.
## Prerequisites
This skill assumes `mcp__projects-meta__*` tools are available. If they aren't (tools missing from the session, or calls fail with a connection error), the server isn't running for this session. Trigger the **`setup-projects-meta`** skill to clone, build, write `auth.toml`, and register `mcpServers.projects-meta` in `~/.claude.json`. It's a one-time procedure with confirmation gates.
## Local-first rule
**For the current project — read disk directly.** `.tasks/STATUS.md` and `.wiki/` files in cwd are always fresher than the MCP cache. The cache:
- May be stale (default sync runs only when triggered).
- Hides 🟢 done by default.
- May not contain locally-developed projects that aren't pushed to Gitea yet.
Use MCP only for **other** projects, **other** machines, or **shared** wiki content.
| 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 a page on X?" | local `.wiki/index.md` + relevant file |
| "Has the **shared** wiki got a page on X?" | `mcp__projects-meta__knowledge_search` |
| "Sync state across machines?" | `mcp__projects-meta__meta_status` |
## When to use
- Cross-project task overview ("what am I working on across projects", "по всем проектам", "across the board").
- Hopping into another repo's task state without cloning it ("what's the status of project X").
- Querying the shared wiki for cross-cutting concepts (patterns, package references, design notes that apply to several repos).
- Ingesting a finished design / decision into the shared wiki so other machines / projects can see it.
- Creating a task in another project's `.tasks/STATUS.md` from the current repo (cross-project handoff).
- Sync diagnostics (when did the cache last refresh, are there errors, how many projects).
## When NOT to use
- The current project's own tasks or wiki — read disk.
- Anything inside a single project — `.tasks/<task>.md` and `.wiki/<page>.md` are always closer.
- One-off questions answered by `git log` or a single file.
- Library / framework documentation — that's `using-context7`.
- Code search — that's `Glob` / `Grep`.
## Step 0 — Freshness gate (run before any tool)
`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. Mandatory pre-flight, every session, every workflow:
```
1. Call mcp__projects-meta__meta_status.
2. Branch on cache freshness:
• If cache_age_minutes > 10 OR errors_count > 0:
run `node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js`
(or `npm run sync` from ~/projects/.common/lib/projects-meta-mcp).
• Else: cache is fresh enough — skip sync, no need to hit the network.
3. For shared-wiki WRITES (knowledge_ingest, knowledge_promote):
ALWAYS additionally run `git -C ~/projects/projects-wiki pull --ff-only`
regardless of cache age. The MCP server uses sha-based optimistic locking;
without an up-to-date local file SHA, the commit will be rejected (422)
and the failure mode is opaque to the user.
4. For tasks-mutations (tasks_create, tasks_update, tasks_close):
sync via dist/sync.js is enough — there's no local clone of the target
tasks repo, mutations go straight through Gitea API. Sync only refreshes
the local view so you reason from current state.
5. If sync returns 401 or 403:
STOP. The Gitea token in ~/.config/projects-mcp/auth.toml is dead or
wrong-scoped. Tell the user explicitly:
"Gitea sync failed with <401|403>. Rotate gitea_token in
~/.config/projects-mcp/auth.toml (Gitea: settings/applications)
and rerun."
Do not pretend sync succeeded. Do not retry silently.
```
**Don't sync unconditionally on every call.** Network overhead + risk of 401 even on a casual "what's on my boards". The 10-minute cache window is the right balance — catches multi-machine drift without burning Gitea round-trips for back-to-back questions.
**Don't apply Step 0 to `meta_status` itself** — it's the freshness probe, not a downstream read.
## Workflow
### Read (no confirmation needed)
```
0. Run Step 0 — Freshness gate (above) first.
1. Identify what you need: cross-project tasks? shared wiki page? sync state?
2. Pick the right read tool (table below).
3. Cite the result with the source slug / project name.
```
### Mutate (always two-step)
```
0. Run Step 0 — Freshness gate (above) first.
For shared-wiki writes (knowledge_ingest, knowledge_promote): unconditional
`git -C ~/projects/projects-wiki pull --ff-only` is part of Step 0.
1. Identify the mutation: tasks_create / tasks_update / tasks_close / knowledge_ingest / knowledge_promote.
2. Call the tool WITHOUT `confirm: true` → returns a dry-run preview (the proposed file diff and the Gitea commit message).
3. Show the preview to the user. Wait for explicit "ok" / "go" / "поехали".
4. Re-call with `confirm: true` to commit.
```
**Never inline `confirm: true` on the first call.** A trigger phrase ("create a task in project X") is permission to *plan*, not to *commit*.
## Tool quick reference
### Read tools
| Tool | Required args | Purpose |
|---|---|---|
| `mcp__projects-meta__tasks_aggregate` | — | All active tasks across all 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 (cached snapshot) |
| `mcp__projects-meta__knowledge_search` | `query`; opt `domain`, `limit` | Shared-wiki search; auto-detects domain from cwd, pass `domain="all"` to disable |
| `mcp__projects-meta__knowledge_get` | `slug` | Full text of one wiki page (e.g. `packages/projects-meta-mcp`) |
| `mcp__projects-meta__knowledge_suggest_promote` | — | Local `.wiki/concepts/` candidates for shared-wiki promotion |
| `mcp__projects-meta__meta_status` | — | Sync diagnostics: cache age, project count, error count, page count |
### Mutation tools (need `write:repository` Gitea scope; preview → confirm)
| Tool | Required args | Effect |
|---|---|---|
| `mcp__projects-meta__tasks_create` | `target_project`, `slug`, `description`, `next_action` (+ opt `where_stopped`, `status`, `blocker`, `branch`, `source_project`) | Append block to `<target>/.tasks/STATUS.md` via Gitea commit |
| `mcp__projects-meta__tasks_update` | `target_project`, `slug` + ≥1 of `where_stopped` / `next_action` / `blocker` / `branch` / `description` / `status` | Sha-based optimistic lock; 422 on conflict |
| `mcp__projects-meta__tasks_close` | `target_project`, `slug` (+ opt `note`) | Sets task to 🟢 done; appends identity-footer |
| `mcp__projects-meta__knowledge_ingest` | `target_project`, `type`, `slug`, `body` (+ opt `frontmatter`, `source_project`) | Three commits: `<type>/<slug>.md` + `index.md` + `log.md`. `type` ∈ entities / concepts / packages / sources / raw |
| `mcp__projects-meta__knowledge_promote` | `target_project`, `slug`, `body` (+ opt `frontmatter`, `source_project`) | Move `raw/<slug>.md``sources/<slug>.md` with auto `raw_path` link |
`target_project` is either a Gitea repo name, or `_meta` (the dedicated meta-tasks / meta-wiki repos from `auth.toml`).
## Examples
### Read example: cross-project status
User: "что у меня на досках?"
```
1. mcp__projects-meta__tasks_aggregate
→ 7 projects, 12 active tasks
2. Group by project, summarize 1 line per active task.
Cite project name; if a task is stale (cache age > 1h), flag it.
```
### Read example: shared wiki query
User: "есть ли в общей вики что-то про setup-using паттерн?"
```
1. mcp__projects-meta__knowledge_search
query: "setup-using skill pair pattern"
domain: "all"
→ hits include concepts/setup-using-skill-pair
2. mcp__projects-meta__knowledge_get
slug: "concepts/setup-using-skill-pair"
→ full text
3. Summarize, link with markdown to the slug.
```
### Mutation example: create cross-project task
User: "заведи в проекте books задачу на миграцию `settings.json`"
```
1. mcp__projects-meta__tasks_create
target_project: "books"
slug: "settings-json-migration"
description: "<...>"
next_action: "<...>"
(no `confirm`)
→ preview: proposed STATUS.md diff + commit message
2. Show preview to user.
3. User: "ok, go"
4. mcp__projects-meta__tasks_create
(same args + confirm: true)
→ committed to Gitea
```
### Mutation example: closing a cross-project task
User: "close `[projects-meta-skills]` in claude-skills"
```
1. mcp__projects-meta__tasks_close
target_project: "claude-skills"
slug: "projects-meta-skills"
note: "<one-line summary>"
(no `confirm`)
→ preview
2. User confirms.
3. Re-call with confirm: true.
```
## Common mistakes
| Mistake | Fix |
|---|---|
| Reading current project's tasks via `tasks_get` instead of disk | Read `.tasks/STATUS.md` directly. MCP is for *other* projects. |
| Inlining `confirm: true` on the first mutation call | Always preview first; show user; only then `confirm: true`. |
| Using `knowledge_search` for the project's own wiki | The shared wiki is a separate Gitea repo. Local `.wiki/` is in cwd. |
| Acting on a stale `tasks_aggregate` without checking `meta_status` | Step 0 — Freshness gate is mandatory. If `cache_age_minutes` > 10 (or errors > 0), run `node ~/projects/.common/lib/projects-meta-mcp/dist/sync.js` first. |
| Skipping `git -C ~/projects/projects-wiki pull` before `knowledge_ingest` / `knowledge_promote` | sha-based optimistic lock will reject the commit (422) and the failure is opaque. Pull is unconditional for shared-wiki writes — fast-forward is a no-op when current. |
| Treating sync 401/403 as "MCP is fine, the page just doesn't exist yet" | 401/403 means the Gitea token is dead. Stop, tell the user to rotate `gitea_token` in `~/.config/projects-mcp/auth.toml`. Never guess on stale data. |
| Calling `knowledge_ingest` with the wrong `type` | `type` must be one of `entities` / `concepts` / `packages` / `sources` / `raw`. Mis-typed pages land in the wrong section and break `index.md`. |
| Vague `knowledge_search` queries ("auth", "config") | Specific multi-word queries return targeted snippets; vague ones return noise. |
| Forgetting `domain="all"` when searching across families | Default `domain` is auto-detected from cwd; use `"all"` if the wiki page lives in a different family. |
## Red flags
- "I'll just commit it directly" → no. Mutation tools have a preview step for a reason — silent writes to another repo are a recipe for drift.
- "The cache is fresh enough" → run Step 0. The 10-minute window is the threshold; below it skip sync, above it sync. Don't eyeball this — the bus moves fast in cross-machine sessions.
- "I'll skip the pull, my last write was 30 seconds ago" → another machine pushed in between. Always pull before shared-wiki writes; the sha-lock check is your only safety net.
- "I'll skip the wiki page" → if you're answering a cross-cutting question and there's no wiki page, that's a `knowledge_ingest` candidate. Surface it to the user.