⚠️ Notice: specflow → persistent

spec-flow has been renamed to persistent due to naming conflicts. All commands now use persistent instead of specflow. The npm package is now @kousthubha/persistent.

Documentation

Everything you need to use persistent in your project.

Installation

Run without installing (recommended for first use):

bash
npx @kousthubha/persistent init

Or install globally:

bash
npm install -g @kousthubha/persistent

Requires Node 18+. No API keys needed for core features — only analyze uses Anthropic.

persistent init

Full project bootstrap. Run once from your project root.

bash
persistent init [--agent <id>] [--obsidian <path>] [--dry-run]

What it does:

Flags

--agent <id>Force a specific agent. Values: claude-code, cursor, copilot, windsurf, opencode, continue, aider
--obsidian <path>Absolute path to your Obsidian vault root (the folder containing .obsidian/)
--dry-runPreview everything that would be written without touching any files

persistent spec

OpenSpec lifecycle — propose, validate, archive, list, regenerate SEED.

persistent spec "add feature name"
Propose a new spec. Creates SPECS/active/<slug>/ with proposal.md, design.md, tasks.md.
persistent spec --validate <slug>
Validate a spec against SEED.md constraints and generation-spec rules. Catches missing sections, SEED conflicts.
persistent spec --archive <slug>
Archive a completed spec. Extracts patterns from design.md, merges into SEED.md. Moves spec to SPECS/archive/. Writes spec back to Obsidian vault.
persistent spec --list
List all active specs with task completion progress.
persistent spec --seed
Regenerate SEED.md from all archived spec patterns.

Spec file structure

text
SPECS/
├── SEED.md                          ← architectural DNA (commit)
├── active/
│   └── add-razorpay-payments/
│       ├── proposal.md              ← problem, solution, scope
│       ├── design.md                ← data model, API, constraints
│       └── tasks.md                 ← actionable checklist
└── archive/
    └── 2026-03-11-add-payments/     ← completed specs

persistent skill

Skills.sh lifecycle — search, create, evolve, update installed skills.

persistent skill --search "react auth"
Search the skills.sh community registry for matching skills.
persistent skill --list
List all installed skills with source (registry/builtin/placeholder) and version.
persistent skill --create <owner/name>
Create a skill from your project patterns + tagged Obsidian notes. Uses AI if ANTHROPIC_API_KEY is set.
persistent skill --evolve <owner/name>
Merge new patterns into an existing skill file.
persistent skill --update
Update all installed skills to latest versions via skills.sh CLI.
persistent add-skill <owner/name>
Install a specific skill directly. Falls back: registry → builtin → placeholder.

Install priority

For each skill: skills.sh registrybundled builtinplaceholder file. Manifest tracked at .skills/.manifest.json.

persistent sync

Bidirectional Obsidian sync. Pulls notes in, routes them by tag, pushes specs and SEED back to vault.

bash
persistent sync                          # bidirectional (default)
persistent sync --one-way               # pull from vault only
persistent sync --discover              # auto-find Obsidian vaults on this machine
persistent sync --pin "Projects/App"    # pin a vault folder to always pull

Tag routing

#spec, #decision, #architectureOpenSpec — feeds spec proposals and SEED.md evolution
#pattern, #skill, #best-practice, #conventionSkills.sh — feeds skill creation and evolution
#persistent, #hot, #bug, #workflowMemory — MEMORY/INDEX.md (agent reads this)

Write-back (bidirectional)

After sync, persistent writes back to <vault>/persistent/:

persistent analyze

AI deep-dive into your actual code. Generates project-specific skill files that reflect how YOUR project uses each library.

bash
persistent analyze                        # analyze all detected skills
persistent analyze --key sk-ant-...      # pass API key directly
persistent analyze --force               # regenerate even if files exist
persistent analyze --only stripe/node    # target specific dependencies

How it differs from init

What analyze generates

Uses claude-haiku-4-5 via Anthropic API — fast and cheap. Set ANTHROPIC_API_KEY in env to avoid passing --key every time.

Slash commands

For Claude Code and OpenCode, persistent init creates native slash commands. Type /persistent- in the AI chat to see them.

These are AI-native — the AI agent itself executes these commands by reading files and analyzing code. They appear as instant suggestions in the chat interface.

/persistent-initAI reads package.json + codebase → generates CLAUDE.md context + SPECS/SEED.md + .skills/ from scratch (re-bootstrap)
/persistent-specAI generates or validates specs via OpenSpec. Read SPECS/SEED.md + MEMORY/INDEX.md for context.
/persistent-skillAI analyzes your actual code patterns → creates/evolves project-specific skills with examples from your source
/persistent-syncAI reads MEMORY/INDEX.md + Obsidian vault notes → routes by tag → updates SEED.md and skills
/persistent-analyzeAI performs deep code analysis → generates detailed skill files with architecture insights and gotchas

Where commands are stored

After persistent init, slash commands are written to:

text
.claude/commands/
├── persistent-init.md
├── persistent-spec.md
├── persistent-skill.md
├── persistent-sync.md
└── persistent-analyze.md

.opencode/commands/
└── (same files)

# Each .md file contains instructions for the AI to read and execute
# The AI reads these when you type /persistent-* in the chat

How they work

Supported agents: Claude Code (.claude/commands/) and OpenCode (.opencode/commands/). Other agents (Cursor, Copilot, etc.) use CLI commands directly from terminal.

Config file (.persistent.json)

Auto-created by persistent init. Persists state between commands.

json
{
  "agent": "claude-code",
  "agents": ["claude-code", "cursor"],
  "agentRoot": "/absolute/path/to/monorepo/root",
  "stack": ["nextjs", "prisma", "clerk", "stripe"],
  "skills": ["vercel/nextjs", "prisma/best-practices", "stripe/stripe-node"],
  "obsidianPath": "/Users/you/obsidian/MyProject",
  "pinnedFolders": ["Projects/MyApp", "Architecture"],
  "lastSync": "2026-03-11T09:00:00.000Z",
  "activeSpec": null
}

.gitignore

bash
# persistent — do not commit these
MEMORY/INDEX.md        # personal vault content
.persistent.json         # contains local paths (vault, agentRoot)
.skills/               # downloaded skills — regenerated on demand

# commit these
# CLAUDE.md (or agents.md, .cursor/rules/, etc.)
# SPECS/
# .persistent/generation-spec.json

Plugin API

Use persistent as a library in your own CLI tool or editor extension.

typescript
import { createPersistentPlugin } from "@kousthubha/persistent/plugin";

const sf = await createPersistentPlugin("/path/to/project");

// Optional: register your CLI's native AI for spec-driven generation
await sf.registerCliAI(cliAIInstance);

// Bootstrap
const result = await sf.detectAndSetup({
  agents: ["claude-code", "cursor"],
  obsidianPath: "/path/to/vault",
  useCliAI: true,  // use registered AI to generate context files
});
// result.stack  → ["nextjs", "prisma"]
// result.files  → ["CLAUDE.md", "SPECS/SEED.md", ...]
// result.method → "ai-driven" | "static"

Detection only

typescript
const info = await sf.detect();
// { stack: ["nextjs","prisma"], currentAgent: "cursor", availableAgents: [...] }

OpenSpec lifecycle

typescript
await sf.proposeSpec("add payments");
await sf.validateSpec("add-payments");
await sf.archiveSpec("add-payments");
const specs = await sf.listSpecs();    // [{ slug, progress }]
await sf.regenerateSeed();

Skills lifecycle

typescript
const results = await sf.searchSkills("react auth");
await sf.discoverSkills();           // auto-discover for detected stack
await sf.createSkill("team/patterns");
await sf.evolveSkill("team/patterns");
await sf.updateSkills();
const installed = await sf.listSkills();

Obsidian

typescript
await sf.syncBidirectional("/path/to/vault");
const specNotes  = await sf.getSpecNotes("/vault");   // #spec, #decision
const skillNotes = await sf.getSkillNotes("/vault");  // #pattern, #skill

Obsidian setup

Auto-discover vaults

persistent reads Obsidian's own config JSON to find your vaults:

bash
persistent sync --discover
# Found vaults:
#   MyVault     /Users/sky/Documents/MyVault
#   WorkNotes   /Users/sky/obsidian/WorkNotes

Connect manually

bash
persistent init --obsidian "/absolute/path/to/vault"
# vault root = folder containing .obsidian/ directory

Vault path by OS

WindowsC:\Users\<you>\Documents\<VaultName>
macOS/Users/<you>/Documents/<VaultName>
Linux~/obsidian/<VaultName>

Tagging notes

Inline tag (anywhere in note body):

markdown
#persistent
#decision  your decision here

Front-matter tags:

yaml
---
tags: [persistent, decision, architecture]
---

generation-spec.json

The stable source of truth for all context generation. Lives at .persistent/generation-spec.json in your project — commit it.

It defines: file schemas (required sections, token limits), validation rules, AI generation prompts, integration settings for OpenSpec/skills/Obsidian. Follows semantic versioning — switching AI models or CLI tools doesn't break your specs because the spec is the source of truth, not the model.

bash
# Initialize generation-spec in your project
persistent init  # creates .persistent/generation-spec.json automatically