Metadata-Version: 2.5
Name: devflow-toolkit
Version: 0.4.3
Summary: Specification workflow toolkit for AI-assisted software changes
Author: DevFlow contributors
License-Expression: MIT
License-File: LICENSE
Keywords: agents,ai,architecture,cli,greenfield,sdd,specification,workflow
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Documentation
Classifier: Topic :: Software Development :: Documentation
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.11
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0
Requires-Dist: typer>=0.12
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.12; extra == 'dev'
Requires-Dist: twine>=5.0; extra == 'dev'
Description-Content-Type: text/markdown

# DevFlow Toolkit

**Current version: `0.4.3`.**

Before any code is written, you and the AI agree on what will be built
and approve it as a spec. The agent then implements once, on something
clear, instead of trying, failing and redoing. Questions are cheap;
redoing code is expensive.

**The expensive part of an agent is not writing, it is correcting.**
Give it something ambiguous and it explores the whole repository, writes
code and tests, you reject it, and it starts again with an ever larger
context. Every round costs more than the last, and it is paid in output
tokens, which cost several times more than input tokens.

**DevFlow trades code rounds for question rounds.**

- **Discovery asks first.** Authentication, permissions, validation,
  what stays out of scope. These rounds are cheap: mostly reading, no
  code.
- **Validation spends no tokens.** DevFlow checks that Discovery is
  complete and that the spec has the right shape with local Python
  code.
- **The approved spec guides the agent.** It says which files to touch,
  which requirements to meet (`FR`) and how to prove it is done (`AC`).
  The agent explores less, stays in scope and writes nothing nobody
  asked for.
- **Each phase reads only what it needs.** Code style rules are loaded
  when implementing, not while specifying.
- **Context is never lost.** Everything stays in your repository, in a
  few files under `.devflow/`. Switch sessions or agents and there is
  nothing to explain again.

The goal is not to generate code faster, but to decide better before
generating it. Thinking is cheap; redoing code is expensive.

## Install

```bash
pip install devflow-toolkit
devflow version
```

You also need an AI agent installed on your machine, for example
[OpenCode](https://opencode.ai) or Claude Code.

## The flow

```text
 devflow init                     once per project
      │
 devflow spec "your change"       Discovery: the agent asks, you answer
      │
 devflow spec --continue 001      repeat until the spec is written
      │
 devflow approve 001              you approve the spec
      │
 "Implement .devflow/specs/001-…/spec.md"   ask your agent to build it

 Need to change an approved spec?  devflow reopen 001
 Not sure what comes next?         devflow status 001
```

The rest of this page is the full reference: every command, option,
file and rule.

## What DevFlow covers

DevFlow is a command-line toolkit for leading AI models and coding
agents through specification-driven changes in real software projects.

Discovery is the centre of that process. It is not a one-shot chat or a
form to fill in; it is a joint exploration between the human team and the
AI model. Both review the project, ask questions, challenge assumptions
and agree on the specification together. The AI is useful because it
explores with you, not because it decides for you. Your criteria become
visible in the discovery record, in the approved specification and at
every step of the process.

This MVP implements the **discovery and specification stages only**. It
supports two specification contexts: **Existing Project** (the default)
and **Greenfield**. It is not a complete SDD platform and does not
include planning, implementation or review workflows.

Discovery decides whether a request is ready to become a
specification. A specification is only generated when every decision is
`resolved` or `assumed`, and every assumption has been explicitly
accepted. Discovery is persisted, so an incomplete request can be
resumed across sessions and agent harnesses. Discovery is also the
requirement-gathering stage: ambiguity, authentication, permissions,
moderation, data lifecycle, validation, ordering, administration,
compatibility and out-of-scope decisions must be resolved there, not in
`spec.md`.

## The problem it solves

AI agents can produce useful specifications, but without a controlled
process the result is often a throwaway chat response:

- it is not tied to the real codebase;
- it ignores the project's own engineering rules;
- it grows in scope and produces code nobody requested;
- there is no record of who approved it or which exact version was
  approved;
- switching agents loses context and history.

DevFlow turns that chat into a reviewable project artifact. It keeps the
specification, the evidence used to write it, the constitution and the
approval record inside the project. Approvals are bound to SHA-256
digests, and the workflow state can be rebuilt from an append-only event
log.

The point is not to generate more code faster. The point is to decide
better before generating any code.

## Two specification contexts

DevFlow does not assume that a project already exists. The difference
between the two modes is where the context comes from, not a permanent
identity for the project:

| Context | Source of context | Typical use |
| --- | --- | --- |
| `existing` (default) | Analysed code, dependencies, conventions and the constitution, plus the declared architecture manifest when present | A change, fix, refactor or integration in a real codebase |
| `greenfield` | Requested requirements, a declared architecture manifest, stack, constraints and the constitution | The initial specification for a system that does not exist yet |

- `existing` is the default and preserves the historical behaviour.
- `greenfield` never invents existing code. It does not scaffold a
  project, generate application code or implement tasks.
- Greenfield is a context for a specification execution, not a permanent
  project identity. After implementation exists, switch back to
  `existing`; the architecture manifest is kept and used as a
  constraint.
- DevFlow never switches modes silently. Use `--project-mode` explicitly
  when a run differs from the configured default.

## Instruction precedence

Every generated `context.md` has two numbered sections: the
`Decision Context` and the `Project Evidence`. The Decision Context is
authoritative for decisions; the Project Evidence supports it. When
instructions conflict, DevFlow applies this order, highest priority
first:

1. Explicit decisions approved by the user.
2. The approved specification.
3. The constitution and the enabled technology profiles.
4. The declared architecture and verified project conventions.
5. General good practices.
6. Agent preferences.

A lower-priority instruction never overrides a higher-priority one. When
two instructions at the same level conflict, the agent asks instead of
resolving the conflict silently. The prompts state the output contract;
DevFlow's Python code applies the enforcement.

## Requirements

- Python 3.11 or newer.
- A POSIX operating system (Linux or macOS). Windows is not tested and is
  not supported in this release, because the workflow locks require
  `fcntl`.
- For agent-generated specifications: OpenCode or Google Antigravity
  (`agy`) installed and authenticated on `PATH`. OpenCode is verified
  end-to-end; Antigravity agent loading and print mode are verified
  locally.
- Git is not required. DevFlow does not initialize a repository, commit
  files or run destructive commands.

## Installation

```bash
python -m venv .venv
source .venv/bin/activate
pip install devflow-toolkit
```

To install a specific built artifact instead:

```bash
pip install devflow_toolkit-0.4.3-py3-none-any.whl
```

Verify the installation:

```bash
devflow --help
devflow version
```

## Quick start: from install to approved specification

This is the normal path for a new change:

1. Install DevFlow and check the command-line tool:

```bash
python -m venv .venv
source .venv/bin/activate
pip install devflow-toolkit
devflow version
```

2. Initialize the project. Choose a harness and a language:

```bash
cd my-project
devflow init --harness opencode --language es
```

`--language es` makes Discovery and `spec.md` use Spanish. In an
interactive terminal, `init` asks for the language and the model when
they are omitted. Add `--model provider/model-name` to pin a specific
model.

3. Start a change. Discovery runs first:

```bash
devflow spec "Agregar un formulario de contacto"
```

4. Answer every Discovery question and accept or reject every proposed
assumption. The interactive harness asks in the terminal. You can also
edit `.devflow/specs/<id>-<slug>/discovery.yaml` directly.

5. Generate the specification once Discovery is complete:

```bash
devflow spec --continue 001
```

6. Review `spec.md` and approve it:

```bash
devflow status 001
devflow approve 001
```

7. Start the next change. The stored language and model are reused:

```bash
devflow spec "Agregar validación al formulario"
```

The exact change id appears in the command output and in
`.devflow/specs/`. Use `--auto` on `devflow spec` when you want to run
Discovery and the specification in one invocation.

## Language

DevFlow can write Discovery questions, reasons, options and `spec.md`
prose in your language. Use a language code or a common name:

```bash
devflow init --language es
devflow spec "Agregar un formulario de contacto" --language es
devflow config language es
```

- `init --language es` stores Spanish as the project default. Without
  `--language`, an interactive `init` asks for the language; `--yes`
  keeps `en`.
- `spec --language es` uses Spanish and stores it as the new default, so
  `devflow spec --continue 001` stays in Spanish.
- `config language es` changes the default without initializing the
  project again.
- Common names such as `Spanish` are normalized to `es`.
- The agent translates existing Discovery questions in place and writes
  new questions and the specification in the selected language.
- Identifiers such as `FR-001` and `AC-001`, paths, commands, code
  blocks and digests are not translated.

## Initialization

Run `devflow init` inside the project you want to manage:

```bash
cd my-project
devflow init
```

DevFlow inspects the existing project, detects its stack and profiles,
copies the applicable constitution documents, writes
`.devflow/config.yaml` and generates the integration for the selected
harness.

The stack is detected from `pyproject.toml`, `requirements*.txt` and
`package.json`. When those manifests are absent or incomplete, DevFlow
also reads the packages installed in a local virtual environment
(`.venv`, `venv` or `env`). This keeps Django, FastAPI and the
RAG/vector stack (`langchain`, `llama-index`, `chromadb`,
`qdrant-client`, `weaviate-client`, `pinecone-client`, `pgvector` and
`sentence-transformers`) detectable without versioning a dependency
manifest.

Common options:

```bash
devflow init --harness opencode --mode non-interactive
devflow init --harness antigravity --mode interactive
devflow init --harness opencode --model provider/model-name
devflow init --profile django-backend --name my-service
devflow init --project-mode greenfield
devflow init --language es
devflow init --no-agent
devflow init --yes
```

`init --language <code>` sets the language used for Discovery and
specification prose. In an interactive terminal, `init` asks for the
language when `--language` is omitted; `--yes` keeps `en`. The value is
stored as `documentation.language` in `.devflow/config.yaml`. Common
language names such as `Spanish` are normalized to their code (`es`).
You can change it later with `devflow config language <code>`. Required
headings, section numbers, `FR-XXX`/`AC-XXX` identifiers, paths,
commands and digests remain unchanged so structural validation still
works.

`init --model <id>` stores the model used by the selected harness in
`agent.model`. When `--model` is omitted, an interactive `init` asks for
one. `--model` on `devflow spec` overrides the stored model for that run
only.

`init --project-mode greenfield` creates `.devflow/architecture.yaml`
from a template when it does not exist. It never overwrites an existing
manifest. Edit the manifest before running a Greenfield specification;
until then, `spec` fails with a clear structural error.

`init` never overwrites an existing constitution document, configuration
file, specification, approval or unmanaged integration file. Running it
again refreshes missing constitution files and managed integration files
without destroying project work.

If an explicitly selected harness is not installed, `init` still records
the selection but prints a warning. Subsequent `spec` runs fall back to
deterministic static analysis until the executable is available.

When an interactive `spec` run asks you to choose a harness and none of
the supported executables is installed, the command fails with a clear
error instead of silently switching to deterministic analysis. Pass
`--harness none` or `--no-agent` to opt into deterministic output
explicitly.

### Local security checks

Semgrep, Bandit, pip-audit and gitleaks review code, so they belong to
implementation. DevFlow offers them once, right after the first
`devflow approve`, in an interactive terminal:

- Semgrep, with rules for Django (or Python) and OWASP;
- Bandit, for Python code;
- pip-audit, for vulnerable dependencies;
- gitleaks, for secrets in the code.

pre-commit (pre-commit.com) runs these tools automatically on every
commit, without tokens. `devflow init --security-tools` installs them at
any time; `devflow init --no-security-tools` turns the offer off. The
answer is remembered in `.devflow/config.yaml` (`security.tools_offered`).

Accepting writes a managed `.pre-commit-config.yaml` with pinned hook
revisions, installs `pre-commit` with pip when it is missing and runs
`pre-commit install` when the project is a git repository. Only the
hooks that apply are added: Bandit and pip-audit for Python projects,
`p/django` rules for Django. An existing, unmanaged
`.pre-commit-config.yaml` is never overwritten. The first commit
downloads the tools; `pre-commit run --all-files` checks the whole
project.

When the checks are configured, `context.md` tells the specification
writer to record `pre-commit run --all-files` as a quality gate in
section 6.

## Configuration

`.devflow/config.yaml` stores project settings. It references the
constitution documents; it does not duplicate their contents.

```yaml
project:
  name: my-service
  type: backend
  mode: existing
profiles:
  - django-backend
constitution:
  base: true
  profile_specific: true
  path: .devflow/constitution
  files:
    - constitution.md
    - code-standards.md
    - architecture.md
    - django-standards.md
specifications:
  path: .devflow/specs
agent:
  harness: opencode
  model: provider/model-name
  execution:
    mode: non-interactive
  permissions:
    allow_project_read: true
    allow_workflow_write: true
    allow_source_code_changes: false
```

`agent.model` is optional. An empty value means the harness default.
`devflow harness use <harness> --model <id>` changes it later without
reinitializing the project.

`constitution.files` accepts plain file names inside the constitution
directory. Absolute paths, `..` and nested paths are rejected.

Existing configurations without `project.mode` load as `existing`.

## Declared architecture

The declared architecture lives in `.devflow/architecture.yaml`, not in
`config.yaml`. It is a reviewable, versionable design decision. Example:

```yaml
version: 1
style: clean-architecture
summary: >
  REST API for contact management with domain separation.
modules:
  - name: contacts
    responsibility: Contact registration and queries
    depends_on: [shared]
  - name: shared
    responsibility: Cross-cutting utilities
    depends_on: []
layers:
  - name: domain
    may_depend_on: []
  - name: application
    may_depend_on: [domain]
  - name: infrastructure
    may_depend_on: [domain, application]
  - name: presentation
    may_depend_on: [application]
stack:
  language: python
  framework: django-rest-framework
  database: postgresql
constraints:
  containerization: docker
  authentication: jwt
  testing: pytest
quality_attributes:
  - testability
  - modularity
fitness_functions:
  - domain must not import infrastructure
```

`style` is free text. Clean Architecture, Hexagonal Architecture,
Microservices, Modular Monolith and Event-Driven are examples and
presets, not a closed list. Custom architectures are valid as long as
they are described in the manifest.

DevFlow validates structure and internal consistency only:

- required fields and non-empty values;
- duplicate module or layer names;
- references to unknown modules or layers;
- dependency cycles, reported as warnings;
- invalid YAML, unsafe paths, symlinks and oversized manifests.

It does **not** certify architectural quality. Contradictions and open
decisions must be recorded as specification questions.

`init` may create the template. `spec` only reads the manifest and never
modifies it. The manifest digest is recorded in `context.md` and in
`spec.md`, including an appendix with the declared manifest, so each
approval identifies the architecture version used. Greenfield
specifications require the manifest; existing-mode specifications use it
as an architectural constraint when it is present.

### Harnesses

| Harness | Status in 0.4.3 |
| --- | --- |
| OpenCode | Verified end-to-end; interactive Discovery uses the `question` tool |
| Antigravity | Custom agents and scoped permissions generated; `agy` loading and print mode verified |
| Codex | Integration files are generated, but not verified for this release |
| Claude Code | Integration files are generated, but not verified for this release |
| Kiro | Integration files are generated, but not verified for this release |
| `none` | Deterministic static analysis only; no agent is invoked |

Do not treat an unverified adapter as a compatibility guarantee. The
generated files and command lines for Codex, Claude Code and Kiro may
change as those integrations are tested.

DevFlow stores the harness and the model together. `devflow harness
current` shows the current selection, `devflow harness list` shows the
installed harnesses, `devflow harness models <harness>` lists the models
that the harness advertises, and `devflow harness use <harness> [--model
<id>]` changes the selection and regenerates that harness's integration
files. `init` and `harness use` ask for a model interactively; `--model`
on `spec` overrides it for one run. The selected model is passed to the
harness on the command line.

For interactive Codex runs, DevFlow enables Codex's experimental
`request_user_input` tool so Discovery questions can be answered by
selecting an option instead of typing a free-form reply. Claude Code uses
its native `AskUserQuestion` dialog. Both adapters fall back to numbered
text options if the installed harness does not expose a structured
question tool.

OpenCode and Antigravity receive an explicit instruction to call their
structured question tool for every pending Discovery question and for
every assumption acceptance. OpenCode's tool is `question`; Antigravity's
tool is `ask_question`. The instruction is injected only for those
harnesses, so the Codex and Claude Code prompts are unchanged.

For Antigravity, DevFlow generates `AGENTS.md` and custom agents under
`.agents/agents/`. Interactive runs use the writable `devflow-spec`
agent with `agy --settings <json> --agent devflow-spec
--prompt-interactive <prompt>`. Non-interactive runs use the read-only
`devflow-spec-readonly` agent with `agy --settings <json> --agent
devflow-spec-readonly --print --output-format text <prompt>`. Project
reads are allowed, writes are scoped to `.devflow/specs` in interactive
mode, and commands, web access and MCP servers are denied. The alias
`agy` is accepted for `--harness`.

To configure Discovery in Spanish, pass `--language es` to `init` or run
`devflow config language es`. `spec --language es` also persists the
language for subsequent runs. The conversation and the stored question
text use the selected language.

For OpenCode, DevFlow generates `AGENTS.md`, `opencode.json` and the
agents under `.opencode/agents/`. The project-level `opencode.json` can
also select a default model, for example:

```json
{
  "$schema": "https://opencode.ai/config.json",
  "model": "provider/model-name"
}
```

DevFlow creates `opencode.json` only when it does not exist and never
replaces an existing OpenCode configuration.

DevFlow records the files it generates for the selected harness in a
managed block inside `.gitignore`, for example `CLAUDE.md`, `AGENTS.md`,
`opencode.json` and the DevFlow agents. Existing ignore entries are
preserved, and the block is shared across harnesses, so switching
adapters keeps earlier generated files ignored. Unmanaged files that
DevFlow did not create are never added. DevFlow does not ignore
`.devflow/` or the constitution.

### Permissions

`allow_workflow_write` controls writes to DevFlow artifacts.
`allow_spec_write` is accepted as a compatibility alias.
`allow_source_code_changes` is disabled by default.

DevFlow translates these settings into technical controls where the
harness exposes them. For OpenCode, the generated agents deny `edit`
outside `.devflow/specs/`, deny shell execution unless source changes are
explicitly allowed, and disable web access and subagents. Prompt text is
not treated as the only permission boundary.

When a harness cannot enforce a restriction technically, DevFlow prints
a warning instead of claiming that the restriction is guaranteed.

For Claude Code, interactive runs use Manual mode
(`--permission-mode manual`) so Discovery can open the
`AskUserQuestion` dialog. Reads and writes under `.devflow/specs/` are
pre-approved, while shell, web and task tools remain denied.
Non-interactive runs keep the locked `dontAsk` mode and do not allow the
question tool.

Manual mode would ask you about any other write, such as a helper
script in `/tmp`. To avoid that prompt, DevFlow also passes a
`PreToolUse` hook (`devflow.hooks.claude_guard`) that blocks every
`Write`, `Edit`, `MultiEdit` and `NotebookEdit` outside
`.devflow/specs/` without asking, and tells the agent why. The hook is
not added when `allow_source_code_changes` is enabled.

## Discovery

Discovery is separate from specification. The project context decides
where evidence comes from; Discovery decides whether the request is
ready to become a specification.

Every new `devflow spec` request creates a persistent record at
`.devflow/specs/<id>-<slug>/discovery.yaml`. It is plain YAML and can be
reviewed, edited and committed:

```yaml
version: 1
spec_id: "001"
change: "001-add-a-contact-form"
request: "Add a contact form"
project_mode: existing
status: awaiting_clarification
created_at: "2026-11-02T10:00:00Z"
updated_at: "2026-11-02T10:00:00Z"
questions:
  - id: Q1
    category: functional_scope
    materiality: functional
    question: What should happen when the contact form is submitted?
    reason: Persistence, confirmation and email delivery change scope.
    blocking: true
    status: pending
    options: []
    answer: null
    answered_by: null
    answered_at: null
  - id: Q2
    category: architecture_boundary
    materiality: technical
    question: Which form mechanism should the page use?
    reason: The project already uses Django Forms.
    blocking: false
    status: resolved
    resolution_source: evidence
    evidence:
      - "profiles/django-backend"
      - "src/contact/forms.py:12"
    answer: Reuse Django Forms.
    options: []
assumptions:
  - id: A1
    question_id: Q3
    value: Use `/contacto/` as the URL path.
    reason: Internal routing must be visible before approval.
    source: agent_default
    status: pending_acceptance
    accepted_by: null
    accepted_at: null
```

Every decision has one outcome: `resolved`, `assumed` or `pending`.
A question presents a pending decision; an assumption is the acceptance
ledger for an assumed decision. Each decision has a `category`, a
`materiality` (`critical`, `functional`, `technical` or `cosmetic`) and
an explicit `blocking` flag.

- `pending` is valid only for blocking or material decisions.
- `resolved` by the user records `answer`, `answered_by` and
  `answered_at`.
- `resolved` by evidence records `resolution_source: evidence` and at
  least one `evidence` entry.
- `assumed` requires a linked assumption with explicit human acceptance.
  Critical and security decisions can never be assumed.
- `answered` is a legacy alias that DevFlow reads as `resolved`.

A specification may only be generated when no decision is `pending` and
every assumption has been explicitly accepted. DevFlow validates the
record and confirms completeness; the agent never declares Discovery
complete on its own.

Discovery uses a per-round question budget and batches independent
decisions into one interaction. The defaults live in `.devflow/config.yaml`:

```yaml
discovery:
  question_budget:
    initial: 6
    follow_up: 6
    maximum: 20
  interaction:
    batch_size: 6
    max_rounds: 5
  assumptions:
    enabled: true
```

The budget only limits optional questions. Critical and blocking
decisions are always asked in the same session, even beyond the cap or
the round limit, and decisions resolved from project evidence do not
count. Projects initialized before `0.4.1` keep the old limits
(`follow_up: 3`, `maximum: 12`, `max_rounds: 3`); `devflow spec` warns
about them and suggests the new values.

The deterministic planner recognizes contact pages, forms, comments,
authentication, persistence, deployments and architecture boundaries in
English and Spanish. Generic data vocabulary such as `datos`, `data` or
`database` does not by itself prove that the feature scope is understood:
when it is the only match, the planner adds a generic blocking scope
question instead of marking Discovery complete. Interactive runs always
produce at least one question when no specific question matches, so the
selected harness is invoked instead of being skipped with an empty
Discovery. Non-interactive runs keep the deterministic behavior for
concrete requests such as `Add a health endpoint`.

The planner's questions are proposals. For an authentication request,
the first options fit the project: Django sessions with the built-in
views and forms for a Django project, server-side sessions otherwise,
and API tokens only when the request mentions an API, tokens or a mobile
client. While a planner question is still pending, the Discovery agent
may rewrite its wording and options, put the recommended level-1 option
first and add a `next_level`; answered decisions are never rewritten.

Discovery and specification agents search only the project's own files
and skip virtual environments and installed dependencies (`venv`,
`.venv`, `node_modules`, `site-packages`), reading a dependency only for
one specific fact. Every prompt opens with the language rule, so the
agent answers in the configured language from its first message.

For user-generated content, Discovery must also resolve who writes it,
who may create, edit or delete it, moderation, authentication
mechanism, validation, ordering, lifecycle on parent deletion, admin
registration, compatibility and explicit out-of-scope items.

An assumption proposed by DevFlow uses `source: agent_default` and
starts as `pending_acceptance`. It never becomes accepted automatically.
A human must set `status: accepted` with `accepted_by` and `accepted_at`,
or reject it and record a different decision.

While any decision is pending or any assumption remains unaccepted:

- `discovery.yaml` and `context.md` are written;
- no `spec.md` is generated;
- `devflow approve` refuses the change;
- the workflow status is `awaiting_clarification`.

`context.md` is the single generated context file. Its
`## 1. Decision Context` section is generated deterministically by
DevFlow from the project facts, conventions, approved decisions,
evidence, pending decisions and constraints. Its
`## 2. Project Evidence` section contains the request, static analysis,
relevant code, constitution scope and declared architecture. The file is
capped and carries the Discovery and architecture digests, so a new
session does not need to rediscover the whole project.

Answer the questions in the file, or run an interactive harness, then
resume:

```bash
devflow spec --continue 006
```

`--continue` never regenerates or overwrites an approved specification.
It reuses a current, valid specification when its Discovery digest still
matches. If an answer changes before approval, DevFlow marks the old
specification stale, preserves it under `history/`, and generates a new
specification bound to the new Discovery digest.

The deterministic `--no-agent` path follows the same rules. It generates
Discovery, records it, and stops when any question or assumption
remains unresolved. It never invents an answer to continue.

Changes created with `0.2.0` that have no `discovery.yaml` remain
approvable as legacy changes, with an explicit warning. New changes
require Discovery.

A generated specification is valid only when section 7 is exactly
`None.`. If the specification agent discovers a decision that Discovery
did not cover, DevFlow rejects the generated document, archives it,
appends the question to `discovery.yaml`, and returns the change to
`awaiting_clarification`. The question must be answered before a new
specification is generated. `devflow approve` rejects a
specification that still lists open questions.

In an interactive run the specification agent checks for missing
decisions **before** writing:

- **Missing decisions:** it asks you about all of them in the same
  session, in batches of up to six, with the same rules as Discovery
  (recommended level-1 option first, a next-level option with its
  reason, security never assumed). Your answers are recorded in
  `discovery.yaml` as decisions resolved by you, and then it writes the
  spec. DevFlow writes the new Discovery digest into the spec header,
  because the agent cannot compute it.
- **No answer, or you prefer to decide later:** it records them as
  `pending`, sets the record to `awaiting_clarification` and stops
  without writing `spec.md`, so no tokens are spent on a document that
  would be discarded.

If the agent leaves `discovery.yaml` invalid, DevFlow writes no
specification and asks you to run `devflow spec --continue`, which
repairs the file first. When an agent lists questions in section 7,
nested bullets stay part of the same question.

DevFlow corrects minor mistakes instead of starting a repair session,
and lists each correction as a warning and in `devflow status`: an
unknown category is read as the closest valid one (for example
`api_contract` as `functional_scope`, `security` as
`security_authentication`), an unknown materiality falls back to the
category default, and a user answer without `answered_by` or
`answered_at` is read as `user` at the record's `updated_at`. The
materiality the agent wrote is kept, so a `critical` decision can still
never be assumed. Unreadable YAML, answers on pending decisions and
assumed critical decisions still require a repair.

DevFlow derives completeness from the decisions themselves: a record
marked `complete` with pending questions is treated as
`awaiting_clarification`, and a question written with
`status: awaiting_clarification` is read as `pending`.

### Level-based Discovery

Discovery builds the solution level by level instead of solving
everything at once:

1. **Level 1 first.** The spec covers the essential behavior, built with
   the tools the project already has, plus basic and obvious security.
2. **Security is always asked, never assumed.** Basic security decisions
   are explicit questions with a recommended option and a short
   explanation, so the user learns them by answering.
3. **Questions offer a next level when a real improvement exists.** One
   option takes the decision one level further (more secure, capable or
   robust; never a mere alternative or a reduction). It is recorded in
   `next_level`, with a `title` phrased as a future spec request:

   ```yaml
   options:
     - "Token valid until logout (basic)"
     - "Token that expires after 24 hours"
   next_level:
     option: "Token that expires after 24 hours"
     title: "Expire login tokens after 24 hours"
     why: "Limits the damage if a token leaks."
   ```

   If the user chooses it, the answer uses that exact text. If not,
   DevFlow suggests `title` (or the option text when there is no title)
   as a later specification. The recommended option is level 1, so a
   `next_level` marked as recommended is ignored.
4. **No deeper than this level.** More advanced decisions found along
   the way, and parts of a large request left for later, are recorded in
   `deferred`:

   ```yaml
   deferred:
     - title: "Limit failed login attempts"
       why: "Protects accounts from password guessing."
       question_id: Q2
   ```

5. **Readiness check.** Before closing, the agent confirms a decision
   exists for every flow, interface, stored data, error case and level-1
   security measure, and asks what is missing in the same round.

DevFlow collects `deferred` items and every unchosen `next_level` into
**suggested next specifications**. They appear in the Decision Context,
in `devflow status`, after approval in the `Next:` line, and in
`spec.md` section `10.1 Suggested next specifications`. DevFlow writes
that subsection itself, with a ready-to-run `devflow spec "..."` command
for each item; the agent does not write it.

### Security baseline (OWASP ASVS 5.0)

DevFlow organizes security with the
[OWASP Application Security Verification Standard](https://owasp.org/www-project-application-security-verification-standard/)
5.0, which groups controls by level: L1 basic, L2 standard, L3 high.

1. **Detection, without tokens.** DevFlow reads the request and the
   Discovery questions and answers, and detects the ASVS areas the
   change touches: authentication (V6), sessions (V7), authorization
   (V8), input validation and encoding (V2, V1), web frontend (V3), file
   handling (V5), APIs (V4), data protection (V14) and deployment
   configuration (V13).
2. **Discovery covers level 1.** The Decision Context lists the
   level-1 controls of each area, with their ASVS identifiers. Every one
   must be covered: by project evidence or by a question whose
   recommended option applies it. Level-2 controls are offered as the
   next level.
3. **Accepted risks have an owner.** If you decide not to apply a
   level-1 control now, it is recorded in `accepted_risks` and Discovery
   stays incomplete until you accept it explicitly:

   ```yaml
   accepted_risks:
     - id: R1
       control: "6.3.1"
       risk: "Login has no protection against password guessing yet."
       reason: "Internal tool behind the VPN; planned for the next spec."
       status: accepted
       accepted_by: jonathan
       accepted_at: "2026-11-10T09:00:00Z"
       review_by: "2026-12-31"
   ```

4. **The spec shows the security work.** Section 4 contains
   `### Security considerations`, a table of threat, mitigation,
   acceptance criterion and ASVS control written by the agent. If the
   agent omits it, DevFlow adds the level-1 controls as a review
   checklist. DevFlow always writes `### Accepted security risks` from
   Discovery.

DevFlow also checks, without tokens, which level-1 controls no question,
answer, evidence or accepted risk cites by its ASVS identifier, and
lists them in the Decision Context and in `devflow status`, so
Discovery covers them before the spec is written.

`devflow status` lists the detected areas and the accepted risks. The
control texts are short summaries; the ASVS document is the normative
reference.

## Workflow

1. Initialize the project with `devflow init`.
2. Create a change and run Discovery.
3. Answer every question and accept or reject assumptions.
4. Generate the specification with `devflow spec --continue <id>`.
5. Review `spec.md`. It must have `None.` in section 7; unresolved
   questions belong in Discovery.
6. Record the approval.
7. Inspect the state, artifacts and approval digests.
8. If artifacts exist without workflow state, diagnose with
   `devflow doctor <id>` and repair with `devflow recover <id>`.

Available commands in `0.4.3`:

| Command | Status |
| --- | --- |
| `devflow init` | Implemented |
| `devflow spec` | Implemented: Discovery, specification, and `--continue` |
| `devflow approve <id>` (stage `spec` by default) | Implemented |
| `devflow reopen <id>` | Implemented: withdraw a spec approval to change it |
| `devflow status <id>` | Implemented |
| `devflow doctor <id>` | Implemented: read-only diagnostics |
| `devflow recover <id>` | Implemented: register existing artifacts |
| `devflow config language <code>` | Implemented: change the documentation language |
| `devflow harness current` | Implemented: show the configured harness and model |
| `devflow harness list` | Implemented: list installed harnesses |
| `devflow harness models <harness>` | Implemented: list advertised models |
| `devflow harness use <harness>` | Implemented: change the harness and regenerate its files |
| `devflow version` | Implemented |
| `devflow plan` | Not implemented |
| `devflow approve <id> --stage plan` | Rejected |
| `devflow implement` | Not implemented |
| `devflow review` | Not implemented |
| `devflow approve <id> --stage review` | Rejected |

There is no separate `execute` command. `approve` is a human
authorization and never changes code. When the `implement` stage is
added, it will be the technical execution command, and it will remain
separate from approval.

### Start, resume and generate a specification

Start a new change:

```bash
devflow spec "Add a GET /patients endpoint that returns JSON"
```

The command:

1. loads and validates the configuration;
2. loads the configured profiles and constitution;
3. builds the context for the effective project mode (`existing` by
   default, or `greenfield`);
4. creates a persistent `discovery.yaml` with classified questions and
   proposed assumptions;
5. writes the Decision Context and the project evidence or declared
   architecture to `context.md`;
6. stops without `spec.md` when any question or assumption remains
   unresolved;
7. in an interactive run, stops after the Discovery session and prints
   the next command, so you can choose the harness for the
   specification;
8. on `--continue` with Discovery already complete (or with `--auto`)
   invokes the selected harness with the specification prompt,
   validates the returned specification, and binds it to the Discovery
   digest;
9. writes `spec.md` and registers the Discovery and specification
   digests in the event log and the workflow projection.

An interactive `devflow spec` therefore uses two harness invocations:
one for Discovery and one for the specification. The first run stops at
the Discovery checkpoint. The second run resumes with the harness you
choose:

```bash
devflow spec "Add a GET /patients endpoint"
devflow spec --continue 006 . --harness opencode
```

Without `--auto`, one interactive command opens at most one agent
session. When a session ends, exit the harness (for example with
`/exit`) so DevFlow can validate the result locally, without spending
tokens:

- after a Discovery session, DevFlow stops and prints the next command,
  also when the session was opened by `--continue`;
- after a specification session, DevFlow validates and registers
  `spec.md`.

Exit the specification session only after the agent says `spec.md` is
written. If the file is missing or invalid, DevFlow writes its
deterministic draft instead.

When no `--harness` is passed, an interactive `devflow spec` asks which
installed harness to use before starting, even if `.devflow/config.yaml`
already names one. The configured harness is offered as the default.
Pass `--harness <name>` to skip the prompt, or `--no-agent` to use
deterministic static analysis.

Use `--auto` to run both phases in a single invocation, as earlier
releases did:

```bash
devflow spec "Add a GET /patients endpoint" --auto
```

Resume an existing change:

```bash
devflow spec --continue 006
```

`--continue` is not a new specification. It reuses the stored request
and project mode, loads Discovery, and stops until no decision is
pending and every assumption is accepted. If it opened a Discovery
session, it stops at the Discovery checkpoint; run `--continue` again to
write the specification. It reuses a current
validated specification when the Discovery digest still matches;
otherwise it archives the old specification and generates a new one. If
an interrupted run left a complete `discovery.yaml` without
`workflow.yaml`, `--continue` creates the missing state and registers
Discovery before generating the specification.

For an existing project, DevFlow inspects relevant code and
dependencies. For Greenfield, it uses the declared architecture and
does not search for code or invent code references.

Useful options:

```bash
devflow spec "Description" --harness opencode --mode non-interactive
devflow spec "Description" --auto
devflow spec "Description" --no-agent
devflow spec "Description" --language es
devflow spec "Change in a real project" --project-mode existing
devflow spec "Create a new service" --project-mode greenfield
devflow spec --continue 006 --harness opencode
```

`--auto` keeps the older one-shot flow: Discovery and the specification
run in the same invocation. Without it, an interactive run stops at the
Discovery checkpoint, including a `--continue` run that answered the
remaining Discovery questions.

`spec --language <code>` selects the language for this run and stores it
as the project default in `.devflow/config.yaml`, so later `--continue`
runs keep the same language. Interactive agent Discovery asks existing
questions and writes new questions in that language, even when the
stored question text was generated in English by the deterministic
planner; the stored question, reason and option text is translated in
place. Specifications written by an agent use the same language. The
deterministic `--no-agent` planner still writes its own stored question
text in English. Use `devflow config language <code>` to change the
default without starting a run.

If the harness is unavailable, fails, or returns an invalid document,
DevFlow writes a deterministic draft and reports the reason. The command
remains usable in CI and on machines without an AI harness, but the draft
still requires human review. A request that is not ready never receives
a silent deterministic specification: Discovery stops instead.

### Check status

```bash
devflow status 001
devflow status 001-add-a-get-patients-endpoint
```

`status` shows the workflow state, registered artifacts and digests,
approvals, stale artifacts and orphan files. It reconciles
`workflow.yaml` from `events.jsonl` before reporting.

It ends with a `Next:` line:

| State | Next |
| --- | --- |
| Discovery pending | `devflow spec --continue 001` |
| Specification validated | review `spec.md`, then `devflow approve 001` |
| Specification approved | ask your coding agent to implement `spec.md` |
| Stale artifact or orphan file | `devflow doctor 001` |

A stale artifact also appears in the status line, for example
`spec_approved (blocked: spec (stale))`.

Use `status` day to day. `doctor` is for a change that `status` reports
as blocked, or that has files on disk without workflow state.

### Diagnose and recover a change

If `context.md`, `discovery.yaml` or `spec.md` were written outside
`devflow spec`, the change can exist on disk without `workflow.yaml`,
`events.jsonl` or `runs/`. In that case `status` reports that no workflow
state was found.

Diagnose the change without changing anything:

```bash
devflow doctor 001
```

`doctor` checks the workflow, Discovery and specification, reports
orphan artifacts, and exits non-zero when the change is unhealthy.

If Discovery is complete but the specification is missing (for example,
an interrupted interactive run), `doctor` prints the resume command:

```bash
devflow spec --continue 001
```

`--continue` creates the missing workflow state, registers the existing
Discovery digest and generates the specification without repeating
Discovery.

If `discovery.yaml` is complete and `spec.md` is structurally valid,
register the existing artifacts without regenerating them:

```bash
devflow recover 001
```

`recover` creates the missing workflow state and registers Discovery and
the specification with `source: existing`. It preserves the artifact
bytes and their digests, does not modify `spec.md`, and does not approve
the change. Running it again after recovery is a no-op.

Recovery does not bypass review. After recovering, inspect
`devflow status 001`, then approve explicitly:

```bash
devflow approve 001
```

If Discovery is incomplete or `spec.md` is invalid, `recover` refuses to
register the artifacts and names the problem. Resolve it with
`devflow spec --continue 001` first.

### Approve the specification

```bash
devflow approve 001
```

Approval is explicit and binds the decision to the current artifact
digests. For a `0.4.3` change it binds `spec.md`, `discovery.yaml` and,
when a manifest applies, the architecture manifest digest. Repeating the
same approval is a no-op. If an artifact changes after validation,
DevFlow marks it stale and refuses approval until it is regenerated and
validated again.

Discovery must be complete before approval. If it is not, approval fails
and names the pending questions and assumptions. Approval also rejects a
specification whose section 7 still lists open questions. Legacy `0.2.0`
changes without `discovery.yaml` remain approvable with a warning.

Only the `spec` stage is available in `0.4.3`, so `--stage` is optional
and defaults to `spec`. `--stage plan` and `--stage review` are
rejected. There are no `plan`, `implement` or
`review` commands in this release.

### Implement an approved specification

DevFlow does not run the implementation itself. Once the spec is
approved, ask your coding agent to implement it:

```text
Implement .devflow/specs/001-add-patients-endpoint/spec.md
```

The generated `AGENTS.md` (or `CLAUDE.md`) tells the agent to:

1. confirm with `devflow status 001` that the change is
   `spec_approved` and the spec artifact is `approved`, not `stale`;
2. read the spec, the constitution and `code-standards.md`;
3. implement only the `FR-XXX` requirements and nothing out of scope;
4. add or update tests for every `AC-XXX` and report each one;
5. leave `.devflow/specs/` untouched and stop on ambiguity instead of
   resolving it silently.

`code-standards.md` governs how code is written, so it is read only in
this step. Discovery and specification prompts skip it to save tokens;
the specification still lists it in section 9.

### Reopen an approved specification

An approved specification is a contract. To change it, reopen it first;
editing `spec.md` directly only marks it `stale`.

```bash
devflow reopen 001              # fix or extend the spec text yourself
devflow reopen 001 --discovery  # add or change decisions with the agent
```

`reopen` asks for confirmation (skip it with `--yes`), copies the
current `spec.md` into `history/`, records a `spec_reopened` event and
withdraws the approval. The previous approval stays in `events.jsonl`;
nothing is deleted.

Without `--discovery`, the change returns to `draft`:

```bash
# edit spec.md
devflow spec --continue 001   # validates and registers your edited spec
devflow approve 001
```

With `--discovery`, the change returns to `awaiting_clarification` and
Discovery is marked pending:

```bash
devflow spec --continue 001   # Discovery session: tell the agent what changes
devflow spec --continue 001   # writes the new spec
devflow approve 001
```

Only an approved spec can be reopened, and only while the change is in
`spec_approved`.

## Generated files

```text
my-project/
├── .devflow/
│   ├── config.yaml
│   ├── architecture.yaml           # declared architecture (Greenfield)
│   ├── .specs.lock                 # serializes specification id assignment
│   ├── constitution/
│   │   ├── constitution.md
│   │   ├── code-standards.md
│   │   ├── architecture.md
│   │   └── django-standards.md     # only when the profile is enabled
│   └── specs/
│       └── 001-add-patients-endpoint/
│           ├── discovery.yaml      # persistent questions and answers
│           ├── context.md          # Decision Context + Project Evidence
│           ├── spec.md             # only when Discovery is complete
│           ├── workflow.yaml       # projection of events.jsonl
│           ├── events.jsonl        # append-only source of truth
│           ├── history/            # earlier versions of spec.md
│           └── .lock               # per-change advisory lock
├── AGENTS.md
├── opencode.json                   # when OpenCode is selected
└── .opencode/agents/               # when OpenCode is selected
```

DevFlow creates only `constitution/` and `specs/` inside `.devflow/`.
Projects initialized before `0.4.2` may also have empty `plans/` and
`templates/` folders and matching keys in `config.yaml`; nothing uses
them, so they can be deleted.

All managed files are identifiable: Markdown files contain
`<!-- devflow:managed -->`, and JSON files contain `"devflowManaged":
true`. Unmanaged files with the same names are left untouched and
reported.

## How approvals and history work

`events.jsonl` is the source of truth. `workflow.yaml` is only a
projection: if it is deleted, lags behind or disagrees with the event log,
DevFlow rebuilds or rejects it rather than trusting it.

```text
generated -> validated -> approved
     |            |            |
     +-> rejected +-> stale    +-> reopen -> validated
```

- An approval stores the artifact kind and its SHA-256 digest.
- Editing an approved artifact makes it stale. Use `devflow reopen` to
  withdraw the approval and change it on purpose.
- A stale, unvalidated or orphan artifact cannot be approved.
- Semantic validation rejects malformed or inconsistent histories.
- Artifact and state writes are atomic; a failed write does not leave a
  partially written managed file.
- Writes are restricted to the project and the configured directories.
  Symlinks that escape the project are rejected or ignored.
- Specification directory allocation is serialized with a lock, so two
  concurrent runs do not receive the same numeric id.

The event log is local and append-only, not cryptographically signed. A
user with full filesystem access can modify it; DevFlow detects
structural and semantic inconsistency, not deliberate tampering by an
administrator.

## Glossary

| Term | Meaning |
| --- | --- |
| **Agent** | An AI model connected through a harness. It explores the project, asks Discovery questions and writes drafts; DevFlow's deterministic checks enforce the rules. |
| **Harness** | The adapter that connects DevFlow to an agent: OpenCode, Antigravity, Codex, Claude Code or Kiro. `none` means no agent is invoked; only deterministic analysis runs. |
| **Model** | The specific AI model used by a harness, for example `provider/model-name`. `init` and `devflow harness use` select it; `spec --model` overrides it for one run. |
| **Discovery** | The joint exploration between the team and the AI that decides whether a request is ready to become a specification. It lives in `discovery.yaml`. |
| **Decision** | A point Discovery must settle: scope, behaviour, data, permissions, architecture boundary, compatibility or out-of-scope work. A decision is `pending`, `resolved` or `assumed`. |
| **Question** | A pending decision presented to a person. It has a category, a materiality and a blocking flag. |
| **Assumption** | A proposed default for a decision that was not resolved by evidence or an explicit answer. A person must accept or reject it; it never becomes accepted on its own. |
| **Materiality** | How much a decision can change the result: `critical`, `functional`, `technical` or `cosmetic`. Critical and security decisions cannot be assumed. |
| **Blocking** | A decision that must be settled before a specification can be generated. |
| **Context** | The generated `context.md`. Its **Decision Context** carries approved decisions, conventions, constraints and open questions; its **Project Evidence** carries the request, static analysis, relevant code, constitution scope and declared architecture. |
| **Constitution** | The project's own engineering rules and standards. DevFlow copies them into `.devflow/constitution/`, and the agent must respect them. |
| **Specification** | The reviewable `spec.md` with requirements and acceptance criteria. It is generated only after Discovery is complete and has no open questions. |
| **Change** | One request tracked under `.devflow/specs/<id>-<slug>/`. The numeric id is stable and is used by `status`, `approve` and `--continue`. |
| **Approval** | An explicit human authorization recorded for a stage. In this release, only the `spec` stage can be approved. |
| **Digest** | A SHA-256 fingerprint of an artifact. An approval binds the exact version reviewed, not just the file name. |
| **Stale** | An artifact that changed after it was validated or approved. A stale artifact must be regenerated or revalidated before it can be approved. |
| **Workflow state** | The recorded history of a change. `events.jsonl` is the append-only source of truth; `workflow.yaml` is a regenerable projection. |
| **Existing project** | The default context: the specification is grounded in the real codebase, its conventions and its constitution. |
| **Greenfield** | A context for a system that does not exist yet. The specification is grounded in requirements and `.devflow/architecture.yaml`; DevFlow does not scaffold code. |
| **Architecture manifest** | `.devflow/architecture.yaml`: the declared style, modules, layers, stack and constraints. DevFlow validates its structure, not its architectural quality. |
| **Language** | The language used for Discovery questions and `spec.md` prose (`en`, `es`, ...). Identifiers, paths, commands and digests are never translated. |

## Updating DevFlow

```bash
pip install --upgrade devflow-toolkit
devflow version
```

Then run `devflow init` again in each project. The update:

- restores missing constitution documents;
- refreshes managed integration files;
- preserves existing constitution documents, specifications,
  approvals and event logs.

Review `.devflow/config.yaml` after a major upgrade, because new options
may have been added. DevFlow does not silently rewrite user-modified
configuration.

## Known limitations

- Only the specification stage is implemented. Planning and review are
  not available. Implementation is delegated to the coding agent through
  the generated `AGENTS.md` instructions; DevFlow does not verify it.
- Greenfield mode produces a specification from a declared
  architecture. It does not scaffold a project, generate application
  code, create Docker or cloud infrastructure, or implement tasks.
- DevFlow validates the structure of the architecture manifest. It does
  not certify that the architecture is correct, complete or appropriate.
- Only OpenCode has been verified end-to-end. Antigravity loading and
  print mode are verified, but not the full workflow. Codex, Claude
  Code and Kiro adapters are unverified scaffolds for future releases.
- Interactive harness mode exists, but the verified release path is
  OpenCode non-interactive mode. Interactive mode requires a terminal.
- Without an available harness, output is produced by deterministic
  static analysis. It is a starting draft, not a substitute for human
  review.
- Static analysis is heuristic: it finds likely affected files, not a
  complete impact map.
- DevFlow is POSIX-only in this release.
- The package does not provide a hosted service, telemetry or remote
  synchronization. All state stays in the project.

## Development

```bash
python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"
pytest
ruff check
python -m build
python -m twine check dist/*
```

The test suite covers the core, CLI, state replay and harness adapters.
Release verification additionally installs the built wheel and sdist in
clean virtual environments and runs the consumer workflow from outside
the repository.

## Acknowledgments

DevFlow is built on the shoulders of open-source work.

**[Typer](https://typer.tiangolo.com)**, by **Sebastián Ramírez
([@tiangolo](https://github.com/tiangolo))**, creator of FastAPI. Every
DevFlow command, option and help screen is built with Typer. Thank you
for making great command-line tools this simple to build.

- **[Rich](https://github.com/Textualize/rich)**, by Will McGugan, for
  the terminal output.
- **[PyYAML](https://pyyaml.org)**, for the Discovery and workflow
  records.
- **[pre-commit](https://pre-commit.com)**, by Anthony Sottile, and the
  Semgrep, Bandit, pip-audit and gitleaks projects, for the local
  security checks.
- **[OWASP](https://owasp.org)**, for the security standards that guide
  DevFlow's security checks.
