agentleFS
NitinJNitinJ/specforge/skills/convert-spec/SKILL.md

convert-spec

Skill4 starsChanged 2 months agoMITView on GitHub

Convert an existing design/spec file into a SpecForge spec in the store. Use when the user asks to "convert <file> to a spec", "import this design doc", or "turn this markdown/HTML into a SpecForge spec". Handles two cases: an existing SpecForge-style .html is ingested as-is; a .md or freeform design doc is re-authored into a full house-style HTML spec. Attaches the result to this session and lints before finishing.

The file

We split this skill into the rules it gives an agent

5 rules. About 0 are common, 0 are distinctive, and 5 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 5

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Do not go looking for references/spec-language.md to supplement it: a rule the owner deleted is deleted.

    line 76
  2. Very specific:

    Read the report before you touch anything.

    line 79
  3. Very specific:

    Read the house rules: ${CLAUDE_PLUGIN_ROOT}/templates/house-rules.md, and the language contract, which is the language field above rather …

    line 95
  4. Very specific:

    Keep every <section id="…">, the theme CSS, and the floating <nav class="toc"> (update TOC links to match the sections you keep).

    line 106
  5. Very specific:

    Do not start a watcher or poll while idle.

    line 147

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

convert-spec

Bring an existing file into the SpecForge store. ${CLAUDE_PLUGIN_ROOT} below denotes the installed plugin directory. Claude and Pi export it; Codex provides the exact value in SpecForge SessionStart context. Substitute it in every path and shell command.

1. Inspect the source

  • The user names a file ($ARGUMENTS). Read it and decide:
    • Already a SpecForge-style HTML spec (has the section ids / theme contract / structured plan) → ingest as-is (step 2A).
    • A .md → convert with import-md, then edit the result (step 2B). Do not hand-author a markdown source: the CLI does the mechanical part faithfully and reports what it could not read, which is a better starting point than a blank scaffold and your reading of the file.
    • A freeform .html design doc → author it into a scaffolded spec by hand (step 2C). There is no deterministic path for arbitrary HTML.
  • Infer the spec type from the source — research (a findings report), design (a design doc, no plan), design-impl (design + a plan), or impl (a build plan). When the source is none of those, use general: the scaffold plus a TL;DR, sections taken from the source's own headings. Pass it as --type below. A converted document keeps its own shape, so general is the right answer more often here than when authoring from scratch.

2A. Ingest an existing HTML spec

node "${CLAUDE_PLUGIN_ROOT}/lib/specforge-cli.mjs" import "<file>" --title "<title>" --type <type> --model <your model id>

Prints { id, htmlPath, url, status, type, language } — the file is copied into the store, attached to this session, daemon ensured. Apply language to anything you write into this spec, on the terms in 2B. Lint htmlPath (step 3). If lint fails because it isn't house-style, fall back to 2C and author into the htmlPath you already have; 2C says so too, and running create there would leave this spec behind and attach a second one. Not 2B: that path runs a markdown parser, and handing it HTML would mechanically reconvert the document instead of shaping it.

2B. Convert a .md — deterministic pass first, then edit

A markdown source is converted by the CLI, not by hand. It reads the file, maps its headings onto sections, rebuilds any plan into the data-sf-* markup, inlines the images that sit beside it, and produces a lint-passing spec:

node "${CLAUDE_PLUGIN_ROOT}/lib/specforge-cli.mjs" import-md "<file>" --model <your model id> [--title "<title>"] [--type <type>]

--model is your own model id; the harness is detected. It credits you as the converted spec's author, the same way create does.

It prints { id, htmlPath, url, type, status, language, report }. Then edit htmlPath — the deterministic pass gives you a valid document to improve, never a blank scaffold to fill.

language is the writing contract in force, and it is the whole of it. Not a note added to a contract you read somewhere else: it already contains SpecForge's own rules, unless this store's owner edited or removed them. Follow what it says and nothing it does not, and apply it to everything you write while improving the converted document. Do not go looking for references/spec-language.md to supplement it: a rule the owner deleted is deleted. They edit this in the Configuration pane, under Language.

Read the report before you touch anything; it is the list of what needs you:

  • unsupported — constructs the parser could not read (setext headings, footnotes, reference links), each with its line number. The content is in the spec as plain text; convert it to house markup by hand.
  • assetsDropped — images that were not inlined, with the reason (missing, too large, outside the source directory). Say so when you hand off.
  • lint — PASS normally. If it is FAIL, lintFailures names the checks.
  • sections — how many the source produced.

Type: omit --type and the import is a general spec, which imposes no section set — usually right, because a converted document keeps its own shape. Pass --type only when the source really is a design / research / impl doc.

Then improve the result:

  • Read the house rules: ${CLAUDE_PLUGIN_ROOT}/templates/house-rules.md, and the language contract, which is the language field above rather than a file. This is where an original's essay voice leaks through: convert the content, not the register.
  • Map the source onto the type's sections exactly as the create-spec skill describes (design / research / design-impl / impl) — adapt sections to the content; keep stable unique ids, the theme, and the floating TOC in sync. For impl types build impl-plan as Stages → Tasks (data-sf-stage/data-sf-task/ data-sf-status, one stage = one PR, each task a verify: note) mirrored into task-tracker, and leave the Runtime stubs. Preserve the author's intent; don't invent scope.
  • Keep every <section id="…">, the theme CSS, and the floating <nav class="toc"> (update TOC links to match the sections you keep).

For a spec general no longer fits (the source turned out to be a design with a build plan), rescaffold with create --type <type> and move the content across; do not grow a plan inside a general spec and call it typed.

2C. Author a freeform HTML doc into a spec

Arbitrary HTML has no deterministic path: it carries someone else's structure and styling, and there is nothing to map it onto mechanically. It gets authored.

Arriving from 2A (an HTML spec that turned out not to be house-style): you already have an htmlPath in the store, attached to this session. Author into that file. Do not run create — it would make a second spec and leave the malformed one attached, so a later edit or handoff could pick up either. The language 2A printed still applies: this is the authoring pass it was for.

Arriving from step 1 with a freeform HTML doc and no spec yet, scaffold one:

node "${CLAUDE_PLUGIN_ROOT}/lib/specforge-cli.mjs" create --title "<title>" --type "<type>" --model <your model id>

It prints { id, htmlPath, url, type, language }. Author into htmlPath, following the same house rules, section mapping and language contract as 2B above, and applying language on the same terms.

3. Lint (must pass)

node "${CLAUDE_PLUGIN_ROOT}/lib/lint-spec.mjs" <htmlPath>

Fix and re-run until PASS. Do not finish on a failing lint.

4. Hand off + arm review delivery

  • Print the spec url. The spec is attached to this session. Mention the original file is left untouched (its path is recorded as the spec's origin).
  • In Codex, finish the turn: the host-owned watcher delivers browser comments automatically. Do not start a watcher or poll while idle. For explicit pickup, run node "${CLAUDE_PLUGIN_ROOT}/lib/specforge-cli.mjs" review-wait once and follow reason when ready is true. A next-turn result means finish without re-arming.
  • In Claude Code, run that command as one background task per session and re-arm it after handling delivered work. Pi owns delivery through its extension.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.