# Intentgraph Spec Writer

> Use when writing or editing intent, constraint, or in-spec decision markdown files under /spec/. Enforces frontmatter schema, outcome-focused phrasing, and links to ADRs.

- Skill: `quinnaho/intentgraph-spec-writer` (Agent Skill)
- Install (CLI): `npx skillmds@latest add quinnaho/intentgraph-spec-writer`
- Raw SKILL.md: https://api.skillmd.com/api/skills/quinnaho/intentgraph-spec-writer/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing
- Author: quinnaho (https://skillmd.com/u/quinnaho)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/quinnaho/intentgraph-spec-writer

---


# IntentGraph Spec Writer

You write and edit the markdown contracts under `/spec/`. These files are the seed for the live graph and they are commit-tracked artifacts the team round-trips through. Treat them like a public API.

## When you activate

Activate when:
- Adding a new intent, constraint, or in-spec decision.
- Editing an existing one (almost always: also bump `verified_by` references and consider an ADR).
- Refactoring frontmatter to follow the schema.

If the change involves an architectural decision (e.g., "do we need a new constraint kind?"), stop and escalate to `intentgraph-architect`.

## Frontmatter schema

Every file under `/spec/intents/`, `/spec/constraints/`, and `/spec/decisions/` starts with YAML frontmatter:

```yaml
---
id: <kebab-case-stable-id>            # required, unique within its folder
title: <human-readable title>         # required
parent: <parent-id-or-null>           # required; null at top level
verified_by: [obligation-id, ...]     # required for constraints; optional for intents
confidence: extracted | inferred | semantic | asserted   # required
adrs: [0001, 0004]                    # optional; ADRs that govern this spec
---
```

- `id` is what the graph uses as the stable handle. Once committed, never rename — supersede with a new file and link.
- `title` is the human label. Update freely.
- `parent` is the concept boundary parent (Daniel Jackson concept design). Use the concept's id.
- `verified_by` lists obligation ids that verify this constraint or intent. Empty array is allowed only at confidence `extracted` or `inferred`.
- `confidence` follows Tech-Spec §4.1 enum.
- `adrs` is a courtesy backlink — handy for grep, not strict.

## Body conventions

- **Intent statements are outcome-focused, not implementation-focused.** "User can recover access without contacting support" is an intent. "We use email magic links" is an implementation choice that belongs in a `decision` file or an ADR.
- **Constraints are predicates.** They state a verifiable property: "Authentication response time is under 500ms at p95," "Every exported symbol in `packages/skill` has a `realizes` edge to an intent." Each constraint links to one or more obligations under `verified_by`.
- **In-spec decisions** are smaller than ADRs — they record a choice within a feature ("we use TOTP, not SMS"). ADRs are for architectural decisions that cross packages or pillars.

## How to work

1. **Read `/spec/<folder>/README.md`** if it exists, for any folder-specific conventions.
2. **Pick the id**: kebab-case, ≤4 words, stable.
3. **Resolve `parent`**: read the concept boundaries already in `/spec/`; if a new top-level concept is needed, that's an architect-level call — escalate.
4. **Draft the file**: frontmatter + body. Keep the body short — this is a contract, not an essay.
5. **Link `verified_by`**: if no obligation exists yet, leave the array empty and note in the body "needs obligation; invoke `intentgraph-verifier-author`."
6. **Cross-link**: if this spec is governed by an ADR, list the number under `adrs`. If this spec realizes a parent intent, the body should say so explicitly.
7. **Validate**: run `pnpm tsx scripts/check-agent-config.ts` if it exists (it validates frontmatter schemas across the project).
8. **Commit pre-flight**: spec changes are documentation, but they should still pass `pnpm typecheck && pnpm lint && pnpm test` because some build steps consume frontmatter.

## What you refuse

- Renaming an existing `id`. Supersede instead — leave the old file and link to the new one.
- Embedding implementation details in an intent statement.
- Adding a new constraint kind. That's an architectural decision (Tech-Spec §4.3 obligation `kind` enum) — escalate to architect.

## Examples

A good intent:

```markdown
---
id: drift-visible-on-save
title: Drift becomes visible on save
parent: spec-driven-loop
verified_by: [drift-visible-within-2s-on-save]
confidence: asserted
adrs: [0003]
---

When a developer saves a TypeScript file in the workspace, any divergence
between the saved code and the intents that govern it surfaces as a drift
event on the affected intent nodes within 2 seconds.

Realizes: `intent: spec-driven-loop`. Verified by:
`obligation: drift-visible-within-2s-on-save`.
```

A good constraint:

```markdown
---
id: agentrunner-is-only-model-path
title: AgentRunner is the only path to model providers
parent: agent-orchestration
verified_by: [eslint-agent-runner-only, ci-no-direct-ai-imports]
confidence: asserted
adrs: [0004, 0005]
---

No file outside `packages/skill/src/agent-runner/` may import the model-call
surface (`generateText`, `streamText`, `generateObject`, `streamObject`,
`embed`, `embedMany`) from `ai`. Enforced by ESLint rule
`intentgraph/agent-runner-only` and a CI gate.
```

