Metadata-Version: 2.5
Name: devflow-toolkit
Version: 0.3.9
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

DevFlow is an installable command-line toolkit for managing
specification-driven changes in existing software projects with the help
of an AI coding agent.

It captures the project context, the project constitution and the
approval history, so a specification can be reviewed and approved before
anyone starts implementing it. DevFlow owns the workflow state; the
selected agent harness is only the execution backend that drafts the
specification.

This is the `0.3.9` MVP. It 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 question
has an explicit answer and every proposed 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 the result is often a
throwaway chat response:

- it is not tied to the real codebase;
- it does not follow the project's own engineering rules;
- there is no record of who approved it or which exact version was
  approved;
- switching agents loses context and history.

DevFlow 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.

## 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.

## 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 installed and
  authenticated on `PATH`. OpenCode is the only harness verified
  end-to-end for this release.
- 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.3.9-py3-none-any.whl
```

Verify the installation:

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

## 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 --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 specification
prose. The value is stored as `documentation.language` in
`.devflow/config.yaml` and defaults to `en`. Common language names such
as `Spanish` are normalized to their code (`es`). Required headings,
section numbers, `FR-XXX`/`AC-XXX` identifiers, paths, commands and
digests remain unchanged so structural validation still works.

`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.

## 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
plans:
  path: .devflow/plans
templates:
  path: .devflow/templates
agent:
  harness: opencode
  execution:
    mode: non-interactive
  permissions:
    allow_project_read: true
    allow_workflow_write: true
    allow_source_code_changes: false
```

`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.3.9 |
| --- | --- |
| OpenCode | Verified end-to-end in non-interactive mode |
| 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.

For OpenCode, DevFlow generates `AGENTS.md`, `opencode.json` and the
agents under `.opencode/agents/`. The project-level `opencode.json` can
also select the model used by the agent, 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.

## 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
    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
assumptions:
  - id: A1
    question_id: Q1
    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
```

Each question has a `category` and an explicit `blocking` flag. The
categories are scope, user-visible behaviour, data and persistence,
security and authentication, external integrations, architecture
boundaries, new dependencies and deployment. The `blocking` flag
prioritizes the conversation; it does not make a question optional.
Every question, blocking or not, must be answered before
`discovery.yaml` can be `complete` and before a specification can be
generated.

The deterministic planner recognizes contact pages, forms, comments,
authentication, persistence, deployments and architecture boundaries in
English and Spanish. If a short request does not match any known feature
vocabulary, the planner adds a generic blocking scope question instead
of marking Discovery complete with no questions.

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 question or assumption remains unresolved:

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

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 --stage spec` rejects a
specification that still lists open questions.

## 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.3.9`:

| Command | Status |
| --- | --- |
| `devflow init` | Implemented |
| `devflow spec` | Implemented: Discovery, specification, and `--continue` |
| `devflow approve <id> --stage spec` | Implemented |
| `devflow status <id>` | Implemented |
| `devflow doctor <id>` | Implemented: read-only diagnostics |
| `devflow recover <id>` | Implemented: register existing artifacts |
| `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 deterministic 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 Discovery is complete and prints
   the next command, so you can choose the harness for the
   specification;
8. on `--continue` (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
```

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 every question is
answered and every assumption is accepted. 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.

`spec --language <code>` overrides the configured language for that run
without changing `.devflow/config.yaml`. The deterministic `--no-agent`
draft remains in English; the language setting applies to specifications
written by an agent.

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.

### 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 --stage spec
```

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 --stage spec
```

Approval is explicit and binds the decision to the current artifact
digests. For a `0.3.9` 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.3.9`. `--stage plan` and
`--stage review` are rejected. There are no `plan`, `implement` or
`review` commands in this release.

## 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
│           ├── spec.md             # only when Discovery is complete
│           ├── workflow.yaml       # projection of events.jsonl
│           ├── events.jsonl        # append-only source of truth
│           └── .lock               # per-change advisory lock
├── AGENTS.md
├── opencode.json                   # when OpenCode is selected
└── .opencode/agents/               # when OpenCode is selected
```

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
```

- An approval stores the artifact kind and its SHA-256 digest.
- Editing an approved artifact makes it stale.
- 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.

## 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,
  implementation and review are not available.
- 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. 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.
