---
name: unikit-mcp-trap
description: >-
  Record a finding about the configured engine MCP server into
  .unikit/MCP-RECHECK-NOTES.md — the project's log of what has to be re-checked
  here. Use right after a call reported success while changing nothing, ate an
  argument, or validated a broken state, e.g. "write this down", "record this MCP
  finding", "the server lied — note it", "add a recheck note", "trap this". Takes
  findings already in the session first (they cost nothing), then optionally scans
  the "## MCP Findings" table of plans touched since the last audit — the table
  only, never the plan body. Writes in the one allowed genre — a check to perform;
  never a lifted gate, never a named workaround, never a claim about what the
  server can or cannot do. Makes zero MCP calls and needs no editor. To replay,
  retire, or upstream existing notes use /unikit-mcp-audit instead.
argument-hint: "[optional: the finding in one line]  (writes .unikit/MCP-RECHECK-NOTES.md; zero MCP calls)"
allowed-tools:
  - Read
  - Write
  - Edit
  - Glob
  - Grep
  - AskUserQuestion
  - Bash(date *)
disable-model-invocation: false
user-invocable: true
metadata:
  author: unikit
  version: "1.0"
  category: tools
---

# MCP Trap — record a finding

Write one durable line about the engine MCP server this project talks to, into
`.unikit/MCP-RECHECK-NOTES.md`.

**This skill makes zero calls to the engine MCP.** It needs no editor, no running
project, and no gate. A finding is something that was *already observed*; re-observing
it here would cost a session and could record the wrong thing. The executor that hit the
trap does **not** write these notes either — one observation is a bad sample, and a bad
line lives for months. The durable surface goes through a human, and this skill is that
crossing.

**This skill owns the notes format.** `references/notes-format.md` is the shared
specification: this skill writes to it, `/unikit-mcp-audit` curates against it. Load it
before writing anything.

## Language Awareness — BLOCKING PRE-REQUISITE

**BEFORE producing ANY output**, silently read `.unikit/system/LANGUAGE_RULES.md` and
apply it to all output (fall back to English if it is missing). The prose of a note is
authored in the project's artifact language; the `id`, the `area` keyword, and the whole
observation protocol below the line stay **English** — they are grepped by other skills.
Do not announce the language setting.

## The one rule that makes this file safe

> A note may contain **only a check**. Never a lifted gate, never a named workaround,
> never an assertion about the state of the server.

This is not style. A check that has gone stale costs one extra call and **fails safe** —
the pipeline stops instead of driving past. A lifted gate lifts an obligation *forever*,
and a "use Y instead of X" outlives the day X was fixed. The genre is the only real
protection this file has; the freshness of its contents is not.

Read `references/notes-format.md` → "Genre" for the rejection table, and apply it to
every candidate before it is offered.

## Bootstrap

Silently load — do not narrate:

1. **`{{skills_dir}}/{{self_name}}/references/notes-format.md`** — the format this skill
   owns. Mandatory; without it, do not write.
2. **`.unikit/system/engine-mcp/INDEX.md`**, first lines only — the delivery stamp
   (`server:`). This is the configured server, the second side of every header
   comparison. File absent → there are no known exceptions for this server; that
   restricts nothing and switches nothing to `⏸️ MANUAL`. Carry the server as unknown
   and say so once.
3. **`.unikit/MCP-RECHECK-NOTES.md`** if it exists — its header (`server:` / `audited:`)
   and the ids already taken.

**Header mismatch is a WARN, never a stop.** If the notes header names a different
server than the stamp, print exactly one line and keep going:

```
WARN [mcp-trap] server in notes header ≠ configured (<notes> ≠ <configured>)
```

The existing entries stay in force — they are *suspect*, not void, and suspect entries
still fail safe. Retiring them is `/unikit-mcp-audit`'s job, not this skill's.

## Step 1 — the current session

Findings already in this conversation cost nothing to collect: they were observed here,
with the raw response still in context.

Scan the session for observations that match a failure class from
`.unikit/system/dev-principles.md` → A3 — a call that reported done over an unchanged
state, an argument that was accepted and ignored, a checker that went green over a
broken artifact, an undo that reported done and left the state, a batch whose total hid
what it skipped, a read that predated the change it was meant to prove.

**Something found → go to Step 5 and stop.** Do not scan plans. The session is the
cheapest and the most reliable source; the plan scan exists only because sessions end.

## Step 2 — ask before reading anything from disk

Nothing in the session → count candidate plans first, then ask once:

```
No findings in this session. <N> plans changed after <audited>. Review them? [y/N]
```

`<audited>` is the `audited:` date from the notes header; `never` means every plan is a
candidate. Candidate plans are `.unikit/code/PLAN.md` and
`.unikit/code/plans/*/TASKS.md`, filtered by modification time against `<audited>`.

**Declined → print one line and stop:**

```
No candidates were searched — the plan scan was declined.
```

That line is not decoration. A silent stop here is indistinguishable from "there was
nothing to find", and the next run would repeat the same offer against the same plans.

## Step 3 — read the table, never the body

Agreed → for each candidate plan read **only the findings table**:

1. `Grep` the heading `## MCP Findings` in the plan.
2. Take the window from that heading to the next `##` heading, or 30 lines, whichever
   comes first.
3. Read nothing else from that file. Not the tasks, not the brief, not the checklist.

The window is the whole contract. A plan is a large file written for a different
purpose, and reading it whole to harvest three rows is how a cheap maintenance skill
turns into an expensive one.

## Step 4 — drop what was already transferred

Every note carries `from: <plan>#<id>` in its observation row when it came from a plan.
Drop every candidate row whose `<plan>#<id>` already appears in the notes.

This is why no registry of processed plans is needed: the cursor is the `audited:` date
plus the `from:` back-references, both of which live in the notes file itself. A repeat
run over the same plans is idempotent by construction — and a plan that grew new rows
after the last transfer is picked up correctly, which a "seen plans" list would not do.

## Step 5 — offer, in the genre

Present the surviving candidates and let the user choose which to record. For each one,
draft **both halves** the format requires:

- **above the line** — the check: `id | area | confirm that …`, phrased as an
  instruction to verify, with **no tool name in it**;
- **below the line** — the observation: `id | observed | replay | evidence | from`,
  where `evidence` is the raw call and the raw answer it gave, and `observed` is the date
  the finding was **observed** — today's date (`Bash(date *)`) for something seen in this
  session, and for a row lifted out of a plan the date already written there, copied
  across. Never the date of the transfer: the column says when this was run into, and a
  transfer date would quietly relabel it.

`area` comes from the 12-word vocabulary in `dev-principles.md` → A8 — the check table
is keyed by area precisely so it survives a server change, and a key outside that
vocabulary is unreachable by the greps the executors run.

`replay` defaults to **`manual`**. Promote it to `safe` only when every condition in
`references/notes-format.md` → "replay: safe" holds. When in doubt it is `manual`; the
cost of a wrong `manual` is that an audit shows the row instead of replaying it, and the
cost of a wrong `safe` is an audit that mutates a project.

**Reject, do not rewrite silently.** A candidate that asserts a capability, pre-declares
a gate, or names a replacement call is refused with the reason and offered back in check
form. If it cannot be expressed as a check, it does not belong in this file.

## Step 6 — write

Write `.unikit/MCP-RECHECK-NOTES.md` per `references/notes-format.md`:

- **File absent** → create it with the full header (`server:` from the delivery stamp,
  `audited: never`), both section headings, and the accepted rows.
- **File present** → append rows to both tables, allocating fresh ids. Do **not** touch
  the header: `server:` describes where the existing entries came from, and `audited:`
  belongs to `/unikit-mcp-audit`.

Both halves of a note are written together, always. A check with no observation behind
it cannot be replayed, retired, or upstreamed — it is a rumour with an id.

Then confirm what landed:

```
CLAIM:    <n> findings recorded in .unikit/MCP-RECHECK-NOTES.md
EVIDENCE: <the ids written> · read back from the file after the write
VERDICT:  CONFIRMED | NOT CONFIRMED
```

Read the file back. The rule that a response is not evidence applies to this skill's own
writes as much as to a server's.

## What this skill never does

- **Never calls the engine MCP.** No verification of the finding, no re-observation, no
  catalog lookup. If the finding needs replaying, that is `/unikit-mcp-audit`.
- **Never edits a plan.** Plans are read through a 30-line window and left untouched;
  the transfer is recorded on the notes side, as `from:`.
- **Never edits the packaged rules tree.** `.unikit/system/engine-mcp/` is rewritten by
  every `init` / `update`; an edit there is lost, and lost silently. A finding that
  deserves to ship to everyone goes upstream through `/unikit-mcp-audit`.
- **Never writes `⏸️ MANUAL`,** and never treats a missing rules file as a restriction.
  Absence of rules means no known exceptions, not absence of capability.

## See also

- `/unikit-mcp-audit` — curate what is here: re-stamp, replay, retire, upstream.
- `.unikit/system/dev-principles.md` — the evidence contract (A1/A2), the nine failure
  classes (A3), and the `kind` / area vocabularies (A8) this skill keys its rows by.
