npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@zurab/spec-first

v0.14.1

Published

Spec-First — CLI и библиотека для управления product passports (constitution + specs + US/FR/AC) поверх @zurab/mdmanager

Readme

@zurab/spec-first

CLI и библиотека для управления product passports на базе @zurab/mdmanager.

История изменений: CHANGELOG.md.

Spec-First вводит модель Product → Constitution → Specs → User Stories → Functional Requirements → Acceptance Criteria поверх markdown с HTML-маркерами. Каждый AC обязан иметь runner — runner превращает критерий приёмки в исполняемый тест, статус (✅/❌) автоматически попадает в собранный паспорт.

С версии 0.14.0 доступен второй режим работы — goal-mode: hypothesis-driven цели с персистентным контекстом (principles, bashrunner-чек-лист, dependent-files, related-ARDs, deferred-tasks). Подходит для исследовательской фазы перед формализацией спек. См. раздел Goal-mode.

Установка / запуск

# Через npx (рекомендованный режим публикации)
npx -p @zurab/spec-first spec-first --help

# Локально в монорепо
node tools/spec-first/dist/cli/spec-first.js --help

@zurab/mdmanager — peerDependency. Устанавливается отдельно потребителем.

Two-level конфигурация

В одном workspace N продуктов. Конфиги двухуровневые:

| Уровень | Файл | Назначение | |---|---|---| | Workspace | .spec-first.json (root) | Где искать продукты, общие runners (global/extend) | | Продукт | <product>/.spec-first.product.json | Имя/title, пути к constitution/template, локальные runners |

Discovery: spec-first ищет root config walk-up от cwd; затем сканирует passportsDir рекурсивно — продукт = директория, содержащая productConfigPattern (.spec-first.product.json по умолчанию).

Пример root .spec-first.json

{
  "passportsDir": "docs/product-passports/products",
  "productConfigPattern": ".spec-first.product.json",
  "discoverBy": "config-file",
  "globalRunners": [],
  "extendRunners": []
}

Пример per-product .spec-first.product.json

{
  "id": "billing",
  "title": "Биллинг",
  "constitution": "constitution.md",
  "passportTemplate": ".template.md",
  "passportOutput": ".product.passport.md",
  "specsDir": "docs/specs",
  "specFilePattern": "*.spec-first.ai.md",
  "specTemplate": "spec.template.md",
  "runners": []
}

Все пути в per-product config резолвятся относительно директории продукта. Минимальный валидный конфиг — { "id": "billing" }.

Hooks (post-runner хуки)

Поле hooks в per-product config — объект с именованными триггерами. Каждый триггер содержит список CLI-команд, которые выполняются автоматически в нужный момент цикла реализации. Команды запускаются через sh -c из корня workspace (там где лежит .spec-first.json).

{
  "id": "billing",
  "hooks": {
    "after-close-ac": ["pnpm nx lint billing", "pnpm nx test billing"],
    "after-close-all": ["pnpm nx build billing && echo 'Готово!'"]
  }
}

Триггеры

| Триггер | Когда срабатывает | Env-переменные | |---|---|---| | after-close-ac | После runner PASS при close ac | SPEC_FIRST_HOOK, SPEC_FIRST_PRODUCT, SPEC_FIRST_AC_ID | | after-close-all | После успешного завершения close all | SPEC_FIRST_HOOK, SPEC_FIRST_PRODUCT, SPEC_FIRST_CLOSED_ACS (CSV) |

Важно: after-close-ac не запускается внутри close all — только after-close-all. Это позволяет запускать тяжёлые команды (build, lint) один раз в конце батча, а не после каждого AC.

При запуске run --product (re-validation без смены статусов) хуки не запускаются.

Семантика fail

Если любая команда хука завершается с ненулевым кодом:

  • close ac — AC не закрывается (остаётся open), exit 1.
  • close all — команда завершается с exit 1.

Команды выполняются последовательно. Первый fail останавливает всё.

Пример: автоматический lint после каждого AC

# Добавить хук
spec-first set hooks --product billing --trigger after-close-ac --add "pnpm nx lint billing"

# Теперь при каждом 'close ac' автоматически запустится lint:
spec-first close ac SPEC-001:AC-003
# [hook] > pnpm nx lint billing
# [hook] ✔ OK
# ✓ SPEC-001:AC-003: закрыт (1240ms)

Пример: build + уведомление после закрытия всех задач

spec-first set hooks --product billing --trigger after-close-all \
  --add "pnpm nx build billing"
spec-first set hooks --product billing --trigger after-close-all \
  --add "echo Закрыто АС: \$SPEC_FIRST_CLOSED_ACS"

spec-first close all --product billing
# ...
# [hook] > pnpm nx build billing
# [hook] ✔ OK
# [hook] > echo Закрыто АС: SPEC-001:AC-001,SPEC-001:AC-002
# [hook] ✔ OK

Управление хуками через CLI

# Добавить команду (идемпотентно — повторный add игнорируется)
spec-first set hooks --product <id> --trigger after-close-ac --add "pnpm nx test myapp"

# Удалить конкретную команду (по точному совпадению строки)
spec-first set hooks --product <id> --trigger after-close-ac --remove "pnpm nx test myapp"

# Очистить весь триггер
spec-first set hooks --product <id> --trigger after-close-all --clear

# Посмотреть текущее состояние хуков
spec-first get config --product <id>

Резолвинг runner'ов (по возрастанию приоритета)

  1. bundled (внутри пакета @zurab/spec-first/runners/)
  2. globalRunners (root config)
  3. extendRunners (root config — пользовательские)
  4. product.runners (per-product config — локальные для продукта)

При совпадении prefix выигрывает источник с большим приоритетом.

CLI команды

spec-first без аргументов печатает help. Все команды поддерживают -c, --config <path> для явного root config.

Чтение

spec-first get products                    список всех продуктов
spec-first get product <id>                карточка продукта (resolved config)
spec-first get specs --product <id>        список спек продукта
spec-first get next-task [--product <id>]  первая незакрытая FR/AC + контекст
spec-first get fn --spec <id>              FR указанной спеки
spec-first get list <us|fr|ac|spec>        с фильтрами --product/--spec/--status
spec-first get replaced-by <id>            миграционная цепочка для deprecated
spec-first get constitution <product>      печать constitution.md
spec-first get config [--product <id>]     resolved config (с merged runners)
spec-first get template <product>          --kind passport|spec
spec-first get spec-batch-run <spec-id>    SPEC-016: batchRun из frontmatter (--json → {specId,command})

Создание / мутации (CLI-only invariant — markdown руками не редактируем)

spec-first init [--check] [--force]                   идемпотентная инициализация workspace
spec-first create product <id> [--title <t>]          бутстрап продукта (вкл. constitution)
spec-first create spec <product> <slug> --title <t>   новая спека из шаблона
spec-first add us <spec-id> --text "<...>"            US-NNN с маркерами
spec-first add fn <us-id> --text "<...>"              FR-NNN под US (FQN: SPEC-N:US-M)
spec-first add ac <fr-id> --text "<...>" \
    --runner <prefix> --block <json>                  AC + runner-блок
spec-first add constitution <product> [--file|--text] создать конституцию (если её нет)
spec-first update <kind> <id> --text "<новый текст>"  изменить текст элемента
spec-first set problem <spec-id> --context/--pain/--goal | --file
spec-first set constitution <product> --file|--text   заменить (--file ИЛИ --text inline)
spec-first set template <product> --kind passport|spec --file <path>
spec-first set spec-batch-run <spec-id> --command "<bash>"  SPEC-016: установить batchRun (с placeholder-поддержкой)
spec-first set spec-batch-run <spec-id> --clear             SPEC-016: удалить batchRun из frontmatter
spec-first delete constitution <product> [--hard]     soft (пустой файл) или hard (rm)

add constitution отказывает (exit 1), если файл уже существует и не пуст — используйте set или delete + add. delete --soft (default) очищает содержимое, оставляя путь валидным; --hard физически удаляет файл.

Устаревание

spec-first deprecate <kind> <id> --replaced-by <ids>           с заменой (CSV/FQN)
spec-first deprecate <kind> <id> --no-replacement --reason ""  без замены
spec-first deprecate fr FR-001 --no-cascade                    не каскадировать

При deprecate родителя потомки получают status=deprecated с deprecationReason="parent <id> deprecated" (если не указан явный replacedBy). FQN форма SPEC-NNN:ID поддерживается везде, где id может быть неоднозначным.

Иерархическое закрытие (status=done через runner-PASS)

spec-first close ac <id>      AC: автоматически прогоняет runner; PASS ⇒ done
spec-first close fr <id>      FR: требует чтобы все non-deprecated AC были done
spec-first close us <id>      US: требует чтобы все non-deprecated FR были done
spec-first close spec <id>    Spec: требует чтобы все non-deprecated US были done
spec-first close all [--product <id>] [--spec <id>] [--dry-run]
spec-first verify-closed [--product <id>]    exit 1 если есть open/draft

close all идёт в порядке AC → FR → US → Spec, перезагружает индекс между фазами. На каждой ошибке: понятный reason (что и почему нельзя закрыть, список блокеров с id/status/text). update --status done тоже теперь делегируется в close — нет escape-hatch.

Re-validation (run — стрим-вывод без смены статусов)

spec-first run                              все AC всех продуктов
spec-first run --product <id>               только продукт
spec-first run --spec <id>                  только спека
spec-first run ac <id>                      один AC (поддерживает FQN)
spec-first run --json                       машинный вывод
spec-first run --timeout <ms>               таймаут одного runner (default 600000 = 10мин)
spec-first run --no-batch                   bypass batch-режима глобально для всех спек
spec-first run --no-batch=SPEC-NNN,SPEC-MMM bypass batch-режима точечно для указанных спек

Stream-формат: при старте каждой Spec/US/FR печатается префикс с заголовком, при завершении AC — ✓/✗ <id> [runner, durationMs] <tail-payload-or-error>. После каждого FR/US/Spec — агрегат Σ: pass/total + sum durationMs. В конце — Total: число AC, wall-time, sum AC time, и список FAIL-ов с reason от runner-а. Exit 0 если все PASS, 1 если хоть один FAIL. Файлы НЕ меняются.

Batch-режим спеки (SPEC-016)

Если у спеки задано поле batchRun в YAML-frontmatter, spec-first run прогоняет её одной bash-командой вместо итерации по отдельным AC. Вердикт определяется exit code (0 = PASS). Это ускоряет прогон для спек, у которых уже есть pnpm nx test или аналог.

Управление через CLI:

# Установить команду
spec-first set spec-batch-run SPEC-NNN --command "pnpm nx test ng-noor-checkbox"

# С placeholders (подставляются на лету перед spawn)
spec-first set spec-batch-run SPEC-NNN \
  --command "pnpm nx test {product} --include='{specDir}/AC-*.spec.ts'"

# Прочитать текущее значение
spec-first get spec-batch-run SPEC-NNN
spec-first get spec-batch-run SPEC-NNN --json   # → { specId, command }

# Удалить поле
spec-first set spec-batch-run SPEC-NNN --clear

Допустимые placeholders:

| Placeholder | Значение | |---|---| | {product} | ID продукта | | {specId} | ID спеки (SPEC-NNN) | | {specUid} | UID спеки | | {specDir} | абсолютный путь к директории файла спеки | | {{ | литеральная { (escape) |

Поведение при FAIL: в stderr выводится WHERE (файл + команда) / WHY (первая строка stderr/stdout) / HOW (spec-first run --no-batch=SPEC-NNN).

Агрегат: batch-спека считается как 1 unit в статистике (не N AC); в JSON-выводе shape { batch: true, batchCommand, result: { status, exitCode, durationMs } }.

Bypass: флаг --no-batch (без значения = глобально, --no-batch=SPEC-NNN,SPEC-MMM = точечно) переключает batch-спеки обратно на поштучный прогон AC — удобно для отладки конкретного AC.

verify-spec-and-product-run — loop-oracle для CI и AI-агентов

Усиленный 2-step verifier (SPEC-008 + SPEC-012 + SPEC-014). Используется как финальный gate Phase D в любом implementation-loop runner-е (Ralph Wiggum Plugin, Cursor agent mode, Gemini CLI, plain bash while), а также в CI как single source of truth «всё ли реально работает».

# Через npx (рекомендованный способ для CI и AI-агентов):
npx -y -p @zurab/spec-first spec-first verify-spec-and-product-run <spec-fqn> --output stable

# Локально в монорепо:
node tools/spec-first/dist/cli/spec-first.js verify-spec-and-product-run <spec-fqn> --output stable

Что делает (2 step):

  1. Step 1 — статика: проверяет что указанная спека закрыта (все non-deprecated US/FR/AC в status=done).
  2. Step 2 — динамика: прогоняет ВСЕ AC-runner-ы продукта параллельно (3 спеки × 2 AC одновременно по умолчанию); даёт защиту от регрессий в других спеках при имплементации новой.
  3. Errors gate (если errorTrackingEnabled=true): проверяет что в errorsDir нет status=new записей.

4 режима вывода (--output <mode>):

| mode | PASS stdout | FAIL stdout | Назначение | |---|---|---|---| | promise (default) | <promise>SPEC-FIRST-VERIFIED:<product>:<spec>:<n1>:<n2></promise> | actionable отчёт с failing AC + sentinel <error>SPEC-FIRST-VERIFY-FAILED:...</error> | Человек-читатель + loop runner с regex-парсингом цифр | | stable | ровно SPEC-FIRST-VERIFIED-OK\n | 4 строки: sentinel / WHERE+WHY / file / retry | Loop runner матчит байт-стабильную строку через [[ "$out" == "SPEC-FIRST-VERIFIED-OK" ]] | | quiet | пусто | пусто (одна stderr-строка) | Exit-code-only сигнал для скриптов в pipe | | stream | live-стрим всех AC + финальный promise | live-стрим + полный список failing | Дебаг / verbose |

WHERE / WHY / HOW (FR-019) — все режимы (кроме quiet) выводят при FAIL:

  • WHERE — FQN (SPEC-014:AC-035) + относительный путь к файлу спеки.
  • WHY — первая значимая строка причины (error → payload → stderr; ANSI/CR cleared, ≤200 символов).
  • HOW — точная команда retry (spec-first close ac <spec>:<ac>).

Параллелизм (SPEC-008):

  • 2 семафора: maxSpecStreams (default 3) × maxAcStreams (default 2) — на 6 ACs одновременно.
  • CLI флаги: --max-spec-streams=N, --max-ac-streams=N, --max-for-every=N (single value перебивает оба).
  • Per-workspace конфиг verifyRunConcurrency в .spec-first.json (root) или .spec-first.product.json (product) — наследуется от runConcurrency если не задан.
  • Speedup измеренный: 5.4× на 262 AC (sum CPU 725s → wall 105s).

Output-config: verifyOutput: "promise" | "stable" | "quiet" | "stream" в root или product config — задаёт default, CLI перебивает.

Таймаут: --timeout <ms> (default 600000 = 10 минут) — на каждый runner отдельно.

Errors-gate isolation (SPEC-014 US-010): child-runner-ы по умолчанию НЕ captureят errors через env SPEC_FIRST_NO_AUTO_CAPTURE=1 (выставляется автоматически). Это предотвращает засорение errorsDir от deliberate-fail-тестов внутри runner-блоков. Чтобы получить child-capture для дебага: SPEC_FIRST_NO_AUTO_CAPTURE=0 spec-first verify-spec-and-product-run ... — explicit user-override побеждает default.

Exit-codes: 0 = PASS обоих step и errors-gate; 1 = FAIL Step 1 / Step 2 / errors-gate.

Best practices:

# CI: проверка что фича готова к merge — простой grep на sentinel.
if npx -y -p @zurab/spec-first spec-first verify-spec-and-product-run \
     <spec-fqn> --output stable | grep -Fxq "SPEC-FIRST-VERIFIED-OK"; then
  echo "✓ ready to merge"
else
  echo "✗ verify failed — see retry hint in output"
  exit 1
fi

# Loop runner (Ralph/Cursor/Gemini): match completion-promise.
spec-first verify-spec-and-product-run <spec-fqn>
# → ловить regex `<promise>SPEC-FIRST-VERIFIED:.*</promise>` из stdout
# → или `<error>SPEC-FIRST-VERIFY-FAILED:...:step([12]):.*</error>` для FAIL

# Pipe-friendly (только exit-code):
spec-first verify-spec-and-product-run <spec-fqn> --output quiet || \
  echo "fail; check stderr for first failing AC"

# Для дебага долгого прогона (262 AC ≈ 2 минуты):
spec-first verify-spec-and-product-run <spec-fqn> --output stream

Не путать с:

  • run — без status-checks, без errors-gate, без promise-sentinel; просто прогоняет AC ради вывода.
  • verify-spec-implemented — только Step 1 (статика). Не запускает runner-ы.
  • verify-closed — workspace-wide статика без runner-прогона.

Полный список параметров и FR — см. SPEC-008 (docs/spec-first-products/spec-first/docs/specs/1-spec/8-parallel-run.spec-first.ai.md), SPEC-012 (12-implement-playbook.spec-first.ai.md), SPEC-014 (14-errors.spec-first.ai.md).

Анализ

spec-first validate [target] [--strict]   target = path к файлу либо productId
spec-first check-to-implement [--product <id>] [--spec <id>]

validate проверяет: парные маркеры, уникальность id, наличие parent (FR→US, AC→FR), резолвинг replacedBy, согласованность checkbox/status, frontmatter. --strict дополнительно требует replacedBy или deprecationReason у любого deprecated элемента.

check-to-implement (pre-implementation gate): каждый non-deprecated Spec имеет ≥1 US, US ≥1 FR, FR ≥1 AC, AC ссылается на зарегистрированный runner и имеет валидный JSON-блок.

Сборка паспорта

spec-first build [--product <id>] [--no-preprocessor]

Программно строит Config для @zurab/mdmanager#runPipeline. Bundled runners резолвятся по абсолютному пути из <dist>/runners/. Deprecated AC пропускаются (помечаются ⚠ deprecated, runner не запускается).

Канонический формат spec-файла

Каждая спека — markdown с YAML-frontmatter и HTML-маркерами. Маркеры невидимы при рендере, но дают однозначный машинный парсер.

---
specId: SPEC-001
product: billing
title: 'Чекаут'
status: draft
---

## Problem

<!-- spec-first:problem-start -->
**Context:** ...
**Pain:** ...
**Goal:** ...
<!-- spec-first:problem-end -->

## User Stories

<!-- spec-first:us-start id=US-001 status=open -->
- [ ] **US-001** — Как покупатель, я хочу оплатить заказ
<!-- spec-first:us-end -->

## Functional Requirements

<!-- spec-first:fr-start id=FR-001 us=US-001 status=open -->
- [ ] **FR-001** — Кнопка 'Оплатить' открывает виджет провайдера
<!-- spec-first:fr-end -->

## Acceptance Criteria

<!-- spec-first:ac-start id=AC-001 fr=FR-001 status=open runner=bashrunner -->
- [ ] **AC-001** — Клик по кнопке открывает iframe

```bashrunner
{ "fr": "AC-001", "command": "true", "expect": "pass" }
```
<!-- spec-first:ac-end -->

Контракт маркера

<!-- spec-first:<kind>-(start|end) key=value... -->

| Атрибут | Где | Значения | |---|---|---| | id | spec, us, fr, ac | SPEC-001, US-001, FR-001, AC-001 | | status | все | draft | open | done | deprecated | | us | fr | id родительского US | | fr | ac | id родительского FR | | runner | ac | prefix runner-блока | | replacedBy | при status=deprecated | id или CSV; FQN SPEC-N:ID для cross-spec | | deprecationReason | при --no-replacement | URL-encoded строка |

Runner contract

Runner — исполняемый файл (node/bash/python), читающий JSON со stdin и пишущий JSON в stdout.

Stdin (передаёт mdmanager):

{
  "blockBody": "<содержимое fenced-блока>",
  "blockLanguage": "<prefix>",
  "sourcePath": "<абсолютный путь к spec.md>",
  "outputPath": "<куда пишется паспорт>",
  "frontmatter": { },
  "contextDoc": { "name": "...", "relativePath": "..." }
}

Stdout:

{ "ok": true, "mode": "replace", "payload": "> ✅ AC-001 PASS\n" }

или при ошибке:

{ "ok": false, "error": { "code": "BAD_BLOCK_JSON", "message": "..." } }

Bundled prefix'ы (резолвятся по __dirname после build):

  • bashrunnerbash-runner.sh
  • jestrunnerjest-runner.js
  • vitestrunnervitest-runner.mjs
  • cypressrunnercypress-ct-runner.js
  • pytestrunnerpytest-runner.py
  • playwrightrunnerplaywright-runner.js

Самотест runner'а: переменная MDMANAGER_SELF_TEST=1 мокает PASS без реального запуска.

Eat own dogfood

@zurab/spec-first сам построен по своим правилам: продукт spec-first живёт в docs/product-passports/products/spec-first/, его 3 спеки покрывают (1) маркеры, (2) discovery, (3) интеграцию с mdmanager. Сборка self-passport'а:

node tools/spec-first/dist/cli/spec-first.js build --product spec-first

Public API

Пакет также экспортирует все команды и core-модули как программный API:

import {
  loadIndex,
  parseSpecText,
  insertBlockInText,
  buildPassport,
  initCommand,
  createProductCommand,
  createSpecCommand,
  addUsCommand,
  validateCommand,
} from '@zurab/spec-first';

Разработка

pnpm nx build tools-spec-first             # сборка через @nx/js:tsc
pnpm nx test tools-spec-first              # jest unit + integration
pnpm nx run tools-spec-first:eslint:lint   # eslint

Все тесты используют tmp-dir и реальную FS, без сети, без npm i -g.

Goal-mode (SPEC-017, 0.14.0)

Зачем. Spec-flow требует ясной формулировки фичи до старта. Когда фича ещё не определена — есть только гипотеза «X улучшит Y» — нужен другой контейнер: персистентная цель с критериями достижения, которая собирает выводы и формирует черновики будущих спек по ходу проверки.

Жизненный цикл (3-state):

[create]                  [start]                    [mark-implemented]
draft  ── наполнение ──→  new  ── checklist run ──→  implemented
   │  (principles,         │     (все items=passed)         │
   │   checklist, deps,    │                                │
   │   ARDs, tasks)        └─ goal task promote ─→ create spec
   └─ goal delete --confirm   (deferred → реальная)
        (только draft)

goal resume <id> работает в любом статусе и не меняет его — печатает zero-context инъекцию: цель + актуальный контент привязанных ARDs (через прямой вызов ard get) + содержимое dependent-files (или missing если файл отсутствует) + open deferred-tasks одним вызовом.

Хранилище. Поле goalsDir в root config (default docs/goals). Файлы — <8-hex>.<slug>.goal.ai.md, формат frontmatter + markdown body. Frontmatter содержит id, title, description, hypothesis, success-criteria, status, product, массивы principles[], checklist[] (с runner-block + status), dependent-files[] (when: always|first-resume|on-implemented), related-ards[]snapshot-at), deferred-tasks[]kind: spec|extension|note и target-product), а также таймстемпы createdAt, startedAt, implementedAt.

CLI surface (~25 команд):

# Lifecycle
spec-first goal create --title T --description D --hypothesis H --success-criteria C [--product P]
spec-first goal start <id>                  # draft → new (требует ≥1 principle и ≥1 checklist)
spec-first goal mark-implemented <id>       # new → implemented (все checklist passed)
spec-first goal delete <id> --confirm       # hard-delete (только draft)

# Базовые
spec-first goal list [--status] [--product] [--description] [--json]
spec-first goal get <id> [--json]
spec-first goal count [--status] [--product] [--json]
spec-first goal resume <id>                 # zero-context инъекция

# Principles (мини-конституция конкретной цели)
spec-first goal principles add <id> --title T --text X
spec-first goal principles list <id> [--json]
spec-first goal principles remove <id> --pid <slug>

# Checklist (только bashrunner для MVP)
spec-first goal checklist add <id> --text T --runner-prefix bashrunner --runner-block '{"command":"...","expect":"pass"}'
spec-first goal checklist list <id> [--json]
spec-first goal checklist run <id> [--item <iid>]   # без --item: запустит все, агрегирует PASS/FAIL
spec-first goal checklist set <id> --item <iid> --text T
spec-first goal checklist remove <id> --item <iid>

# Dependent files (context injection при resume)
spec-first goal deps add <id> --path <rel> --when always|first-resume|on-implemented --why <reason>
spec-first goal deps list <id> [--json]
spec-first goal deps remove <id> --path <rel>

# Related ARDs (snapshot + sync)
spec-first goal ard add <id> --ard ARD-NNN
spec-first goal ard list <id> [--json]
spec-first goal ard sync <id>               # обновить snapshot-at до now
spec-first goal ard remove <id> --ard ARD-NNN

# Deferred tasks (черновики будущих спек)
spec-first goal task add <id> --title T --description D [--kind spec|extension|note] [--target-product P]
spec-first goal task list <id> [--status] [--json]
spec-first goal task promote <goalId>:<taskId> [--apply]   # без --apply: dry-run; с --apply для kind=spec → create spec
spec-first goal task discard <id> --task <tid>             # soft: status → discarded
spec-first goal task remove <id> --task <tid>              # hard: убрать из массива

Workflow (типовой):

  1. Создаёшь цель с title + description + hypothesis + success-criteria.
  2. Подгружаешь актуальные ard list --status approved и предлагаешь пользователю прикрепить релевантные через goal ard add.
  3. Формируешь principles (≥1) — инварианты конкретной гипотезы.
  4. Формируешь checklist — каждый пункт = bashrunner-блок, один Then-критерий.
  5. Добавляешь dependent-files (constitution, релевантные специ, конфиги).
  6. goal start <id> (draft → new).
  7. По мере проверки гипотезы — goal task add для всего, что может стать спекой.
  8. Когда все checklist items = passed → goal mark-implemented <id>.
  9. Пользователь смотрит goal task list <id>, отбраковывает (task discard), promote'ит подтверждённые: goal task promote <id>:<task-id> --apply для kind=spec создаёт реальную спеку.

Skill mz-spec-first. В версии 0.14.0 SKILL.md переработан в dispatcher (~87 строк): intent-таблица роутит к одному из трёх reference: goal-workflow.md (этот режим), spec-workflow.md (классический 4-фазный flow), cli-cheatsheet.md (топ-команды по группам). Полный workflow goal-mode — в skills/mz-spec-first/references/goal-workflow.md.

Архитектурные принципы

  1. CLI-only invariant — markdown spec-файлы НИКОГДА не редактируются руками. Любые изменения — через CLI; каждая mutate-команда атомарна (temp + rename).
  2. Two-level config — root для discovery + per-product для деталей.
  3. Bundled runners — пакет самодостаточен, не требует копирования внешних скриптов.
  4. CLI-flat программный API — каждая команда экспортирует функцию (initCommand, addUsCommand, ...) для встраивания в другие инструменты.
  5. Constitution-sync invariant (с 0.14.0) — конституция продукта (constitution.md) всегда отражает актуальный набор принципов и режимов работы. После любых изменений в спеках, режимах (например добавление goal-mode), CLI-инвариантах или жизненных циклах — конституция обновляется тем же изменением через set constitution <product> --file|--text. Расхождение конституции и поведения CLI считается багом конституции.
  6. Release artifacts sync invariant (с 0.14.0) — CHANGELOG.md и README.md пакета обновляются как часть того же изменения, которое добавляет/меняет функциональность. CHANGELOG ведётся по Keep a Changelog с секциями Added/Changed/Fixed/Tests; README — публичная витрина пакета на npm и описывает любые новые поля конфига, CLI-команды и режимы. Релиз с обновлением кода без CHANGELOG/README — неполный.

См. также конституцию продукта в docs/product-passports/products/spec-first/constitution.md и план ai/plans/spec-first-sleepy-fountain.md.