Skip to content

feat(specs): user-definable spec types as type cards (skills-for-specs) - #232

Draft
Rustam Sadykov (SBOne-Kenobi) wants to merge 5 commits into
mainfrom
spec-system-architecture-design
Draft

feat(specs): user-definable spec types as type cards (skills-for-specs)#232
Rustam Sadykov (SBOne-Kenobi) wants to merge 5 commits into
mainfrom
spec-system-architecture-design

Conversation

@SBOne-Kenobi

Copy link
Copy Markdown
Collaborator

A skills-like system for spec types: users/teams define their own kinds of specs as type cards — one markdown file per type, human-first prose plus a small machine-readable frontmatter core — registered per project and resolved through a registry that agents, tools, and the UI all read.

Design history (approaches considered, prior-art research, decision rounds) lives in the task-spec .thinkrail/context/TASK-spec-type-system.md (gitignored scratch); the durable decisions are promoted into packages/spec-graph/SPEC.md and the touched module specs.

What a type card is

---
name: decision
title: Decision record (ADR)
description: One significant, hard-to-reverse decision — context, options, outcome.
lifecycle: durable            # durable = ground truth · ephemeral = serves one piece of work
home: docs/decisions/          # a default, never enforced
sections: [Context, Options considered, Decision, Consequences]
statuses: [proposed, accepted, superseded]
---
Use when a choice is significant and hard to reverse; one decision per file.
## Quality bar
- States the rejected options and why — the part code can never reveal.
  • Registry precedence: project .pi/spec-types/*.md (committed, team vocabulary) → (P2) user ~/.pi/agent/spec-types/seven built-ins: the original five (task-spec = ephemeral) plus charter (the project's declared stance on specs) and decision (MADR-shaped ADR).
  • Lifecycle is first-class: durable specs are ground truth; ephemeral specs serve one piece of work and end by promotion into durable specs, then retire. Location is a default, never a rule.
  • Advisory-only: the registry gates authoring (spec_create) with helpful errors; it never influences graph construction or which files are specs. Conformance warnings in spec_validate are recorded for P2.

Changes by layer

layer change
pi-spec-graph/core card parser (full YAML, fence-aware ## Template extraction) + SpecTypeRegistry (revalidate-on-read); built-ins embedded as string constants (bundle-safe — core compiles into the binary); frozen SPEC_TYPES tuple removed
pi-spec-graph/tools new spec_types (list, or one card in full); spec_create validates type + per-card statuses against the registry and scaffolds from the card (Template → sections)
skill + workflow registry-driven Types section; read the card before authoring norm; cards refine global rules, never override them
wire (v38) SpecGraphSnapshot.types (SpecTypeInfo[]) + scoped spec.saveTypeCard (slug + is-a-card validated server-side; writes only .pi/spec-types/ — deliberately not a general fs write)
server spec registry mapped into the snapshot; projectHasSpecs lifecycle-driven (custom ephemeral types can't signal "set up")
web (prototype) type-aware Specs rows (description tooltips, ephemeral specs dimmed/italic), a types legend, and the type constructor dialog (guided form — the hints are the card schema's meaning — with a live markdown preview)

Where to find it in the UI

Right panel → SPECS tab → scroll to the bottom of the tree → the collapsed "SPEC TYPES (N)" row. Its button opens the constructor. (Known prototype limitation: the legend scrolls with the tree instead of being pinned — easy to miss on a long graph; candidate P2 polish.)

Specs tab — legend collapsed at the bottom

Specs panel

Legend expanded — the seven built-ins, lifecycle marked

Types legend

The type constructor — every field hint explains the card schema

Constructor

Live preview of the exact markdown that will be written

Preview

After save — runbook — PROJECT joins the registry (SPEC TYPES (8))

Saved

Ephemeral specs render dimmed/italic in the tree (our own task-spec, dogfooded)

Ephemeral

Verification

  • check:deps · check:seams · lint · typecheck — green
  • Unit: 69 (spec-graph) · 581 (server) · 475 (web) — green
  • Full e2e: all 8 shards, 203 tests — green (one pre-existing history-search CPU-contention flake, green in isolation, unrelated area)
  • The screenshots above are a live end-to-end run of the new path: constructor → spec.saveTypeCard.pi/spec-types/runbook.md on disk → fs-tick refetch → registry shows the new type

Recorded for P2 (not in this PR)

User-local ~/.pi/agent/spec-types/ · advisory conformance warnings in spec_validate (incl. near-duplicate-prose detection) · pinned legend + viewer polish · custom link kinds (supersedes) · covers-based drift detection (holds architecture.md's deferral)

danyaberezun and others added 5 commits August 13, 2026 13:01
A skills-like system for spec types: one markdown card per type (human-first
prose + a small machine-readable frontmatter core) resolved through a registry
— project .pi/spec-types/ wins over seven built-ins (the original five plus
charter and decision). lifecycle (durable/ephemeral) is first-class; ephemeral
specs end by promotion, never authority.

- pi-spec-graph/core: card parser + SpecTypeRegistry (revalidate-on-read);
  built-ins embedded as string constants (bundle-safe — core is compiled into
  the binary); SPEC_TYPES tuple removed, the registry replaces it
- tools: new spec_types (list, or one card in full); spec_create validates
  type + per-card statuses against the registry and scaffolds from the card
  (Template > sections)
- skill: registry-driven Types section + read-the-card-before-authoring norm
- wire v38: SpecGraphSnapshot.types + scoped spec.saveTypeCard (slug and
  is-a-card validated server-side; writes only .pi/spec-types/)
- server/spec: registry in the snapshot; projectHasSpecs lifecycle-driven
- web: type-aware Specs rows (description tooltips, ephemeral dimming), a
  types legend, and the SpecTypeDialog constructor (guided form, live preview)
@SBOne-Kenobi

Copy link
Copy Markdown
Collaborator Author

The chat side — the agent using the type registry (live run)

The other half of the system: what the agent does with type cards in a chat. This is a real claude-sonnet-5 run against a throwaway sample repo (fresh git repo, one README, zero specs), driven end-to-end through the UI.

Prompt: "Run spec_types to list this project's registered spec types. Then read the decision type card and create one decision spec with spec_create …"

The run: tool steps → result → the divider's "1 spec" chip → the Specs panel updates

Chat run

  • 3 steps · spec_types ×2, spec_create — the agent discovered the types, read the decision card, then created against it (exactly the norm the skill sets).
  • The turn divider counts 3 tool calls · 1 spec · 12s — the "1 spec" chip classifies the written file as a spec off the same registry-backed snapshot the panel renders.
  • Right panel: "Use SQLite for local storage — DECISION" appears without a manual refresh.
  • (The two red bubbles above are honest transcript history: Anthropic returned overloaded_error twice before we switched models — provider weather, not this PR.)

spec_types expanded — the registry as the agent sees it

Tools expanded

Each entry carries name / title / description / lifecycle / origin — the same card data the UI legend shows, one source of truth.

What landed on disk (card-driven scaffold, per-type statuses)

---
id: decision-use-sqlite
type: decision
status: proposed        # validated against the decision card's proposed|accepted|superseded
title: Use SQLite for local storage
---

## Context

## Options considered

## Decision

## Consequences

The headings come from the decision card's sections — the agent never invented a structure, and status: proposed passed because the card narrows the vocabulary for this type.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants