Cross-machine workflows broke silently when the agent reasoned on a stale
MCP cache, or hit sha-based optimistic-lock 422s on shared-wiki writes
because another host had pushed minutes earlier. Codify the missing
pre-flight as Step 0:
1. Always probe mcp__projects-meta__meta_status first.
2. If cache_age_minutes > 10 OR errors_count > 0 → run
`node ~/.local/projects-meta-mcp/dist/sync.js` before any read.
3. For shared-wiki WRITES (knowledge_ingest, knowledge_promote) →
unconditional `git -C ~/projects/projects-wiki pull --ff-only`
(sha-lock will reject the commit otherwise; failure is opaque).
4. Tasks-mutations: sync via dist/sync.js is enough (no local clone
of target tasks repo).
5. Sync 401/403 → STOP, send user to ~/.config/projects-mcp/auth.toml
to rotate gitea_token. No silent retry.
10-minute cache window chosen as the read threshold — balances
multi-machine drift detection against unnecessary Gitea round-trips.
Common mistakes + Red flags expanded to call out the new failure modes.
README mirrors the rule for human readers. Wiki concept page
projects-meta-skills.md gets a "Freshness gate (v1.1.0)" subsection.
Closes [using-projects-meta-freshness-gate].
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.3 KiB
title, type, updated
| title | type | updated |
|---|---|---|
| projects-meta-skills: setup + using pair for projects-meta-mcp | concept | 2026-04-29 |
projects-meta-skills: setup + using pair for projects-meta-mcp
2026-04-29.
What got built
A split skill pair for the local projects-meta-mcp stdio server (cross-project task aggregation + shared Gitea wiki):
skills/setup-projects-meta/— one-time install: clones the server repo, builds it, writes~/.config/projects-mcp/auth.toml, clones the shared wiki to~/projects/projects-wiki/(canon path; legacy~/projects/.wikiis migrated), registersmcpServers.projects-metain~/.claude.json. Eight phases, confirmation gates between Phase 1↔2 and before Phase 3.skills/using-projects-meta/— runtime policy: read tools (tasks_aggregate,knowledge_search,meta_status, …) and mutation tools (tasks_create,knowledge_ingest, …) with mandatory two-step preview → confirm. Carries the local-first rule inline: for the current project, read.tasks//.wiki/from disk; MCP cache is for other projects only.
Both skills v1.0.0, build artifacts in dist/, installed to ~/.claude/skills/.
Why split (recap)
Same reason as context7-setup.md:
- Setup is intrusive (writes secrets, edits
~/.claude.json, clones repos), one-time per machine, never auto-trigger. - Using is daily policy, auto-triggers on cross-project / shared-wiki phrases.
Mixing them dilutes the policy skill's description (worse triggering) and pulls install procedure into context every time the user asks "what's on the boards".
Pattern reference
mcp__projects-meta__knowledge_get slug=concepts/setup-using-skill-pair — full pattern doc in the shared wiki, written by another machine in the fleet ahead of this build. The 8-phase setup-X structure documented there is exactly what setup-projects-meta/SKILL.md follows; the using-X structure is exactly what using-projects-meta/SKILL.md follows.
The pattern is now used in claude-skills three times: context7, wiki, tasks, projects-meta. Templated enough that the next setup-X / using-X pair can be produced from these four exemplars in one pass.
Local-first rule (decision)
Concept page calls it out, but it's load-bearing enough to put inline in using-projects-meta/SKILL.md:
| 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 |
Without this rule, the agent burns latency on a stale MCP cache for state that's six lines away on disk.
Mutation pattern (decision)
All five mutation tools (tasks_create / update / close, knowledge_ingest / promote) follow strict two-step:
- Call without
confirm: true→ dry-run preview. - Show preview to user; wait for "ok" / "go" / "поехали".
- Re-call with
confirm: true→ committed to Gitea.
Documented in using-projects-meta/SKILL.md "Mutate (always two-step)" + "Common mistakes" rows. Forbidden inlining of confirm: true is the same hard rule as setup-X's "no auto-mutate of user config".
Cross-platform
Skills are platform-agnostic. Only auxiliary tooling (JSON validate, timestamp gen, chmod 600 on auth.toml — Linux/macOS only) differs. POSIX paths (~/.local/..., ~/.config/..., ~/projects/...) work identically under git-bash on Windows.
Path canon (caught after first draft)
Initial draft used ~/projects/.wiki for the shared wiki clone — the path the wiki anchor still documented. A fresh git pull of projects-wiki (after the user pointed out we'd skipped pull on session start) revealed wiki-path-mismatch-resolution — the canon is now ~/projects/projects-wiki/ (clone root), with content at ~/projects/projects-wiki/.wiki/. Reason: the MCP writer wrote to <clone>/.wiki/<type>/<slug>.md while the reader walked <clone>/<type>/... — under the old ~/projects/.wiki clone the writer's output was invisible to reads. Fixed in upstream commit 621a69f (branch fix/wiki-path-mismatch).
Both setup-projects-meta and using-projects-meta now write the canon path. setup-projects-meta Phase 1 detects a legacy clone; Phase 4 re-clones to canon and leaves the legacy dir for the user to inspect / delete.
This is a meta-lesson: always pull shared/multi-machine resources before relying on cached anchors. Saved as a feedback memory.
Freshness gate (v1.1.0)
using-projects-meta v1.1.0 adds a mandatory pre-flight Step 0 before any tasks_* / knowledge_* call:
- Probe
mcp__projects-meta__meta_status(cache age + errors). - If
cache_age_minutes > 10orerrors_count > 0→node ~/.local/projects-meta-mcp/dist/sync.js. - For shared-wiki writes (
knowledge_ingest,knowledge_promote) → unconditionalgit -C ~/projects/projects-wiki pull --ff-only(sha-based optimistic lock will reject otherwise with 422). - For tasks-mutations (
tasks_create/update/close) → sync viadist/sync.jsis enough; no local clone of target tasks repo. - 401/403 from sync → token dead → send user to
~/.config/projects-mcp/auth.toml. Loud failure mandatory.
Why: projects-meta is a bus between machines. Another host can push minutes ago without the agent knowing. Without Step 0, reads return stale data and writes hit opaque 422s — exactly the failure mode we hit during this very session (skipped initial pull → wiki anchors stale → had to rewrite three places after retroactive git pull). Codified the lesson into the skill so future sessions don't repeat it.
10-minute threshold is the chosen balance: catches multi-machine drift, doesn't burn Gitea round-trips for casual back-to-back questions.
Round-trip note
The task [projects-meta-skills] was created on a different machine (OpeItcLoc03@DESKTOP-NSEF0UK) via mcp__projects-meta__tasks_create target_project=claude-skills. Closing it on this machine via mcp__projects-meta__tasks_close target_project=claude-skills slug=projects-meta-skills round-trips back to the same Gitea board — both sides see the 🟢 done state. First end-to-end multi-machine task lifecycle in the fleet.