Spec Kit Workflow¶
Spec Kit is a structured, spec-driven development lifecycle. Instead of jumping straight to code, it forces you to articulate what to build and why before deciding how.
In this project, every feature goes through the same lifecycle:
flowchart LR
A[constitution\n.specify/memory/constitution.md] --> B[specify\nspec.md]
B --> C{clarify?\noptional}
C -->|"updates spec.md in-place"| D
C -->|skip| D
D[plan\nplan.md\ndata-model.md\ncontracts/] --> R1{review plan\ngate}
B --> R0{review spec\ngate}
R0 -->|approve| C
R0 -->|skip| D
R1 -->|approve| E[tasks\ntasks.md\nchecklists/]
E --> F{analyze?\noptional}
F -->|"checks spec+plan+tasks\nconsistency"| G[implement\nquickstart.md]
F -->|skip| G
Stages¶
Constitution¶
The project constitution lives at .specify/memory/constitution.md. It defines the non-negotiable principles that every feature, every plan, and every agent must respect. It supersedes all other guidance.
In this project, the constitution enforces six principles:
| # | Principle | Short form |
|---|---|---|
| I | Hexagonal Architecture | domain ← application ← adapters ← apps. No framework/SQL in inner layers. |
| II | Test-First (NON-NEGOTIABLE) | TDD red→green→refactor. Tests are never optional. |
| III | Auditability | Every state change → immutable, ordered audit record. Append-only. |
| IV | Orchestration Behind a Port | WorkflowEngine port in domain. Temporal lives only in adapters. |
| V | Explicit Contracts & Consistency | Transactional outbox. Single effective decision under concurrency. |
| VI | Local Validation Before Push | ./gradlew build must pass locally before any push. |
Run /speckit-constitution to create or amend the constitution.
Specify¶
Write a business-facing, technology-agnostic feature specification in specs/NNN-feature/spec.md.
A good spec describes:
- The user stories (who does what, and why it matters)
- Acceptance scenarios (Given / When / Then)
- Functional requirements (what the system must do)
- Key entities (the domain vocabulary)
- Success criteria (measurable outcomes)
- Assumptions (what is out of scope)
The spec must not mention Kotlin, Temporal, jOOQ, or any other technology. Those decisions belong in the plan.
Run /speckit-specify with a plain-language feature description.
Clarify (optional, runs before plan)¶
Surface ambiguities before any technology decisions are made. /speckit-clarify asks up to 5 targeted questions and writes the answers directly into spec.md — it does not send you back to re-run /speckit-specify.
This is cheap — changing a spec before planning costs nothing; changing a plan mid-implementation costs a lot.
Plan¶
Translate the spec into a technology-specific design in specs/NNN-feature/plan.md. This is where Kotlin, Temporal, jOOQ, Ktor, etc. are chosen and justified.
The plan also produces:
data-model.md— entity relationships and database schemacontracts/lib/models.tsp+routes.tsp— TypeSpec source (REST contract)contracts/openapi.yaml— generated from TypeSpec; consumed by docs and UI type generationcontracts/events.md— integration event definitions (CloudEvents, prose format)checklists/requirements.md— FR/SC traceability matrix
Every plan must pass a Constitution Check gate before proceeding: each Core Principle is verified, and any deviation must be recorded with justification.
Run /speckit-plan.
Tasks¶
Generate an ordered, dependency-aware tasks.md from the plan. Each task is:
- Small enough to be executed by a single agent in one session
- Self-contained with a clear done condition
- Ordered so dependencies are always satisfied before dependents
Run /speckit-tasks, then optionally /speckit-analyze before moving to implementation.
Analyze (optional, runs after tasks)¶
/speckit-analyze performs a non-destructive cross-artifact consistency check across spec.md, plan.md, and tasks.md. It catches drift — requirements that didn't make it into the plan, plan decisions that didn't produce tasks, tasks that don't trace back to any requirement.
Run it before starting implementation to catch gaps while they're still cheap to fix.
Implement¶
Execute tasks one by one. The agent reads the task, writes a failing test, makes it pass, then refactors. Each task is marked done in tasks.md when complete.
Run /speckit-implement.
Branch and Artifact Conventions¶
- Feature branches:
NNN-short-name(e.g.001-document-approval-engine) - All artifacts live under
specs/NNN-short-name/ - Business specs are technology-agnostic; technology decisions live only in
plan.md
The Constitution (full text)¶
wrkflw Constitution¶
Core Principles¶
I. Hexagonal Architecture (NON-NEGOTIABLE)¶
Every part of the system is structured as ports and adapters, with dependencies pointing
inward only: domain ← application ← adapters ← apps.
- The
domainandapplicationlayers MUST NOT reference any framework, transport, persistence library, or orchestration SDK. No HTTP framework, no database/SQL library, and no workflow-engine types may appear in these layers. - All interaction with the outside world (persistence, messaging, orchestration, HTTP, identity) MUST occur through a port — an interface owned by the domain or application layer — with the concrete implementation living in an adapter.
- Apps are thin composition roots: they wire adapters to ports and own configuration; they contain no business logic.
Rationale: Keeping business logic pure and framework-free makes it fast to test, cheap to reason about, and ensures infrastructure choices (including the orchestration engine) remain replaceable rather than load-bearing.
II. Test-First Discipline (NON-NEGOTIABLE)¶
Tests are written before the implementation they describe, follow Red→Green→Refactor, and gate every change.
domainandapplicationlogic MUST be covered by fast, isolated unit tests that touch no infrastructure.- Every adapter and every cross-boundary contract (persistence, orchestration, HTTP, events) MUST be covered by integration tests that exercise real backing services rather than mocks of those services (e.g., containerized Postgres and a real workflow-engine test environment).
- Concurrency and correctness guarantees (single-effective-decision, audit completeness, event/state consistency) MUST have explicit tests; they may not be assumed.
- This principle OVERRIDES any downstream template that treats tests as optional.
Rationale: A workflow engine's value rests on correctness under concurrency and on trustworthy state transitions — properties that cannot be verified by inspection.
III. Auditability & Traceability¶
The system is a trustworthy record of who did what, when.
- Every state transition, assignment, claim, release, and decision MUST produce an immutable, ordered audit record capturing the acting party, the change, and the timestamp.
- Audit records are append-only: they are never updated or deleted.
- A flow's complete lifecycle MUST be reconstructable from its audit history alone.
- Administrative actions (reassign, restart, reset) MUST be audited with the administrator's identity, with the same rigor as ordinary actions.
Rationale: Approvals are compliance-sensitive; the history must be complete and tamper- evident to be relied upon for accountability and recovery.
IV. Orchestration Behind a Port¶
Durable orchestration is a swappable capability, not an architectural assumption.
- Durable, long-running orchestration MUST be provided by a dedicated engine accessed only
through a
WorkflowEngine(or equivalent) port; the domain MUST remain unaware of the orchestration technology. - Internal flow progression MUST use the orchestration engine's own mechanisms (e.g., signals and activities). Message brokers and event streams MUST NOT be used to drive internal flow steps.
- Brokers and emitted events are for integration with the outside world only.
Rationale: Adopting a proven engine avoids reinventing durability, while the port keeps the engine replaceable and prevents orchestration concerns from leaking into business rules.
V. Explicit Contracts & Consistency¶
Boundaries are explicit, and persisted state and emitted facts never disagree.
- A state change and any integration events it produces MUST be atomically consistent: if the state change commits, its events are eventually delivered exactly once; if it rolls back, no event is emitted (i.e., a transactional outbox or equivalent guarantee).
- Concurrent actions on the same unit of work MUST resolve to at most one effective outcome.
- Integration events MUST use a vendor-neutral envelope so consumers are not coupled to internal representations.
- Ports MUST expose intention-revealing contracts (commands, queries, and domain events), not leak storage or transport shapes.
Rationale: Distributed correctness and safe, decoupled integration depend on consistency between what the system records and what it tells the world.
VI. Local Validation Before Push¶
CI is a safety net, not a first reviewer. The full build MUST pass locally before any commit is pushed to a shared branch.
./gradlew build(which runs lint, compilation, and all tests) MUST pass locally before anygit push. Pushing code that has not been locally verified is prohibited.- Integration tests depend on containerized services (Postgres) via Testcontainers. The test framework handles container engine discovery and Docker API version negotiation natively — no manual pre-step or helper script is required before running tests.
- CI failures that would have been caught locally MUST be treated as process violations, not just build breaks. The root fix is enforcing local validation, not iterating on CI.
mise run cireproduces the exact sequence CI executes. Running it locally before push provides the strongest local/CI parity guarantee.
Rationale: CI queues are shared, feedback is slower, and CI-only failures create churn and break shared branches. Local validation catches issues in seconds and keeps the shared history clean.
Technology & Architecture Constraints¶
These constraints apply at the adapter and app layers only; the domain and application layers remain free of all of them per Principle I.
- Language & build: Kotlin on the JVM, organized as a Gradle multi-module monorepo. Module boundaries enforce the inward-only dependency rule of Principle I.
- REST / HTTP: Ktor is the standard framework for any HTTP/REST API built in Kotlin. Spring Boot MUST NOT be used for the API layer.
- Orchestration: Temporal is the orchestration engine, accessed only via the port defined in Principle IV.
- Persistence: PostgreSQL for current state plus the append-only audit log, accessed with type-safe SQL (jOOQ). Reliable event publication uses a transactional outbox.
- Integration events: CloudEvents as the vendor-neutral envelope (Principle V).
- Assignment model: group/role candidate groups with a claim-to-act pattern; named external identity integration may be added later behind a port.
- Topology: deployables share the same
domain/application/persistencemodules and differ only in which driving adapters they activate.
A constraint in this section may be revised by amendment (see Governance) when a better-fitting technology is justified, provided the Core Principles continue to hold.
Development Workflow & Quality Gates¶
- Spec-driven flow: Work proceeds through the Spec Kit lifecycle — constitution → specify → (clarify) → plan → tasks → implement. Specifications stay business-facing and technology- agnostic; technology decisions live in the plan.
- Feature branches: Each feature is developed on its own branch under the
NNN-short-nameconvention, with its artifacts underspecs/NNN-short-name/. - Constitution gate: Every implementation plan MUST pass the Constitution Check gate before design proceeds, and re-check after design. Violations MUST be recorded with justification in the plan's Complexity Tracking, or the design MUST change.
- Local validation gate: Per Principle VI,
./gradlew buildMUST pass locally before pushing. Container-backed tests connect to the host container engine directly via Testcontainers — no manual pre-step required. Usemise run cifor full local/CI parity. - Definition of done: All tests (unit and integration) pass locally; the inward-only dependency rule is not violated; new state-changing behavior has corresponding audit records and, where applicable, integration events.
- Review: Changes are reviewed for conformance to the Core Principles before merge.
Governance¶
- Authority: This constitution supersedes other practices. Where guidance conflicts, the Core Principles win.
- Amendments: Proposed in a pull request that states the change, its rationale, and its impact on dependent templates and existing features. Amendments take effect when merged.
- Versioning: This constitution is versioned with semantic versioning:
- MAJOR — backward-incompatible governance changes or removal/redefinition of a principle.
- MINOR — a new principle or section, or materially expanded guidance.
- PATCH — clarifications and wording fixes with no change in meaning.
- Compliance review: Plans and pull requests are checked against the Core Principles. Deviations require explicit, recorded justification; unjustified deviations block merge.
Version: 1.2.0 | Ratified: 2026-06-09 | Last Amended: 2026-06-13