duckflow is a lightweight annotation format and toolkit for tracing data flow through source code using local, comment-based facts.
The split is intentional:
- Source comments store only local facts about the code immediately below them.
- Generated graph artifacts stitch those local facts into end-to-end paths.
duckflow/core.py: extraction, filtering, stitching, and Mermaid rendering logicduckflow/cli.py: installable CLI entry pointsscripts/extract_duckflow.py: CLI for normalized JSON outputscripts/generate_duckflow_mermaid.py: CLI for Mermaid flowchart outputtests/test_duckflow_tools.py: parser and graph-behavior testsdocs/skill-outline.md: draft user-level skill outlinedocs/prompt-structure.md: draft/duckflowprompt structure
Each annotation is a YAML mapping stored in a source comment after duckflow:.
Use one fixed vocabulary only.
Required fields:
id: stable unique identifier for the annotated code block.kind: one ofui,api,state,orchestrator,artifact, or another small local role label.timestamp: UTC annotation update time inYYYY-MM-DDTHH:MM:SSZformat. Bump it whenever the annotated code block changes in a way that affects duckflow facts.
Optional fields:
status:live,planned, orshared.handles: operations this block owns, such asPOST /api/generate-summaryorui:summary-review.build.calls: operations this block invokes.reads: state, response, or artifact tokens consumed locally.writes: state or artifact tokens written locally.returns: response or function-output tokens exposed locally.notes: brief local clarification.
# duckflow:
# id: summary.api.generate
# kind: api
# timestamp: "2026-03-25T00:00:00Z"
# status: live
# handles: ["POST /api/generate-summary"]
# writes: ["state:session_summaries.ai_generated"]
# returns: ["response:POST /api/generate-summary.summary"]
Allowed keys:
idkindtimestampstatushandlescallsreadswritesreturnsnotes
Legacy JSON and shorthand annotations are not supported.
Use exact string tokens so the graph builder can stitch by equality.
- HTTP handlers:
POST /api/generate-summary - UI steps:
ui:summary-review.build - Session state:
state:summary_focus_override - Customization payload:
customizations:summary_focus - API responses:
response:GET /api/status.professional_summaries - Preview artifacts:
artifact:generation_state.preview_html - Output files:
file:generated_files.final_html
The extractor and Mermaid generator build edges from local facts only:
- Control edge:
callsmatches another annotation'shandles - Data edge:
writesorreturnsmatches another annotation'sreads
- Keep annotations adjacent to the code they describe.
- Record only facts visible in the local block.
- Prefer a small number of stable tokens over prose.
- Every annotation must include a UTC
timestamp, and that timestamp must be refreshed whenever the annotated code changes. - When two implementations mirror the same local flow, annotate both and mark
statusaccurately. - Do not describe whole workflows in source comments; let generated artifacts do that.
python -m venv .venv
source .venv/bin/activate
pip install -e .[dev]Extract normalized entries:
duckflow-extract --repo-root .or:
python scripts/extract_duckflow.py --repo-root .Render Mermaid:
duckflow-mermaid --repo-root .or:
python scripts/generate_duckflow_mermaid.py --repo-root .Render only matching flow entries:
python scripts/generate_duckflow_mermaid.py --repo-root . --match summaryRestrict scanning to explicit globs:
python scripts/extract_duckflow.py --repo-root . --include "src/**/*.py" --include "web/**/*.ts"