A workflow engine for doing the work.

Whatever the work — feature dev, research, hiring pipelines, content production, ops runbooks — if it walks a state machine, this engine runs it. The workflow lives in workflow.yaml: statuses, transitions, validators, side-effects, human-approval gates. Markdown files are the database. One file per work item, plain text, version-controlled, greppable.

issue-cli enforces the workflow contract step by step. The web UI is the human window. Agents, humans, and scripts are all valid clients.

Markdown files are the database

The workflow engine doesn't sit on top of Postgres or a SaaS API. The substrate is a directory of markdown files — one per work item — and a few sidecar files. That choice changes everything downstream.

file
row. One work item per .md file. The filename is the slug.
YAML frontmatter
schema. Typed fields like status, priority, assignee. Custom keys are open columns.
markdown body
row content. Sections that grow as the work progresses — design, implementation, test plan, docs.
subdirectories
partitions. issues/Combat/, issues/Renderer/ — tag and namespace at once.
sidecar JSON
wide-column. <slug>.data.json for structured rows; <slug>.stats.json for transition stats.
git history
audit log. Every status change and body edit is a commit. Free, automatic, replicable.
grep / find / sed
query language. No SDK, no SQL, no API token. Anything that reads files is a client.

The trade-off is real: no JOIN, no transactions across rows, no millions-per-second throughput. In return, you get a database that survives any tool change, that diffs cleanly in a code review, that anyone with a text editor can read or write, that backs up by being git push-ed, and that an LLM can reason about with the same primitives it uses on source code.

The default lifecycle

Nine statuses configured in workflow.yaml. Each transition can carry validators, side-effects, and human-approval gates. The CLI walks the path strictly; the web UI lets a human drag-and-drop to override.

idea raw, needs exploration in design specced, checklists backlog ready, awaits human in progress actively implementing testing verifying behavior human approval human-testing manual verification documentation updating docs shipping commit, push, release done shipped, documented human approval
Human approval gate
Agent-driven status
Terminal status

Anatomy of a transition

Every transition is an ordered list of actions. Validators check preconditions. require_human_approval blocks until a checkbox in the web UI is ticked. Side-effects mutate the issue file or inject prompt context for the next agent.

# workflow.yaml
transitions:
  - from: "in design"
    to:   "backlog"
    actions:
      - type: validate
        rule:  section_min_length
        section: Design
        min: 200
        hint: "flesh out the Design section"
      - type: validate
        rule:  section_checkboxes_checked
        section: Design
      - type: require_human_approval
        status: backlog
      - type: append_section
        title: "Implementation"
        body: |
          - [ ] Wire happy path
          - [ ] Cover edge cases
          - [ ] Add automated tests
      - type: inject_prompt
        prompt: |
          The design is locked. Treat the Design
          section as the spec; raise a comment
          before deviating from it.

validate — section_min_length

Blocks the transition unless ## Design has at least 200 non-whitespace characters. The hint is appended to the failure message so the agent knows exactly what to do next.

validate — section_checkboxes_checked

Every [ ] under ## Design must be ticked. The library includes ~15 validators: has_pr_url, linked_issue_in_status, field_in, command_succeeds, and more.

require_human_approval

The CLI refuses the transition until a human ticks the matching checkbox in the web UI. The CLI's failure message includes a deep link to the exact approval row.

append_section

Side-effect: drops a checklist scaffold into the issue body so the next stage starts with a known shape. Fence-aware — quoted markdown in the body won't trigger a false "section already exists".

inject_prompt

Adds extra guidance for this specific transition. Combines with the destination status's baseline prompt when the next agent picks up the issue.

Workflow examples

Four patterns from a real workflow. Drop them into workflow.yaml and they take effect on the next CLI invocation.

approval gate

Block in progress until a human approves

Agents finish design and stop, instead of plowing into implementation off a half-baked spec.

transitions:
  - from: "backlog"
    to:   "in progress"
    actions:
      - type: require_human_approval
        status: "in progress"

# Agent runs:    issue-cli start fix-heat
# CLI answers:   missing approval — open
#   /p/x/issue/fix-heat#approve-in-progress
#   to grant it.
shell validator

Don't ship done without a green test suite

Templated arguments, sandboxed env, opt-in via top-level allow_shell: true.

allow_shell: true

transitions:
  - from: "shipping"
    to:   "done"
    actions:
      - type: validate
        rule:  command_succeeds
        command:
          "gh pr view {{number}} --json state
           -q .state | grep -q MERGED"
        timeout_seconds: 15
        hint: "land or close PR #{{number}}"
optional parking state

Park on another team without breaking the path

Statuses marked optional: true are skippable on forward transitions but reachable as a CTA when needed.

statuses:
  - name: "in progress"
  - name: "waiting-for-team-input"
    optional: true
    description: "blocked on another team"
  - name: "testing"

transitions:
  - from: "in progress"
    to:   "waiting-for-team-input"
    cta_label: "Block on another team"
    actions:
      - type: require_human_approval
        status: "waiting-for-team-input"
system overlay

Per-subsystem rules without forking the workflow

Each system (API, CLI, UI, …) can override status prompts and add transition actions. Overlays merge with the base workflow.

systems:
  API:
    statuses:
      - name: "in design"
        prompt: |
          API design must include the OpenAPI
          delta and a backwards-compat note.
    transitions:
      - from: "testing"
        to:   "documentation"
        actions:
          - type: validate
            rule:  has_section
            section: "API Reference"

The CLI: issue-cli

issue-cli is how clients drive the workflow. Bots, humans at a terminal, CI jobs, shell scripts — same interface. The CLI presents the workflow contract as a set of subcommands and refuses to violate it.

Where the web UI lets a human bypass the rules with a drag-and-drop, the CLI enforces them. create only allows idea or in design. transition moves one status forward and rejects skips. done is only valid from documentation. There is no --force.

Failure messages double as remediation: every gate rejection ends with an issue-cli command the caller can run to fix the gate. The contract is also surfaced before the transition, via the Requires: / Will: block printed underneath every == Next == hint, so the caller knows what's coming. This works as well for an LLM agent as it does for a developer running commands by hand.

Discovery

process
Print the live workflow: statuses, prompts, transitions, validators, side-effects.
process schema
Print the workflow.yaml schema with field types and rules.
next
Find work for a version (backlog + in progress + testing).
context
Full body, comments, checklist for one issue.
list / search
Filter or grep across the project.
stats
Project health overview.

Drive the workflow

start
Pick up an issue: claim, transition forward, print next-step contract.
transition
Move one status forward (strict).
claim / unclaim
Set or clear the assignee.
done
Mark done; only valid from documentation.
append / replace
Body edits, section-aware, fence-safe.
check / comment
Tick a checkbox or add an inline comment.
data
Per-issue structured data store (sidecar JSON).

A real issue-cli process transitions dump — the contract an agent reads before touching anything:

$ issue-cli process transitions

== Transition Rules ==

  → idea                        Initial state — title only
  idea → in design              Validate issue body is not empty
                                  Side-effect: appends ## Idea section
                                  Side-effect: appends ## Design section
                                  Side-effect: appends ## Acceptance Criteria section
  in design → backlog           Validate section Design checkboxes are checked
                                  Validate section Acceptance Criteria has checkboxes
                                  Must be human-approved for "backlog" in the issue viewer
                                  Side-effect: clears assignee
  backlog → in progress         Must be human-approved for "in progress" in the issue viewer
                                  Validate issue has assignee
                                  Side-effect: appends ## Implementation section
                                  Side-effect: appends ## Test Plan section
  in progress → testing         Validate section Implementation checkboxes are checked
                                  Validate test plan is present
                                  Side-effect: appends ## Testing section
  testing → human-testing       Validate test plan is present
                                  Validate section Testing checkboxes are checked
                                  Validate comment starts with tests:
                                  Side-effect: appends ## Human Testing section
  human-testing → documentation  Must be human-approved for "documentation" in the issue viewer
                                  Side-effect: appends ## Documentation section
  documentation → shipping      Validate section Documentation checkboxes are checked
                                  Validate comment starts with docs:
                                  Side-effect: appends ## Shipping section
  shipping → done               Validate section Shipping checkboxes are checked
                                  Must be human-approved for "done" in the issue viewer

Transitions are strict — you cannot skip required statuses.

Issues are files that grow

An issue starts almost empty — a title and a few lines of context. As it walks the workflow, each transition appends a new section to its body. By the time the issue reaches done, the file is a self-contained record of every decision and verification that produced the change.

This is the opposite of the ticket-system model where an issue is a static description and the work happens elsewhere — in chat, in PR comments, in a wiki, in some tracker's activity log. Here the file is the activity log. Design checklists, implementation notes, the test plan, the docs links, the shipping refs, the inline review comments — they all accrete into the same markdown file, in the same git repo, under the same diff history.

The engine drives this directly: append_section side-effects on transitions scaffold the next stage's structure with empty checkboxes. The agent fills the boxes and the prose. Validators on the next transition check that the boxes were ticked. By the time you read the file at done, it tells you what the change was, why, what was considered, what was tested, and how it shipped.

Inline comments live at the bottom of each file in an HTML comment block — invisible to grep, cat, and other markdown renderers, but addressable in the web UI per-block. Per-issue structured data (code-review findings, triage rows) lives in a sidecar JSON next to the issue file. Custom frontmatter keys render as a sidebar in the detail view.

A single issue file at done, annotated with the transition that produced each section

issues/Combat/42-fix-heat-overflow.md
# --- frontmatter ---create
---
title: "Fix heat overflow on burst weapons"
status: "done"
system: "Combat"
version: "0.4"
priority: "high"
labels: [bug, combat]
pr: "https://github.com/me/proj/pull/812"
---

# --- body intro ---create
Burst weapons accumulate heat across modules and overflow
the i16 register at sustained fire. Reproducible with the
"long burn" scenario in tests.

# --- appended on idea → in design ---idea → in design
## Idea
- [x] Description with enough context for someone unfamiliar
- [x] Edge cases identified (overflow, underflow, multi-module)
- [x] Scope clear (what is NOT included)

## Design
- [x] Switch heat accumulator to i32, gate at MAX_HEAT
- [x] Per-module heat decay rate
- [x] Test strategy: long-burn fixture + property test

## Acceptance Criteria
- [x] No overflow under 10x sustained fire
- [x] Existing scenarios pass unchanged

# --- appended on backlog → in progress ---backlog → in progress
## Implementation
- [x] Wire i32 accumulator in combat/heat.go
- [x] Migrate save format (backwards-compatible)
- [x] Cover edge cases from the Design section

## Test Plan
- [x] Unit: heat_test.go — long burn, edge cases
- [x] Property test: random weapon mixes, 10k iterations
- [x] Manual: smoke through tutorial mission

# --- appended on in progress → testing ---in progress → testing
## Testing
- [x] All automated tests green on CI
- [x] No regression in existing fixtures
- [x] tests: 10k-iteration property run completed clean

# --- appended on human-testing → documentation ---human-testing → docs
## Documentation
- [x] Updated docs/Combat/heat-model.md
- [x] Added migration note to CHANGELOG
- [x] docs: heat-model section reviewed

# --- appended on documentation → shipping ---docs → shipping
## Shipping
- [x] Committed with ref #42
- [x] Pushed; PR #812 merged
- [x] Tagged v0.4.1, release notes polished

# --- inline comments accrete throughout ---
<!-- issue-viewer-comments
{"id":1,"block":2,"date":"2026-04-12","text":"check legacy save format","status":"done"}
{"id":2,"block":4,"date":"2026-04-14","text":"property test seed?","status":"done"}
-->

Operating the workflow

Three views from the running web UI: authoring the workflow, observing what the engine has done, and feeding lessons back into the workflow itself.

Workflow engine designer
Workflow designerVisual editor for the lifecycle. Statuses, transitions, validators, and side-effects rendered straight from workflow.yaml.
Agent activity timeline
Agent timelineChronological log of every command run against the project — dispatch, start, transition, append, retrospective, and more.
Retrospectives view
RetrospectivesWorkflow feedback that lives next to the work. Each retro is a markdown file; lessons feed back into workflow.yaml.
Kanban board view
BoardDrag-and-drop, score badges, agent indicators, version and system filters.
List view
ListFilterable, sortable, score column, search across titles and bodies.
Docs view
DocsPer-system documentation rendered straight out of the docs directory.

Run it locally

The repo ships with a configured demo workflow, sample issues, and docs.

1. Clone and run the demo

Boots a sample project at localhost:8080.

git clone github.com/michal-franc/
  ai-native-project-viewer
cd ai-native-project-viewer
make demo

2. Install the CLI

Walks agents through the workflow contract.

make install

issue-cli process
issue-cli next --version 0.1
issue-cli start <slug>

3. Configure your workflow

Edit workflow.yaml. Validators, gates, side-effects, overlays — all hot-reloaded.

$EDITOR workflow.yaml

issue-cli process schema
issue-cli process transitions