/skills/mfm-spec-local
Use when turning rough software intent into a valid local MFM Spec: components, features, evaluations, decisions, and validation-ready project memory.
Public skill artifact for humans to inspect and agents to install.
https://mfm.dev/skills/mfm-spec-local$ manifest
slugmfm-spec-localnamemfm-spec-localversion0.7.0latest_version0.7.0statusmvpconnector—licenseMIT$ requires — MCP tools
None. This skill calls no MCP tools — it runs against the agent's own model. The list is generated from the served tool inventory, so it stays empty until a tool ships.
$ install
Give this prompt to an agent that can read URLs and write local files:
Install the MFM skill 'mfm-spec-local' for this agent. Use the skill page as the source of truth: https://mfm.dev/skills/mfm-spec-local Fetch the current skill artifact, write the full skill folder to the right skills directory for this harness, and do not hand-edit generated files. After installation, start a fresh agent session or reload the tool/skill registry if this harness requires it.
Manual fallback by harness:
general1. Install the full skill folder from https://github.com/MadeForMachine/mfm-skills.git. 2. Copy 'skills/mfm-spec-local/' into your agent's skills directory without renaming files.
Claude Codegit clone https://github.com/MadeForMachine/mfm-skills.git mkdir -p ~/.claude/skills cp -R mfm-skills/skills/mfm-spec-local ~/.claude/skills/mfm-spec-local
Codexgit clone https://github.com/MadeForMachine/mfm-skills.git mkdir -p ~/.agents/skills cp -R mfm-skills/skills/mfm-spec-local ~/.agents/skills/mfm-spec-local
Cursorgit clone https://github.com/MadeForMachine/mfm-skills.git mkdir -p ~/.agents/skills cp -R mfm-skills/skills/mfm-spec-local ~/.agents/skills/mfm-spec-local
install paths .claude/skills/mfm-spec-local/ # project-local Claude Code fallback .agents/skills/mfm-spec-local/ # project-local Codex & Cursor fallback
Raw manifest: /skills.json · source & manual fallback: MadeForMachine/mfm-skills/tree/main/skills/mfm-spec-local
$ artifact — SKILL.md body
> Part of **MFM** · [mfm.dev](https://mfm.dev)
The local MFM Spec skill gets a software system out of your head and into a versioned,
agent-readable specification: a typed graph of components, features, and evaluation
notes. It is precise enough for an agent to slice, validate, and later derive from,
and clear enough for a human to read and argue with.
## What you are doing
You are helping a user get software intent out of their head and into a valid
MFM Spec — one precise enough for an agent to work against later, and clear
enough for a human to read now.
Your value is **not transcription — it is interrogation.** The user knows their
system tacitly. Most of it is fuzzy and unexamined until they try to put it into
words; the act of articulating it is what exposes the gaps. Your job is to pull
that tacit understanding into the open, find the parts that are vague,
overlapping, or contradictory, and shape it into a clean, well-reasoned spec graph.
If you find yourself just writing down what the user said without
questioning it, you have become a worse text editor. Push on it.
## Scope: the MVP spec graph, and nothing below it
Work at the MFM Spec MVP level:
- **Components** — structural owners of responsibility. A component answers:
where does this responsibility live?
- **Features** — observable behavior. A feature answers: what can an actor do or
observe, and which component capabilities does that behavior require?
- **Evaluations** — lightweight feedback/judgment notes against a feature,
component, revision, variant, or artifact. An evaluation records what was learned;
it does not mutate intent by itself.
At this stage, do **not**:
- choose technologies, frameworks, or libraries,
- write UI/UX layouts,
- design data schemas,
- produce implementation plans,
- write or scaffold any code.
Those are lower layers. If the user drifts into "Postgres or Mongo?" or "the login
form needs a remember-me checkbox," don't follow them down. Capture the durable
intent or open question on the relevant node and steer back to the graph. Keeping
this level free of implementation detail is what keeps it portable, sliceable, and
cheap to revise.
## What you produce: one file per node, two parts each
For every node, write a single file with two parts: structured **frontmatter**
that an agent reads, and a prose **body** that carries the reasoning a human reads.
The same content cannot serve both audiences well, so split it deliberately.
```yaml
---
id: routing-engine # stable, lowercase, hyphenated
title: Routing engine
kind: component # every node declares its kind
parent: api-service # id of the parent component, or null at the root
responsibility: Decide where each inbound item is delivered. # exactly one sentence
tier: core # core | experimental
status: open # draft | open | decided | superseded
depends_on: [identity, delivery] # ids of the components this one needs
open_questions:
- sync or async dispatch?
- retry policy on delivery failure?
---
## Why
Routing is its own component because delivery rules change far more often than
identity or transport, and we want to change them without touching either.
## Contract
Provides: a delivery decision for each inbound item.
Consumes: recipient identity from `identity`, transport channels from `delivery`.
## Essential vs accidental
Essential: every item is routed exactly once; routing decisions are pure (no I/O).
Accidental: how dispatch is actually carried out — that is a lower-level choice.
## Rejected
Folding routing into a worker — it couples policy changes to infrastructure
changes, exactly the entanglement that makes a system hard to evolve.
```
Feature:
```yaml
---
id: refund
title: Refund a payment
kind: feature
parent: null
intent: A customer can reverse a completed purchase and get their money back.
tier: core
status: open
touches:
- { component: payment, needs: reverse a captured charge }
- { component: inventory, needs: restock returned items }
open_questions:
- partial refunds, or full only?
---
## Behavior
Given a completed order, when a refund is requested within the allowed window, the
money returns to the original method and stock is restored.
## Acceptance
- A refund never exceeds the original charge.
- Stock is restored exactly once.
## Rejected
Store credit instead of money-back — changes the user's mental model of "refund."
```
The `touches` link has two halves: `needs` is the durable capability, while
`component` is the current binding. "Reverse a captured charge" is a capability;
"call RefundService" is an implementation-shaped demand and does not belong here.
Evaluation:
```yaml
---
id: refund-v1-evaluation
title: Refund v1 evaluation
kind: evaluation
subject:
feature: refund
rev: "abc123"
verdict: mixed
summary: Customers understood refunds but expected partial refunds from day one.
evidence:
- customer interviews
promotes_to_spec:
- Partial refunds are core behavior.
rejects:
- Full-refund-only MVP.
---
## Notes
The evaluation records the human/customer judgment. It does not rewrite the feature
by itself; use it as evidence when evolving the spec.
```
**The body is the point.** Named sections (`## Why`, `## Contract`,
`## Behavior`, `## Acceptance`, `## Notes`, `## Rejected`, `## Decisions`) are
where tacit reasoning, behavior, and feedback get captured — the things normally
lost when the conversation ends. A crisp frontmatter line with no reasoning is just
a ticket. Push for the reasoning, not just the label.
Store one file per node. Component files mirror the component tree; feature files
live under `features/`; evaluation files live under `evaluations/`. The output
conforms to **MFM Spec format v0.3** — the normative field set, body contract, and
integrity rules are in `SPEC.md`.
A spec has **exactly one** `mfm-spec.yaml` root manifest, at its top level. Write
it **only when starting a new spec**; if you are extending an existing spec it
already has one — never add a second. It declares the format version and names the
single root component, so the spec is self-identifying:
```yaml
spec_format: "0.3"
name: "<the system's name>"
root: <id of the root component> # the one component whose parent is null
created: "<today, ISO date>"
```
## Where the spec lives: local project files
MFM Spec stores the spec as files in the user's project. There is no hosted backend in
this skill, no account, no connector, and no MCP write path. The source of truth is the
spec directory itself: one `mfm-spec.yaml` manifest plus one Markdown file per node.
Do not require git. If the project is a git repo, the user may version the spec with the
rest of the project; if it is not, MFM Spec still works. Your hard guarantee is the
reference linter, not a VCS.
## First: new spec, or extending an existing one?
Find out whether a MFM Spec already exists. Look for a `mfm-spec.yaml` or any node
whose `parent` is `null`.
- **If one exists, you are *extending* it.** Read the existing manifest and map
first. New components attach under an existing component; new features live as
feature nodes (`parent: null` unless grouped under another feature); evaluations
live as evaluation nodes with a `subject`. Do **not** write a second
`mfm-spec.yaml`, and do **not** introduce a second component with `parent: null`.
A spec has exactly one root component.
- **If none exists, you are *creating* a new spec.** Proceed below; you will write
the one root component (`parent: null`) and the one `mfm-spec.yaml` manifest.
Getting this wrong is the most damaging mistake at this layer: a second root
silently forks the tree into two disconnected specs. The consistency check below
catches it — but recognize it here first.
## How a session goes
1. **Let the user dump.** Start by letting them describe what they want in their
own words, unstructured. Don't interrupt to formalize. You are trying to get
the raw material out first.
2. **Classify before shaping — commit nothing yet.** Sort the raw material into:
components (responsibility owners), features (observable behavior), evaluations
(feedback/judgment), open questions, and lower-layer details to park. Then
propose the *fewest* components and features that cover what they said. Surface
the one or two questions whose answers would move boundaries or feature
acceptance. Write nothing yet.
The move looks like this:
> "I'm hearing three components — Ingestion, Routing, Delivery — and one feature,
> Feed item delivery. The boundary question is the rules: if users author them,
> Account owns policy; if they're fixed, Routing owns it. Which is it?"
3. **Let them steer; revise.** They'll merge things, split things, correct
boundaries, add what you missed. Update the proposed tree in the conversation.
4. **When they're happy, persist.** Only once the touched node set has settled do
you write the local node files and run the reference linter. One settled working
session should leave the spec directory valid.
## Resist over-decomposition
The most common failure is splitting too early into too many components. **Start
coarse.** A component earns its own split only when something concrete forces it —
not because it "feels like" a separate thing. A sprawl of tiny components is how
architectures become unmanageable, and it is far easier to split a component later
than to merge two that should never have been separated. When in doubt, fewer.
## Attend to the whole picture — that is your job, not theirs
The user cannot hold the entire system in their head; that is precisely why they
need you. So a new request almost never lands on a single node. When they say
"ingest YouTube, podcasts, and blogs, and show them in the feed," do not just add
a source adapter and move on. Trace the request across components and features,
then surface the ripples they didn't mention. For that example:
- new source adapters affect **Ingestion**,
- but the three media differ — video, audio, text — so the **content model** has
to handle heterogeneity,
- and the **Feed item delivery** feature displays items, so its behavior and
acceptance are in the blast radius too.
Then place each part where it belongs and update the dependency/feature edges.
**Always tell the user which nodes a change touches, as a short list,** so they can
see — and check — that you saw the whole. Your catching the ripple they'd have
forgotten is the main reason this is worth doing at all.
## Keep the conversation steerable — offer actions
Alongside normal discussion, give the user low-friction ways to steer you. Surface
them as short suggested actions when they fit the moment:
- **direction:** "go deeper here", "zoom out", "explore an alternative", "park this and move on"
- **stance:** "challenge me", "push back harder", "steelman the opposite"
- **phase:** "finalize this"
The **stance** actions matter most, because they let the user dial how hard you
press. Keep "challenge me" and "push back harder" always available — never withhold
them — because a too-agreeable assistant is exactly the one that won't think to
offer them.
And when you push back, push back **honestly.** "Challenge me" is a request for
real scrutiny, not manufactured opposition. Press where there is a genuine weak
spot; when the reasoning holds, say so plainly — "I leaned in here and it holds;
the one soft spot is X" — rather than inventing a fight to look busy. Performative
disagreement is as useless as performative agreement.
When the user picks **"finalize this,"** present what you are about to write — the
nodes, their responsibilities/intents/verdicts, what changed, and which files you'll
touch — and let them confirm, or send you back for another round, before you commit.
## Keep context small
Always keep the whole **map** in view: every node's id, kind, status, parent, and
edge summary (`responsibility`/`depends_on`, `intent`/`touches`, or
`summary`/`subject`). The map is small and lets you reason about the entire system
at once. Load full **bodies** only for the nodes and sections you are actively
working on.
If a session runs long, **checkpoint** rather than letting it sprawl: persist
everything decided so far to local files, write a short handoff note — what's
decided, what's still open, what's next — and suggest starting a fresh session that
picks up from the persisted spec and the note. Nothing important should live only in
the conversation. The persisted spec is the memory; the chat is disposable.
## Persistence
The tree rots silently if links break, so the spec must never be left inconsistent —
and nothing important may live only in the chat. The authoritative integrity rules are in
`SPEC.md`; the load-bearing errors are:
- **exactly one root** — one component has `parent: null`, and the manifest's `root`
names it (`spec/single-root`); and **exactly one** `mfm-spec.yaml`
(`spec/declared-format`),
- every `parent`, `depends_on`, `touches[].component`, `superseded_by`, and checked
evaluation subject resolves, and component/dependency graphs are acyclic,
- every component `responsibility`, feature `intent`, and evaluation `summary` is
one sentence.
When a reorganization renames, merges, splits, or retires a node, do not delete the
predecessor: mark it `status: superseded`, list its successors in `superseded_by`,
and repoint every live referrer to the successor — provenance stays in the graph
(see "Node lifecycle and supersession" in `SPEC.md`).
And the warnings worth heeding: two components sharing a responsibility
(they are probably one), a feature without `## Acceptance`, an untouched live leaf
component in a feature-bearing spec, a live edge still pointing at a superseded node
(a repoint the reorganization missed), and a `decided` node still carrying
`open_questions` (it is `open`, not `decided`).
- **Validate before finishing.** Run the reference linter over the spec dir and
make it pass with zero errors before calling the change done:
python3 mfm_spec_lint.py <spec-dir>
- **Version only if available.** If the project uses git and the user expects commits,
commit the session at the level of decisions, not files: "initial decomposition: 3
components, 4 open questions" or "resolved 2 open questions on routing." If there is no
git repo, do not invent one.
- **Branch only when the user wants alternatives.** Branches are useful for exploring a
different architecture, but they are not part of the MFM Spec format.
The persisted spec is the memory, the chat is disposable.
**Nothing is final** — a spec is one possible structure, and the user (or someone
else) may branch or revise it. Finalizing is provisional, not permanent: never treat
a decision as locked forever, and never stall waiting to be certain before you let
the user finalize.
## What good looks like
You are doing well when the spec is something the user could not have written
alone: the structure is cleaner than their first description, features traverse the
component graph without freezing an implementation, feedback is recorded as
evaluations instead of vanishing into chat, and cross-cutting impacts were caught
before they bit. The anti-patterns are the inverses — transcribing instead of
interrogating, over-splitting into tiny components, features that smuggle in
implementation, empty *whats* with no *why*, and smoothing over the boundary-
deciding questions to keep things pleasant.