petrarca-agent-flow 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. petrarca_agent_flow-0.1.0/.github/workflows/ci.yml +97 -0
  2. petrarca_agent_flow-0.1.0/.github/workflows/publish.yml +82 -0
  3. petrarca_agent_flow-0.1.0/.github/workflows/release.yml +29 -0
  4. petrarca_agent_flow-0.1.0/.gitignore +21 -0
  5. petrarca_agent_flow-0.1.0/.pre-commit-config.yaml +37 -0
  6. petrarca_agent_flow-0.1.0/AGENTS.md +193 -0
  7. petrarca_agent_flow-0.1.0/CONTRIBUTING.md +121 -0
  8. petrarca_agent_flow-0.1.0/LICENSE +190 -0
  9. petrarca_agent_flow-0.1.0/PKG-INFO +360 -0
  10. petrarca_agent_flow-0.1.0/README.md +324 -0
  11. petrarca_agent_flow-0.1.0/Taskfile.yml +157 -0
  12. petrarca_agent_flow-0.1.0/deploy/docker-compose.yml +63 -0
  13. petrarca_agent_flow-0.1.0/docs/README.md +13 -0
  14. petrarca_agent_flow-0.1.0/docs/design/orchestrator/backend.md +117 -0
  15. petrarca_agent_flow-0.1.0/docs/design/orchestrator/cli-events.md +150 -0
  16. petrarca_agent_flow-0.1.0/docs/design/orchestrator/control-file.md +93 -0
  17. petrarca_agent_flow-0.1.0/docs/design/orchestrator/engine.md +114 -0
  18. petrarca_agent_flow-0.1.0/docs/design/orchestrator/flowdef.md +174 -0
  19. petrarca_agent_flow-0.1.0/docs/design/orchestrator/gates.md +106 -0
  20. petrarca_agent_flow-0.1.0/docs/design/orchestrator/index.md +145 -0
  21. petrarca_agent_flow-0.1.0/docs/design/orchestrator/input-plane.md +192 -0
  22. petrarca_agent_flow-0.1.0/docs/design/orchestrator/node_builder.md +82 -0
  23. petrarca_agent_flow-0.1.0/docs/design/orchestrator/result-schema.md +77 -0
  24. petrarca_agent_flow-0.1.0/docs/design/orchestrator/supervision.md +127 -0
  25. petrarca_agent_flow-0.1.0/docs/usage/advanced-recipes.md +495 -0
  26. petrarca_agent_flow-0.1.0/docs/usage/getting-started.md +212 -0
  27. petrarca_agent_flow-0.1.0/docs/usage/index.md +74 -0
  28. petrarca_agent_flow-0.1.0/docs/usage/recipes.md +187 -0
  29. petrarca_agent_flow-0.1.0/docs/usage/writing-agents.md +120 -0
  30. petrarca_agent_flow-0.1.0/examples/.opencode/agent/analyst.md +41 -0
  31. petrarca_agent_flow-0.1.0/examples/.opencode/agent/architecture-analyst.md +37 -0
  32. petrarca_agent_flow-0.1.0/examples/.opencode/agent/architecture-verifier.md +33 -0
  33. petrarca_agent_flow-0.1.0/examples/.opencode/agent/coupling-analyst.md +35 -0
  34. petrarca_agent_flow-0.1.0/examples/.opencode/agent/coupling-verifier.md +33 -0
  35. petrarca_agent_flow-0.1.0/examples/.opencode/agent/domain-analyst.md +37 -0
  36. petrarca_agent_flow-0.1.0/examples/.opencode/agent/domain-verifier.md +33 -0
  37. petrarca_agent_flow-0.1.0/examples/.opencode/agent/executive-summary.md +38 -0
  38. petrarca_agent_flow-0.1.0/examples/.opencode/agent/extractor.md +38 -0
  39. petrarca_agent_flow-0.1.0/examples/.opencode/agent/summary-verifier.md +33 -0
  40. petrarca_agent_flow-0.1.0/examples/.opencode/agent/tech-stack-analyst.md +37 -0
  41. petrarca_agent_flow-0.1.0/examples/.opencode/agent/tech-stack-verifier.md +33 -0
  42. petrarca_agent_flow-0.1.0/examples/.opencode/agent/verifier.md +36 -0
  43. petrarca_agent_flow-0.1.0/examples/README.md +66 -0
  44. petrarca_agent_flow-0.1.0/examples/__init__.py +0 -0
  45. petrarca_agent_flow-0.1.0/examples/custom_flow.py +422 -0
  46. petrarca_agent_flow-0.1.0/examples/declarative.py +154 -0
  47. petrarca_agent_flow-0.1.0/examples/imperative.py +92 -0
  48. petrarca_agent_flow-0.1.0/examples/inprocess.py +180 -0
  49. petrarca_agent_flow-0.1.0/pyproject.toml +86 -0
  50. petrarca_agent_flow-0.1.0/setup.cfg +4 -0
  51. petrarca_agent_flow-0.1.0/src/agent_flow/__init__.py +222 -0
  52. petrarca_agent_flow-0.1.0/src/agent_flow/backends/__init__.py +68 -0
  53. petrarca_agent_flow-0.1.0/src/agent_flow/backends/_prefect_env.py +94 -0
  54. petrarca_agent_flow-0.1.0/src/agent_flow/backends/base.py +107 -0
  55. petrarca_agent_flow-0.1.0/src/agent_flow/backends/inprocess.py +80 -0
  56. petrarca_agent_flow-0.1.0/src/agent_flow/backends/prefect.py +102 -0
  57. petrarca_agent_flow-0.1.0/src/agent_flow/cli/__init__.py +38 -0
  58. petrarca_agent_flow-0.1.0/src/agent_flow/cli/app.py +126 -0
  59. petrarca_agent_flow-0.1.0/src/agent_flow/cli/commands/__init__.py +7 -0
  60. petrarca_agent_flow-0.1.0/src/agent_flow/cli/commands/nodes.py +82 -0
  61. petrarca_agent_flow-0.1.0/src/agent_flow/cli/commands/run.py +248 -0
  62. petrarca_agent_flow-0.1.0/src/agent_flow/cli/console.py +22 -0
  63. petrarca_agent_flow-0.1.0/src/agent_flow/cli/context.py +28 -0
  64. petrarca_agent_flow-0.1.0/src/agent_flow/cli/events.py +216 -0
  65. petrarca_agent_flow-0.1.0/src/agent_flow/cli/progress.py +56 -0
  66. petrarca_agent_flow-0.1.0/src/agent_flow/cli/tables.py +62 -0
  67. petrarca_agent_flow-0.1.0/src/agent_flow/core/__init__.py +72 -0
  68. petrarca_agent_flow-0.1.0/src/agent_flow/core/_mock_agent.py +232 -0
  69. petrarca_agent_flow-0.1.0/src/agent_flow/core/agent_runtime.py +425 -0
  70. petrarca_agent_flow-0.1.0/src/agent_flow/core/context.py +86 -0
  71. petrarca_agent_flow-0.1.0/src/agent_flow/core/control_protocol.py +96 -0
  72. petrarca_agent_flow-0.1.0/src/agent_flow/core/env.py +50 -0
  73. petrarca_agent_flow-0.1.0/src/agent_flow/core/report_signals.py +57 -0
  74. petrarca_agent_flow-0.1.0/src/agent_flow/core/schema.py +112 -0
  75. petrarca_agent_flow-0.1.0/src/agent_flow/core/schema_pydantic.py +39 -0
  76. petrarca_agent_flow-0.1.0/src/agent_flow/engine.py +813 -0
  77. petrarca_agent_flow-0.1.0/src/agent_flow/flowdef/__init__.py +15 -0
  78. petrarca_agent_flow-0.1.0/src/agent_flow/flowdef/compile.py +129 -0
  79. petrarca_agent_flow-0.1.0/src/agent_flow/flowdef/models.py +109 -0
  80. petrarca_agent_flow-0.1.0/src/agent_flow/gates.py +224 -0
  81. petrarca_agent_flow-0.1.0/src/agent_flow/node_builder.py +266 -0
  82. petrarca_agent_flow-0.1.0/src/agent_flow/preflight.py +103 -0
  83. petrarca_agent_flow-0.1.0/src/agent_flow/registry.py +258 -0
  84. petrarca_agent_flow-0.1.0/src/agent_flow/run_config.py +257 -0
  85. petrarca_agent_flow-0.1.0/src/agent_flow/run_context.py +126 -0
  86. petrarca_agent_flow-0.1.0/src/agent_flow/runners/__init__.py +77 -0
  87. petrarca_agent_flow-0.1.0/src/agent_flow/runners/base.py +236 -0
  88. petrarca_agent_flow-0.1.0/src/agent_flow/runners/claude_code.py +52 -0
  89. petrarca_agent_flow-0.1.0/src/agent_flow/runners/executor.py +93 -0
  90. petrarca_agent_flow-0.1.0/src/agent_flow/runners/inprocess.py +119 -0
  91. petrarca_agent_flow-0.1.0/src/agent_flow/runners/mock.py +34 -0
  92. petrarca_agent_flow-0.1.0/src/agent_flow/runners/opencode.py +252 -0
  93. petrarca_agent_flow-0.1.0/src/agent_flow/utils.py +97 -0
  94. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/PKG-INFO +360 -0
  95. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/SOURCES.txt +130 -0
  96. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/dependency_links.txt +1 -0
  97. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/requires.txt +25 -0
  98. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/scm_file_list.json +127 -0
  99. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/scm_version.json +8 -0
  100. petrarca_agent_flow-0.1.0/src/petrarca_agent_flow.egg-info/top_level.txt +1 -0
  101. petrarca_agent_flow-0.1.0/tests/conftest.py +52 -0
  102. petrarca_agent_flow-0.1.0/tests/fixtures/opencode/agent/selftest-analyst.md +18 -0
  103. petrarca_agent_flow-0.1.0/tests/integration/test_flow_backends.py +79 -0
  104. petrarca_agent_flow-0.1.0/tests/integration/test_flow_progress.py +53 -0
  105. petrarca_agent_flow-0.1.0/tests/integration/test_run_agent_mock.py +125 -0
  106. petrarca_agent_flow-0.1.0/tests/integration/test_run_agent_opencode.py +57 -0
  107. petrarca_agent_flow-0.1.0/tests/unit/test_backends.py +164 -0
  108. petrarca_agent_flow-0.1.0/tests/unit/test_cli_summary.py +63 -0
  109. petrarca_agent_flow-0.1.0/tests/unit/test_context.py +49 -0
  110. petrarca_agent_flow-0.1.0/tests/unit/test_control_protocol.py +22 -0
  111. petrarca_agent_flow-0.1.0/tests/unit/test_engine.py +196 -0
  112. petrarca_agent_flow-0.1.0/tests/unit/test_env.py +31 -0
  113. petrarca_agent_flow-0.1.0/tests/unit/test_events.py +252 -0
  114. petrarca_agent_flow-0.1.0/tests/unit/test_flowdef.py +98 -0
  115. petrarca_agent_flow-0.1.0/tests/unit/test_inprocess.py +175 -0
  116. petrarca_agent_flow-0.1.0/tests/unit/test_instructions.py +128 -0
  117. petrarca_agent_flow-0.1.0/tests/unit/test_node_builder.py +243 -0
  118. petrarca_agent_flow-0.1.0/tests/unit/test_on_event.py +45 -0
  119. petrarca_agent_flow-0.1.0/tests/unit/test_only.py +119 -0
  120. petrarca_agent_flow-0.1.0/tests/unit/test_prefect_isolation.py +139 -0
  121. petrarca_agent_flow-0.1.0/tests/unit/test_preflight.py +115 -0
  122. petrarca_agent_flow-0.1.0/tests/unit/test_progress.py +68 -0
  123. petrarca_agent_flow-0.1.0/tests/unit/test_registry.py +241 -0
  124. petrarca_agent_flow-0.1.0/tests/unit/test_report_signals.py +98 -0
  125. petrarca_agent_flow-0.1.0/tests/unit/test_require_extra.py +24 -0
  126. petrarca_agent_flow-0.1.0/tests/unit/test_run_config.py +146 -0
  127. petrarca_agent_flow-0.1.0/tests/unit/test_run_context.py +169 -0
  128. petrarca_agent_flow-0.1.0/tests/unit/test_runners.py +105 -0
  129. petrarca_agent_flow-0.1.0/tests/unit/test_schema.py +99 -0
  130. petrarca_agent_flow-0.1.0/tests/unit/test_start_from.py +84 -0
  131. petrarca_agent_flow-0.1.0/tests/unit/test_utils.py +53 -0
  132. petrarca_agent_flow-0.1.0/uv.lock +1936 -0
@@ -0,0 +1,97 @@
1
+ name: CI
2
+
3
+ # Build-only CI: lint, format-check, tests, and build the package.
4
+ # Publishing to PyPI + the GitHub Release happen on a version tag (v*) via
5
+ # publish.yml / release.yml, not here.
6
+
7
+ on:
8
+ push:
9
+ branches: [main]
10
+ paths-ignore:
11
+ - '**/*.md'
12
+ pull_request:
13
+ branches: [main]
14
+ paths-ignore:
15
+ - '**/*.md'
16
+ workflow_dispatch:
17
+
18
+ permissions:
19
+ contents: read
20
+
21
+ jobs:
22
+ test:
23
+ name: Lint + Test
24
+ runs-on: ubuntu-latest
25
+ timeout-minutes: 20
26
+ strategy:
27
+ matrix:
28
+ python-version: ['3.14']
29
+
30
+ steps:
31
+ - name: Checkout repository
32
+ uses: actions/checkout@v7
33
+ with:
34
+ fetch-depth: 0 # setuptools-scm needs full history for the version
35
+
36
+ - name: Set up Python ${{ matrix.python-version }}
37
+ uses: actions/setup-python@v7
38
+ with:
39
+ python-version: ${{ matrix.python-version }}
40
+
41
+ - name: Install uv
42
+ uses: astral-sh/setup-uv@v9.0.0
43
+ with:
44
+ enable-cache: true
45
+
46
+ - name: Install Task
47
+ uses: arduino/setup-task@v3.0.0
48
+ with:
49
+ version: 3.x
50
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
51
+
52
+ - name: Install dependencies (editable + dev extras)
53
+ run: task install
54
+
55
+ - name: Lint + format check (read-only)
56
+ run: task verify
57
+
58
+ - name: Unit + integration tests (mock; opencode e2e is skipped)
59
+ run: task test:all
60
+
61
+ build:
62
+ name: Build package
63
+ runs-on: ubuntu-latest
64
+ timeout-minutes: 15
65
+ needs: test
66
+
67
+ steps:
68
+ - name: Checkout repository
69
+ uses: actions/checkout@v7
70
+ with:
71
+ fetch-depth: 0
72
+
73
+ - name: Set up Python 3.14
74
+ uses: actions/setup-python@v7
75
+ with:
76
+ python-version: '3.14'
77
+
78
+ - name: Install uv
79
+ uses: astral-sh/setup-uv@v9.0.0
80
+ with:
81
+ enable-cache: true
82
+
83
+ - name: Install Task
84
+ uses: arduino/setup-task@v3.0.0
85
+ with:
86
+ version: 3.x
87
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
88
+
89
+ - name: Build sdist + wheel
90
+ run: task build
91
+
92
+ - name: Upload build artifacts
93
+ uses: actions/upload-artifact@v7
94
+ with:
95
+ name: dist-${{ github.sha }}
96
+ path: dist/
97
+ retention-days: 7
@@ -0,0 +1,82 @@
1
+ name: Publish to PyPI
2
+
3
+ # Publish on a version tag. setuptools-scm derives the version from the tag
4
+ # (see [tool.setuptools_scm] tag_regex "^v..."), so tagging vX.Y.Z is the release
5
+ # trigger. Trusted publishing (OIDC) is used — no API token secret needed; the
6
+ # PyPI project must have this repo configured as a trusted publisher for the
7
+ # `pypi` environment.
8
+
9
+ on:
10
+ push:
11
+ tags:
12
+ - 'v*'
13
+
14
+ permissions:
15
+ contents: read
16
+ id-token: write # Required for trusted publishing (OIDC)
17
+
18
+ jobs:
19
+ test:
20
+ name: Lint + Test
21
+ runs-on: ubuntu-latest
22
+ timeout-minutes: 20
23
+
24
+ steps:
25
+ - name: Checkout repository
26
+ uses: actions/checkout@v7
27
+ with:
28
+ fetch-depth: 0 # setuptools-scm needs full history for the version
29
+
30
+ - name: Set up Python 3.14
31
+ uses: actions/setup-python@v7
32
+ with:
33
+ python-version: '3.14'
34
+
35
+ - name: Install uv
36
+ uses: astral-sh/setup-uv@v9.0.0
37
+ with:
38
+ enable-cache: true
39
+
40
+ - name: Install Task
41
+ uses: arduino/setup-task@v3.0.0
42
+ with:
43
+ version: 3.x
44
+ repo-token: ${{ secrets.GITHUB_TOKEN }}
45
+
46
+ - name: Install dependencies (editable + dev extras)
47
+ run: task install
48
+
49
+ - name: Lint + format check (read-only)
50
+ run: task verify
51
+
52
+ - name: Unit + integration tests (mock; opencode e2e is skipped)
53
+ run: task test:all
54
+
55
+ publish:
56
+ name: Build + Publish to PyPI
57
+ runs-on: ubuntu-latest
58
+ timeout-minutes: 15
59
+ needs: test
60
+ environment: pypi
61
+
62
+ steps:
63
+ - name: Checkout repository
64
+ uses: actions/checkout@v7
65
+ with:
66
+ fetch-depth: 0 # Required for setuptools-scm
67
+
68
+ - name: Set up Python 3.14
69
+ uses: actions/setup-python@v7
70
+ with:
71
+ python-version: '3.14'
72
+
73
+ - name: Install uv
74
+ uses: astral-sh/setup-uv@v9.0.0
75
+ with:
76
+ enable-cache: true
77
+
78
+ - name: Build sdist + wheel
79
+ run: uv build
80
+
81
+ - name: Publish to PyPI
82
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,29 @@
1
+ name: Release
2
+
3
+ # Create a GitHub Release with auto-generated notes on a version tag. Runs
4
+ # alongside publish.yml (both trigger on 'v*'); this one only creates the
5
+ # Release entry, publish.yml uploads to PyPI.
6
+
7
+ on:
8
+ push:
9
+ tags:
10
+ - 'v*'
11
+
12
+ permissions:
13
+ contents: write
14
+
15
+ jobs:
16
+ release:
17
+ name: Create GitHub Release
18
+ runs-on: ubuntu-latest
19
+ timeout-minutes: 5
20
+ steps:
21
+ - name: Checkout repository
22
+ uses: actions/checkout@v7
23
+ with:
24
+ fetch-depth: 0
25
+
26
+ - name: Create GitHub Release
27
+ uses: softprops/action-gh-release@v3
28
+ with:
29
+ generate_release_notes: true
@@ -0,0 +1,21 @@
1
+ .venv/
2
+ .prefect/
3
+ .env
4
+ __pycache__/
5
+ *.pyc
6
+ *.egg-info/
7
+ .ruff_cache/
8
+ dist/
9
+ build/
10
+
11
+ .DS_Store
12
+
13
+ # Example RUN ARTIFACTS — reports/sidecars agents write during a demo run when
14
+ # run_dir/REPORT resolves into the example dir (normal runs go to /tmp). Agent
15
+ # DEFINITIONS under examples/**/.opencode/agent/ are tracked and NOT ignored.
16
+ examples/*/*.md
17
+ examples/*/*.json
18
+ examples/*/*.control.json
19
+
20
+ # JS deps accidentally created under an example's .opencode/
21
+ node_modules/
@@ -0,0 +1,37 @@
1
+ ###############################
2
+ # pre-commit configuration
3
+ #
4
+ # Strategy:
5
+ # - Use only "local" hooks so we orchestrate via Taskfile tasks (single source
6
+ # of truth for how we lint/format/test).
7
+ # - Split fast feedback (pre-commit) from deeper validation (pre-push).
8
+ # - pass_filenames: false because the tasks already know what to operate on.
9
+ #
10
+ # Tips:
11
+ # - Skip all hooks: git commit -m "msg" --no-verify
12
+ # - Run manually: task fct
13
+ # - Install the hooks: task pre-commit:install
14
+ # - Update the hooks: task pre-commit:update
15
+ ###############################
16
+ repos:
17
+ - repo: local
18
+ hooks:
19
+ # Pre-commit (fast): format + lint(+fix) + unit tests.
20
+ - id: fct
21
+ name: "format + check + unit tests (quick)"
22
+ entry: bash -c 'task fct'
23
+ language: system
24
+ pass_filenames: false
25
+ files: \.py$
26
+
27
+ # Pre-push (deeper): read-only lint/format gate + unit tests. Integration
28
+ # (mock subprocess) and the real-opencode e2e are deliberately NOT run here
29
+ # — they are slower / opt-in; run them explicitly with `task test:all` /
30
+ # `task test:opencode` when needed.
31
+ - id: verify-and-test
32
+ name: "pre-push: verify + unit tests"
33
+ entry: bash -c 'task verify && task test'
34
+ language: system
35
+ pass_filenames: false
36
+ files: \.py$
37
+ stages: [pre-push]
@@ -0,0 +1,193 @@
1
+ # Agent Instructions
2
+
3
+ This file contains project-specific rules and conventions for AI coding
4
+ assistants working on **agent-flow**.
5
+
6
+ ## Project Overview
7
+
8
+ agent-flow is a Python library for **deterministic orchestration of coding-agent
9
+ pipelines**. It replaces the fragile "LLM orchestrator agent" pattern with a
10
+ deterministic engine that supervises coding-agent subprocesses (opencode today)
11
+ and runs them as a graph — with parallelism, bounded re-runs, cross-node
12
+ jump-back, telemetry, and optional typed output. The execution backend
13
+ (in-process default / opt-in Prefect) and the agent runtime (opencode / Claude
14
+ Code / …) are both pluggable.
15
+
16
+ ### The three usage tiers (high level → low level)
17
+
18
+ - **Tier 3 — declarative**: declare `Node`s, call `build_flow` → a runnable flow
19
+ callable that dispatches execution to the selected backend. `agent_node` builds
20
+ a node that runs one agent in one call.
21
+ - **Tier 2 — primitives in your own flow**: call `run_agent` as the leaf of a
22
+ hand-written flow (a consumer may hand-write a Prefect flow around it — the toy
23
+ example does).
24
+ - **Tier 1 — engine core**: `run_agent` spawns + liveness-supervises + kills +
25
+ reads the control sidecar. Runtime-agnostic; no Prefect.
26
+
27
+ The dependency direction is strictly downward: **Tier 3 (`engine.py`) must not
28
+ import Tier 1** (`core.agent_runtime`/`runners`) — they meet only through a
29
+ node's `run` callable. `batteries.py` is the single module allowed to bridge
30
+ both.
31
+
32
+ ## Project Structure
33
+
34
+ ```
35
+ src/agent_flow/
36
+ __init__.py # Public API exports (keep in sync with what ships)
37
+ engine.py # Node / RunContext / build_flow / plan_groups / interpret / _walk (Tier 3)
38
+ batteries.py # agent_node — one-call node (bridges engine + run_agent)
39
+ gates.py # Directive (Continue/Restart/GoTo/Stop) + GateContext + ready gates
40
+ run_config.py # RunConfig (pydantic-settings) / build_run_config / get_settings lifecycle
41
+ run_context.py # RunContextService — open domain params + exports
42
+ preflight.py # runtime pre-flight checks (opencode/agent_dir/prefect) -> Check results
43
+ utils.py # resolve_run_dir / default_temp_base / require_extra (pure top-level leaf)
44
+ core/ # Tier-1 primitives, GUARANTEED backend-free (run_agent,
45
+ # control protocol, result-schema, context ingestion, env)
46
+ runners/ # agent-runtime seam (AgentRunner Protocol) + get_runner registry
47
+ backends/ # execution seam (FlowBackend ABC) + get_backend;
48
+ # inprocess default, prefect opt-in (DEFAULT_BACKEND="inprocess")
49
+ cli/ # run_cli + display helpers (typer/rich, opt-in [cli] extra)
50
+ examples/
51
+ toy_pipeline/ # Tier-2 demo (hand-written flow) + its .opencode/agent/*.md
52
+ tech_assessment/ # Tier-3 demo (declared graph) + its .opencode/agent/*.md
53
+ docs/
54
+ usage/ # consumer OKF bundle (getting-started, writing-agents, recipes)
55
+ design/orchestrator/ # design OKF bundle (one concept per file; start at index.md)
56
+ deploy/ # docker-compose (Prefect server + Postgres) for persistent mode
57
+ ```
58
+
59
+ ## Running commands (full output)
60
+
61
+ When running a command whose output matters, capture and read the FULL output —
62
+ do not truncate with `tail`, `head`, `grep`, or similar. Truncation hides errors,
63
+ stack traces, and warnings that appear outside the visible window. Prefer piping
64
+ through `tee` to a file and reading the whole file:
65
+
66
+ ```bash
67
+ some-command 2>&1 | tee /tmp/out.log # then read /tmp/out.log in full
68
+ ```
69
+
70
+ This is especially important for `task fct`, the examples, and any run that can
71
+ fail partway — the interesting line is rarely the last one.
72
+
73
+ ## Build & Test
74
+
75
+ House-standard task names (same across petrarca repos):
76
+
77
+ ```bash
78
+ task setup # create the venv
79
+ task install # editable install with dev tools
80
+ task fct # format + check (lint) + test — run before committing
81
+ task format # ruff format
82
+ task check # ruff check --fix
83
+ task verify # CI gate: lint + format check, read-only
84
+ task test # unit tests (fast)
85
+ task test:unit # unit tests only
86
+ task test:integration # integration (mock subprocess)
87
+ task test:all # unit + integration
88
+ task test:opencode # opt-in real-opencode e2e (needs opencode; run OUTSIDE an opencode session)
89
+ task build # build sdist + wheel
90
+ task rebuild:all # clean + install + format + check + test:all + build
91
+ task clean # remove build artifacts and caches
92
+ task pre-commit:install # install git pre-commit + pre-push hooks
93
+ task pre-commit:update # update pinned hook versions
94
+ task pre-commit:run # run all hooks against the tree
95
+ ```
96
+
97
+ Run the examples:
98
+
99
+ ```bash
100
+ task example:toy:mock TOPIC="Ports and Adapters"
101
+ task example:tech:mock PRODUCT=my-product
102
+ task example:tech PRODUCT=my-product RUNTIME=opencode SHOW_EVENTS=--show-events
103
+ ```
104
+
105
+ > Real-opencode runs must start from a normal shell **outside** an opencode
106
+ > session (a nested opencode raises `UnknownError`).
107
+
108
+ ## Core Concepts (do not violate)
109
+
110
+ ### The control-file contract
111
+
112
+ An agent signals completion by writing a JSON **control sidecar** — the SOLE
113
+ verdict. The library injects the protocol into the prompt
114
+ (`build_control_preamble`); agent `.md` files carry only domain instructions.
115
+
116
+ - **Envelope (engine reads):** `status` (`ok`/`verified`/`error`), `agent`,
117
+ `reason`, and `rerun_required` (a flow-control signal a gate consumes).
118
+ - **Payload (only gates/consumers read):** `result` — free-form dict. The engine
119
+ never looks inside.
120
+ - **No `artifact` field** — what an agent produces is expressed in the files it
121
+ was told to write, not reported back.
122
+ - **No sidecar → error.** The engine never inspects artifacts to guess success.
123
+
124
+ ### Two directories (never conflate)
125
+
126
+ - **`run_dir`** — where control sidecars + relative artifact paths resolve. NOT a
127
+ cwd. Unset → a fresh temp dir under `<temp>/agent-flow/` (ephemeral; pass an
128
+ explicit `run_dir` for output you keep). Resolved once per run via
129
+ `utils.resolve_run_dir`.
130
+ - **`agent_dir`** — where agent DEFINITIONS live (opencode `--dir`); becomes the
131
+ subprocess cwd. Global default via `build_flow(agent_dir=)`, per-node override
132
+ via `agent_node(agent_dir=)`.
133
+
134
+ ### Gates are the consumer's optional hook
135
+
136
+ A gate `(GateContext) -> Directive` decides flow control AFTER an agent runs. The
137
+ engine never auto-fails on schema/artifact issues — a gate does. A verifier is
138
+ NOT a library concept: it is just another node that `depends_on` its subject and
139
+ returns `GoTo(subject)`.
140
+
141
+ ### Typed output
142
+
143
+ `result_schema` is an opt-in convenience. `ctx.result["result"]` is always the
144
+ dict (validated if a schema was attached). `ctx.result["_result_obj"]` is a
145
+ Pydantic model instance ONLY when a `PydanticSchema` was used, else `None` (a
146
+ dict schema / no schema add no new object).
147
+
148
+ ### The input plane (prompt composition order)
149
+
150
+ `[control protocol] [run-wide context] [run-wide brief] [per-node context]
151
+ [per-node instructions] [work order]`. "Context" = FILE CONTENT ingested by the
152
+ library (the fix for "agents don't read the rules"); "instructions" = inline
153
+ text. Any `pipeline(**params)` key is a `{name}` template usable in
154
+ inputs/context/paths. To hand a value TO the agent, put it in `inputs`.
155
+
156
+ ## Code Quality
157
+
158
+ - Ruff `E, F, B, I, C90`, line length **150**, McCabe max-complexity **10**.
159
+ - No bare `except Exception`; catch concrete types. `except A, B:` (no `as`) is
160
+ valid Python 3.14 (PEP 758) — do not flag it.
161
+ - Dependencies are a lean core plus opt-in extras. Core (always installed):
162
+ pydantic, pydantic-settings, pyyaml, jsonschema, python-dotenv — enough to
163
+ declare a pipeline and run it on the default InProcessBackend. The heavy pieces are
164
+ extras matching the runtime seams: `[prefect]` (the opt-in PrefectBackend) and
165
+ `[cli]` (typer + rich for `run_cli` / display); `[all]` is both, `[dev]` adds
166
+ the tooling. An optional dep is lazy-imported at its entry point only — prefect
167
+ inside `backends/prefect.py`, rich/typer inside `cli/` — guarded by
168
+ `utils.require_extra(...)` so a missing extra fails with an actionable
169
+ "install agent-flow[...]" message.
170
+ - When adding a public symbol, export it in `src/agent_flow/__init__.py` and keep
171
+ the module-docstring "Public API" example current.
172
+
173
+ ## Git Conventions
174
+
175
+ - Commit prefixes: `feat:`, `fix:`, `refactor:`, `chore:`, `docs:`, `test:`.
176
+ - Short messages, max ~two sentences per point.
177
+ - **Run `task fct` (format + check + test) before every commit** and make sure it
178
+ passes. The pre-commit hook enforces this, but run it yourself first — never
179
+ commit code that has not passed `task fct`.
180
+ - **Never commit or push implicitly.** Do not run any git write operation
181
+ (`commit`, `push`, `merge`, `rebase`, `tag`, `reset --hard`, etc.) unless the
182
+ user has explicitly instructed it for that specific action. Do not chain a
183
+ commit/push onto another task on your own initiative. When in doubt, stop and
184
+ ask. Read-only git (`status`, `log`, `diff`) is fine without asking.
185
+ - `main` is the default branch. Do not commit `work*`, `.venv`, `.env`, caches,
186
+ or `node_modules` (all gitignored).
187
+
188
+ ## Documentation
189
+
190
+ Docs are OKF bundles (`docs/usage/`, `docs/design/orchestrator/`) — every file
191
+ has a `type` frontmatter field. When you change behavior, update the matching
192
+ concept doc and verify code snippets run. The README covers install + the three
193
+ tiers + running the examples.
@@ -0,0 +1,121 @@
1
+ # Contributing to agent-flow
2
+
3
+ Thank you for considering contributing to agent-flow! This document outlines the
4
+ process for contributing and the conventions that keep the project consistent.
5
+
6
+ ## Code of Conduct
7
+
8
+ By participating in this project, you agree to maintain a respectful and
9
+ inclusive environment for everyone.
10
+
11
+ ## Getting Started
12
+
13
+ ### Prerequisites
14
+
15
+ - Python 3.14+
16
+ - [`uv`](https://docs.astral.sh/uv/) package manager
17
+ - [`task`](https://taskfile.dev/) (go-task)
18
+ - For real (non-mock) runs: `opencode` on `PATH`, configured with model access
19
+
20
+ ### Setting up the development environment
21
+
22
+ ```bash
23
+ git clone <your-fork-url>
24
+ cd agent-flow
25
+ task install # editable install with dev tools (ruff, pytest, pydantic, jsonschema, typer, rich, pyyaml)
26
+ ```
27
+
28
+ ## Development workflow
29
+
30
+ ### Branch naming
31
+
32
+ Use descriptive branch names with prefixes:
33
+
34
+ - `feat/` — new features
35
+ - `fix/` — bug fixes
36
+ - `docs/` — documentation changes
37
+ - `refactor/` — code refactoring
38
+ - `test/` — tests only
39
+
40
+ Example: `feat/claude-code-runner`
41
+
42
+ ### Coding standards
43
+
44
+ - Ruff for linting and formatting, rules `E, F, B, I, C90`, line length **150**.
45
+ - McCabe max complexity **10** — refactor complex functions into helpers.
46
+ - Type-annotate public functions.
47
+ - No bare `except Exception` — catch concrete types (note: `except A, B:` without
48
+ `as` is valid Python 3.14 per PEP 758; do not "fix" it to parentheses).
49
+ - Keep the **core** dependency-light. Core deps (always installed): `pydantic`,
50
+ `pydantic-settings`, `pyyaml`, `jsonschema`, `python-dotenv`. Optional extras:
51
+ `[prefect]` (the Prefect backend) and `[cli]` (`typer` + `rich`). An optional
52
+ dep must be **lazy-imported at its entry point**, never at module-import time —
53
+ `prefect` only inside `backends/prefect.py`, `rich`/`typer` only inside `cli/`.
54
+ Guard the entry-point import with `utils.require_extra(...)` so a missing extra
55
+ fails with an actionable "install agent-flow[...]" message. The
56
+ `test_prefect_isolation` guard proves core + runners + InProcessBackend import and
57
+ run with `prefect` blocked.
58
+ - Respect the layering: the engine (Tier 3) must not import the runtime core
59
+ (Tier 1); they meet only through a node's `run` callable (`batteries` is the
60
+ one bridge). See `docs/design/orchestrator/index.md`.
61
+
62
+ ### Testing
63
+
64
+ ```bash
65
+ task test # unit tests (fast, no subprocess)
66
+ task test:all # unit + integration (mock subprocess; opencode e2e skipped)
67
+ task test:opencode # opt-in real-opencode e2e (needs opencode + creds; run OUTSIDE an opencode session)
68
+ ```
69
+
70
+ Run real-opencode examples/e2e from a normal shell **outside** an opencode
71
+ session — a nested opencode raises `UnknownError`.
72
+
73
+ ### The local loop
74
+
75
+ ```bash
76
+ task fct # format + check (lint) + test — run before every commit
77
+ task verify # CI gate: lint + format check, read-only (no fixes)
78
+ ```
79
+
80
+ ## Documentation
81
+
82
+ Design docs and consumer docs are [OKF](https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md)
83
+ bundles under `docs/`:
84
+
85
+ - `docs/usage/` — task-oriented consumer guides (start at `index.md`)
86
+ - `docs/design/orchestrator/` — architecture + one concept per file
87
+
88
+ When you change behavior, update the relevant doc and keep every OKF file's
89
+ `type` frontmatter intact. Verify code snippets actually run.
90
+
91
+ ## Pull request process
92
+
93
+ 1. Update docs and the README for any behavior/API change.
94
+ 2. Run `task fct` — lint, format, and tests must pass.
95
+ 3. Submit a PR with a clear description of the change.
96
+ 4. Address review feedback.
97
+
98
+ ## Commit messages
99
+
100
+ Short, clear, category-prefixed (conventional-commits style):
101
+
102
+ ```
103
+ <type>(<optional scope>): <description>
104
+ ```
105
+
106
+ Types: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`.
107
+ Example: `feat(cli): add --config run-file support`.
108
+
109
+ ## Reporting bugs
110
+
111
+ Include: a clear title, steps to reproduce, expected vs. actual behavior, and
112
+ environment details (OS, Python version, opencode version if relevant).
113
+
114
+ ## Feature requests
115
+
116
+ Provide a clear description, the motivation, and any implementation thoughts.
117
+
118
+ ## License
119
+
120
+ By contributing, you agree that your contributions will be licensed under the
121
+ Apache License 2.0 (see `LICENSE`).