fdsx 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 (184) hide show
  1. fdsx-0.1.0/.github/workflows/publish.yml +83 -0
  2. fdsx-0.1.0/.github/workflows/test.yml +53 -0
  3. fdsx-0.1.0/.pre-commit-config.yaml +7 -0
  4. fdsx-0.1.0/AGENTS.md +70 -0
  5. fdsx-0.1.0/CLAUDE.md +70 -0
  6. fdsx-0.1.0/LICENSE +21 -0
  7. fdsx-0.1.0/MANIFEST.in +19 -0
  8. fdsx-0.1.0/PKG-INFO +197 -0
  9. fdsx-0.1.0/README.md +159 -0
  10. fdsx-0.1.0/examples/workflows/plan-implement-review.yaml +203 -0
  11. fdsx-0.1.0/pyproject.toml +88 -0
  12. fdsx-0.1.0/setup.cfg +4 -0
  13. fdsx-0.1.0/src/fdsx/__init__.py +8 -0
  14. fdsx-0.1.0/src/fdsx/checkpoint/__init__.py +1 -0
  15. fdsx-0.1.0/src/fdsx/checkpoint/manager.py +337 -0
  16. fdsx-0.1.0/src/fdsx/cli/__init__.py +1 -0
  17. fdsx-0.1.0/src/fdsx/cli/main.py +366 -0
  18. fdsx-0.1.0/src/fdsx/core/__init__.py +1 -0
  19. fdsx-0.1.0/src/fdsx/core/batch.py +527 -0
  20. fdsx-0.1.0/src/fdsx/core/compiler/__init__.py +42 -0
  21. fdsx-0.1.0/src/fdsx/core/compiler/aggregation.py +45 -0
  22. fdsx-0.1.0/src/fdsx/core/compiler/compile.py +412 -0
  23. fdsx-0.1.0/src/fdsx/core/compiler/execution.py +163 -0
  24. fdsx-0.1.0/src/fdsx/core/compiler/helpers.py +218 -0
  25. fdsx-0.1.0/src/fdsx/core/compiler/nodes.py +283 -0
  26. fdsx-0.1.0/src/fdsx/core/compiler/parallel.py +306 -0
  27. fdsx-0.1.0/src/fdsx/core/compiler/routing.py +47 -0
  28. fdsx-0.1.0/src/fdsx/core/config.py +233 -0
  29. fdsx-0.1.0/src/fdsx/core/engine/__init__.py +41 -0
  30. fdsx-0.1.0/src/fdsx/core/engine/batch.py +126 -0
  31. fdsx-0.1.0/src/fdsx/core/engine/interrupts.py +59 -0
  32. fdsx-0.1.0/src/fdsx/core/engine/results.py +74 -0
  33. fdsx-0.1.0/src/fdsx/core/engine/resume.py +231 -0
  34. fdsx-0.1.0/src/fdsx/core/engine/run.py +189 -0
  35. fdsx-0.1.0/src/fdsx/core/engine/signals.py +156 -0
  36. fdsx-0.1.0/src/fdsx/core/engine/tasks_dir.py +415 -0
  37. fdsx-0.1.0/src/fdsx/core/engine/validate.py +24 -0
  38. fdsx-0.1.0/src/fdsx/core/extraction.py +253 -0
  39. fdsx-0.1.0/src/fdsx/core/graph_utils.py +52 -0
  40. fdsx-0.1.0/src/fdsx/core/hooks.py +200 -0
  41. fdsx-0.1.0/src/fdsx/core/loader.py +178 -0
  42. fdsx-0.1.0/src/fdsx/core/paths.py +40 -0
  43. fdsx-0.1.0/src/fdsx/core/selector.py +430 -0
  44. fdsx-0.1.0/src/fdsx/core/thread_id.py +8 -0
  45. fdsx-0.1.0/src/fdsx/core/variables.py +390 -0
  46. fdsx-0.1.0/src/fdsx/display/__init__.py +1 -0
  47. fdsx-0.1.0/src/fdsx/display/terminal.py +674 -0
  48. fdsx-0.1.0/src/fdsx/logging/__init__.py +6 -0
  49. fdsx-0.1.0/src/fdsx/logging/recorder.py +204 -0
  50. fdsx-0.1.0/src/fdsx/logging/stream_logger.py +99 -0
  51. fdsx-0.1.0/src/fdsx/models/__init__.py +1 -0
  52. fdsx-0.1.0/src/fdsx/models/flow.py +485 -0
  53. fdsx-0.1.0/src/fdsx/models/task.py +229 -0
  54. fdsx-0.1.0/src/fdsx/models/validators.py +30 -0
  55. fdsx-0.1.0/src/fdsx/notify/__init__.py +1 -0
  56. fdsx-0.1.0/src/fdsx/notify/webhook.py +72 -0
  57. fdsx-0.1.0/src/fdsx/providers/__init__.py +1 -0
  58. fdsx-0.1.0/src/fdsx/providers/base.py +381 -0
  59. fdsx-0.1.0/src/fdsx/providers/claude.py +294 -0
  60. fdsx-0.1.0/src/fdsx/providers/codex.py +236 -0
  61. fdsx-0.1.0/src/fdsx/providers/opencode.py +96 -0
  62. fdsx-0.1.0/src/fdsx/providers/system.py +50 -0
  63. fdsx-0.1.0/src/fdsx.egg-info/PKG-INFO +197 -0
  64. fdsx-0.1.0/src/fdsx.egg-info/SOURCES.txt +182 -0
  65. fdsx-0.1.0/src/fdsx.egg-info/dependency_links.txt +1 -0
  66. fdsx-0.1.0/src/fdsx.egg-info/entry_points.txt +2 -0
  67. fdsx-0.1.0/src/fdsx.egg-info/requires.txt +15 -0
  68. fdsx-0.1.0/src/fdsx.egg-info/top_level.txt +1 -0
  69. fdsx-0.1.0/tests/__init__.py +5 -0
  70. fdsx-0.1.0/tests/conftest.py +7 -0
  71. fdsx-0.1.0/tests/e2e/__init__.py +1 -0
  72. fdsx-0.1.0/tests/e2e/cli_test_utils.py +43 -0
  73. fdsx-0.1.0/tests/e2e/conftest.py +1 -0
  74. fdsx-0.1.0/tests/e2e/test_batch_backward_compat.py +73 -0
  75. fdsx-0.1.0/tests/e2e/test_batch_edge_cases.py +121 -0
  76. fdsx-0.1.0/tests/e2e/test_batch_error_messages.py +53 -0
  77. fdsx-0.1.0/tests/e2e/test_batch_full_pipeline.py +471 -0
  78. fdsx-0.1.0/tests/e2e/test_cli_batch_split.py +277 -0
  79. fdsx-0.1.0/tests/e2e/test_cli_batch_tasks.py +114 -0
  80. fdsx-0.1.0/tests/e2e/test_cli_flow_types.py +49 -0
  81. fdsx-0.1.0/tests/e2e/test_cli_signal_handling.py +211 -0
  82. fdsx-0.1.0/tests/e2e/test_cli_thread_id.py +106 -0
  83. fdsx-0.1.0/tests/e2e/test_cli_validation_and_run.py +50 -0
  84. fdsx-0.1.0/tests/e2e/test_cli_wait_and_resume.py +191 -0
  85. fdsx-0.1.0/tests/e2e/test_cli_workflow_name.py +24 -0
  86. fdsx-0.1.0/tests/fixtures/batch_flow.yaml +19 -0
  87. fdsx-0.1.0/tests/fixtures/checkpoint_flow.yaml +29 -0
  88. fdsx-0.1.0/tests/fixtures/choice_flow.yaml +46 -0
  89. fdsx-0.1.0/tests/fixtures/choice_flow_default.yaml +46 -0
  90. fdsx-0.1.0/tests/fixtures/claude_stream.ndjson +10 -0
  91. fdsx-0.1.0/tests/fixtures/codex_stream.jsonl +12 -0
  92. fdsx-0.1.0/tests/fixtures/extraction_flow.yaml +51 -0
  93. fdsx-0.1.0/tests/fixtures/input_flow.yaml +12 -0
  94. fdsx-0.1.0/tests/fixtures/invalid_flows/bad_next_ref.yaml +12 -0
  95. fdsx-0.1.0/tests/fixtures/invalid_flows/missing_start_at.yaml +12 -0
  96. fdsx-0.1.0/tests/fixtures/invalid_flows/mutual_exclusive.yaml +14 -0
  97. fdsx-0.1.0/tests/fixtures/json_codeblock_extraction_flow.yaml +52 -0
  98. fdsx-0.1.0/tests/fixtures/json_extraction_flow.yaml +51 -0
  99. fdsx-0.1.0/tests/fixtures/loop_flow.yaml +42 -0
  100. fdsx-0.1.0/tests/fixtures/max_iterations_flow.yaml +36 -0
  101. fdsx-0.1.0/tests/fixtures/max_iterations_wait_flow.yaml +38 -0
  102. fdsx-0.1.0/tests/fixtures/parallel_min_success.yaml +28 -0
  103. fdsx-0.1.0/tests/fixtures/parallel_review.yaml +80 -0
  104. fdsx-0.1.0/tests/fixtures/prompt_file_test/flow.yaml +13 -0
  105. fdsx-0.1.0/tests/fixtures/prompt_file_test/prompt.txt +1 -0
  106. fdsx-0.1.0/tests/fixtures/regex_extraction_flow.yaml +51 -0
  107. fdsx-0.1.0/tests/fixtures/sample_tasks.md +3 -0
  108. fdsx-0.1.0/tests/fixtures/simple_flow.yaml +26 -0
  109. fdsx-0.1.0/tests/fixtures/wait_approval.yaml +56 -0
  110. fdsx-0.1.0/tests/fixtures/wait_resume_flow.yaml +56 -0
  111. fdsx-0.1.0/tests/fixtures/wait_webhook.yaml +60 -0
  112. fdsx-0.1.0/tests/fixtures/workflows_name_display/alpha.yaml +12 -0
  113. fdsx-0.1.0/tests/fixtures/workflows_name_display/beta/workflow.yaml +12 -0
  114. fdsx-0.1.0/tests/fixtures/workflows_name_display/gamma.yaml +12 -0
  115. fdsx-0.1.0/tests/integration/__init__.py +1 -0
  116. fdsx-0.1.0/tests/integration/test_auto_select.py +223 -0
  117. fdsx-0.1.0/tests/integration/test_checkpoint_resume.py +282 -0
  118. fdsx-0.1.0/tests/integration/test_choice_flow.py +45 -0
  119. fdsx-0.1.0/tests/integration/test_claude_streaming.py +185 -0
  120. fdsx-0.1.0/tests/integration/test_codex_completion.py +78 -0
  121. fdsx-0.1.0/tests/integration/test_codex_streaming.py +202 -0
  122. fdsx-0.1.0/tests/integration/test_extraction_flow.py +100 -0
  123. fdsx-0.1.0/tests/integration/test_hook_streaming_interaction.py +667 -0
  124. fdsx-0.1.0/tests/integration/test_hooks_integration.py +1042 -0
  125. fdsx-0.1.0/tests/integration/test_inactivity_timeout.py +261 -0
  126. fdsx-0.1.0/tests/integration/test_iteration_logs.py +100 -0
  127. fdsx-0.1.0/tests/integration/test_large_command.py +79 -0
  128. fdsx-0.1.0/tests/integration/test_linear_flow.py +41 -0
  129. fdsx-0.1.0/tests/integration/test_lock_atomicity.py +131 -0
  130. fdsx-0.1.0/tests/integration/test_loop_enforcement.py +16 -0
  131. fdsx-0.1.0/tests/integration/test_loop_flow.py +55 -0
  132. fdsx-0.1.0/tests/integration/test_max_iterations_flow.py +136 -0
  133. fdsx-0.1.0/tests/integration/test_parallel_flow.py +216 -0
  134. fdsx-0.1.0/tests/integration/test_provider_options.py +359 -0
  135. fdsx-0.1.0/tests/integration/test_quiet_mode.py +104 -0
  136. fdsx-0.1.0/tests/integration/test_result_file.py +174 -0
  137. fdsx-0.1.0/tests/integration/test_resume_interrupt.py +272 -0
  138. fdsx-0.1.0/tests/integration/test_scenario_flows.py +358 -0
  139. fdsx-0.1.0/tests/integration/test_split.py +613 -0
  140. fdsx-0.1.0/tests/integration/test_split_spinner.py +290 -0
  141. fdsx-0.1.0/tests/integration/test_subprocess_completion.py +270 -0
  142. fdsx-0.1.0/tests/integration/test_tasks_dir.py +1023 -0
  143. fdsx-0.1.0/tests/integration/test_wait_resume.py +107 -0
  144. fdsx-0.1.0/tests/integration/test_workflow_persistence.py +225 -0
  145. fdsx-0.1.0/tests/unit/__init__.py +1 -0
  146. fdsx-0.1.0/tests/unit/test_aggregation.py +328 -0
  147. fdsx-0.1.0/tests/unit/test_backoff.py +268 -0
  148. fdsx-0.1.0/tests/unit/test_batch.py +826 -0
  149. fdsx-0.1.0/tests/unit/test_checkpoint.py +252 -0
  150. fdsx-0.1.0/tests/unit/test_claude_stream_parser.py +610 -0
  151. fdsx-0.1.0/tests/unit/test_cli_version.py +18 -0
  152. fdsx-0.1.0/tests/unit/test_codex_stream_parser.py +591 -0
  153. fdsx-0.1.0/tests/unit/test_compiler_merge.py +283 -0
  154. fdsx-0.1.0/tests/unit/test_config.py +595 -0
  155. fdsx-0.1.0/tests/unit/test_engine.py +397 -0
  156. fdsx-0.1.0/tests/unit/test_execution.py +447 -0
  157. fdsx-0.1.0/tests/unit/test_extraction.py +475 -0
  158. fdsx-0.1.0/tests/unit/test_graph_utils.py +158 -0
  159. fdsx-0.1.0/tests/unit/test_hooks.py +624 -0
  160. fdsx-0.1.0/tests/unit/test_loader.py +264 -0
  161. fdsx-0.1.0/tests/unit/test_max_iterations.py +189 -0
  162. fdsx-0.1.0/tests/unit/test_models.py +479 -0
  163. fdsx-0.1.0/tests/unit/test_paths.py +47 -0
  164. fdsx-0.1.0/tests/unit/test_prompt_file.py +152 -0
  165. fdsx-0.1.0/tests/unit/test_provider_options.py +360 -0
  166. fdsx-0.1.0/tests/unit/test_provider_stdin_fallback.py +173 -0
  167. fdsx-0.1.0/tests/unit/test_recorder.py +508 -0
  168. fdsx-0.1.0/tests/unit/test_result_file.py +647 -0
  169. fdsx-0.1.0/tests/unit/test_resume_display.py +193 -0
  170. fdsx-0.1.0/tests/unit/test_selector.py +899 -0
  171. fdsx-0.1.0/tests/unit/test_selector_name.py +155 -0
  172. fdsx-0.1.0/tests/unit/test_signal_handler.py +347 -0
  173. fdsx-0.1.0/tests/unit/test_spinner.py +339 -0
  174. fdsx-0.1.0/tests/unit/test_stream_logger.py +331 -0
  175. fdsx-0.1.0/tests/unit/test_stream_logger_iteration.py +167 -0
  176. fdsx-0.1.0/tests/unit/test_subprocess_completion.py +710 -0
  177. fdsx-0.1.0/tests/unit/test_subprocess_realtime_streaming.py +105 -0
  178. fdsx-0.1.0/tests/unit/test_subprocess_stdin.py +206 -0
  179. fdsx-0.1.0/tests/unit/test_task_model.py +621 -0
  180. fdsx-0.1.0/tests/unit/test_terminal.py +574 -0
  181. fdsx-0.1.0/tests/unit/test_thread_id.py +54 -0
  182. fdsx-0.1.0/tests/unit/test_variables.py +789 -0
  183. fdsx-0.1.0/tests/unit/test_webhook.py +255 -0
  184. fdsx-0.1.0/tests/unit/test_workflow_cui.py +350 -0
@@ -0,0 +1,83 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ testpypi:
10
+ description: "Publish to TestPyPI"
11
+ required: false
12
+ default: false
13
+ type: boolean
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ jobs:
19
+ test:
20
+ name: test
21
+ uses: ./.github/workflows/test.yml
22
+
23
+ build:
24
+ name: build
25
+ needs: test
26
+ runs-on: ubuntu-latest
27
+ steps:
28
+ - uses: actions/checkout@v4
29
+ with:
30
+ fetch-depth: 0
31
+ - uses: actions/setup-python@v5
32
+ with:
33
+ python-version: "3.12"
34
+ - name: install build
35
+ run: pip install build
36
+ - name: build
37
+ run: python -m build
38
+ - name: upload artifact
39
+ uses: actions/upload-artifact@v4
40
+ with:
41
+ name: dist
42
+ path: dist/
43
+
44
+ publish-to-testpypi:
45
+ name: publish-to-testpypi
46
+ needs: build
47
+ runs-on: ubuntu-latest
48
+ if: github.event_name == 'workflow_dispatch' && inputs.testpypi
49
+ environment:
50
+ name: testpypi
51
+ url: https://test.pypi.org/project/fdsx/
52
+ permissions:
53
+ id-token: write
54
+ steps:
55
+ - name: download artifact
56
+ uses: actions/download-artifact@v4
57
+ with:
58
+ name: dist
59
+ path: dist/
60
+ - name: publish to TestPyPI
61
+ uses: pypa/gh-action-pypi-publish@release/v1
62
+ with:
63
+ repository-url: https://test.pypi.org/legacy/
64
+ skip-existing: true
65
+
66
+ publish-to-pypi:
67
+ name: publish-to-pypi
68
+ needs: build
69
+ runs-on: ubuntu-latest
70
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
71
+ environment:
72
+ name: pypi
73
+ url: https://pypi.org/project/fdsx/
74
+ permissions:
75
+ id-token: write
76
+ steps:
77
+ - name: download artifact
78
+ uses: actions/download-artifact@v4
79
+ with:
80
+ name: dist
81
+ path: dist/
82
+ - name: publish to PyPI
83
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,53 @@
1
+ name: test
2
+
3
+ on:
4
+ pull_request:
5
+ workflow_call:
6
+
7
+ permissions:
8
+ contents: read
9
+
10
+ jobs:
11
+ lint:
12
+ name: lint
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ - uses: actions/setup-python@v5
17
+ with:
18
+ python-version: "3.12"
19
+ - name: install ruff
20
+ run: pip install ruff
21
+ - name: ruff check
22
+ run: ruff check .
23
+ - name: ruff format check
24
+ run: ruff format --check .
25
+
26
+ test:
27
+ name: test
28
+ runs-on: ubuntu-latest
29
+ strategy:
30
+ fail-fast: false
31
+ matrix:
32
+ python-version:
33
+ - "3.10"
34
+ - "3.11"
35
+ - "3.12"
36
+ - "3.13"
37
+ steps:
38
+ - uses: actions/checkout@v4
39
+ with:
40
+ fetch-depth: 0
41
+ - uses: actions/setup-python@v5
42
+ with:
43
+ python-version: ${{ matrix.python-version }}
44
+ - name: install dev deps
45
+ run: pip install -e ".[dev]"
46
+ - name: ruff check
47
+ run: ruff check .
48
+ - name: ruff format check
49
+ run: ruff format --check .
50
+ - name: mypy
51
+ run: mypy src/fdsx
52
+ - name: pytest
53
+ run: pytest
@@ -0,0 +1,7 @@
1
+ repos:
2
+ - repo: https://github.com/astral-sh/ruff-pre-commit
3
+ rev: v0.11.4
4
+ hooks:
5
+ - id: ruff
6
+ args: [--fix]
7
+ - id: ruff-format
fdsx-0.1.0/AGENTS.md ADDED
@@ -0,0 +1,70 @@
1
+ # Agent Instructions
2
+
3
+ ## Testing Guidelines
4
+
5
+ ### Test Trophy Strategy
6
+
7
+ This project follows the test trophy pattern. Tests are organized into three layers:
8
+
9
+ #### Directory Structure
10
+ - `tests/unit/` — Unit tests for complex pure logic
11
+ - `tests/integration/` — Integration tests (primary confidence layer)
12
+ - `tests/e2e/` — CLI end-to-end tests (thinnest layer)
13
+
14
+ #### What belongs at each level
15
+
16
+ **Unit tests** (`tests/unit/`):
17
+ - Complex parsing logic (YAML parsing, JSONPath resolution, variable substitution)
18
+ - State transition rules and algorithms
19
+ - Pure functions with non-trivial logic
20
+ - NOT: Pydantic model field assignments, default value checks, isinstance checks
21
+
22
+ **Integration tests** (`tests/integration/`):
23
+ - Complete workflow execution via `engine.run_flow()`
24
+ - Feature-centered tests: each file answers "Does feature X work correctly?"
25
+ - Checkpoint persistence and recovery
26
+ - State variable mutations and result paths
27
+ - Tests using `CliRunner` for testing CLI behavior with mocked internals
28
+
29
+ **E2E tests** (`tests/e2e/`):
30
+ - CLI surface tests via `run_fdsx()` subprocess calls
31
+ - Exit codes, stderr/stdout format validation
32
+ - CLI argument parsing and mutual exclusion
33
+ - Signal handling
34
+
35
+ #### Anti-patterns to avoid
36
+
37
+ - **Trivial field assertion tests**: Don't test that `TaskState(type="task").type == "task"`. Pydantic guarantees this.
38
+ - **isinstance checks**: Don't test `isinstance(generate_thread_id(), str)`. The type system handles this.
39
+ - **Default value tests**: Don't test that `ClaudeOptions().permission_mode is None`. This is framework behavior.
40
+ - **Unnecessary real-time waits**: Mock `time.sleep` for in-process delays. Minimize subprocess sleep durations.
41
+ - **Writing artifacts to project root**: Tests must never create `.fdsx/` artifacts in the project root. Always use `monkeypatch.chdir(tmp_path)` or `cwd=tmp_dir` for subprocess tests.
42
+
43
+ #### Naming conventions
44
+
45
+ - Test files: `test_<feature>.py` (never `test_phase1.py` or `test_e2e_phase2.py`)
46
+ - Test functions: `test_<scenario>_<expected_outcome>`
47
+ - Test classes: `Test<Feature><Aspect>` (e.g., `TestCheckpointResume`, `TestChoiceStateValidation`)
48
+
49
+ #### Integration Test Feature-Centeredness Assessment
50
+
51
+ All integration tests are already feature-centered. No files need restructuring beyond the e2e moves. Each integration test file is organized around a specific feature:
52
+
53
+ - `test_checkpoint_resume.py` — checkpoint and resume behavior
54
+ - `test_choice_flow.py` — choice state routing
55
+ - `test_parallel_flow.py` — parallel execution
56
+ - `test_linear_flow.py` — linear workflow execution
57
+ - `test_loop_flow.py` — loop state behavior
58
+ - `test_extraction_flow.py` — data extraction
59
+ - `test_quiet_mode.py` — quiet mode flag
60
+ - `test_result_file.py` — result file output
61
+ - `test_resume_interrupt.py` — interrupted workflow recovery
62
+ - `test_split.py` — batch split behavior
63
+ - `test_tasks_dir.py` — tasks directory handling
64
+ - `test_auto_select.py` — auto-select logic
65
+ - `test_lock_atomicity.py` — lock file atomicity
66
+ - `test_workflow_persistence.py` — workflow state persistence
67
+ - `test_inactivity_timeout.py` — inactivity timeout handling
68
+ - `test_scenario_flows.py` — cross-cutting scenario flows
69
+
70
+ The integration test suite is well-organized around features (checkpoint, choice, parallel, loop, extraction, etc.) rather than implementation phases. No restructuring was required.
fdsx-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,70 @@
1
+ # Agent Instructions
2
+
3
+ ## Testing Guidelines
4
+
5
+ ### Test Trophy Strategy
6
+
7
+ This project follows the test trophy pattern. Tests are organized into three layers:
8
+
9
+ #### Directory Structure
10
+ - `tests/unit/` — Unit tests for complex pure logic
11
+ - `tests/integration/` — Integration tests (primary confidence layer)
12
+ - `tests/e2e/` — CLI end-to-end tests (thinnest layer)
13
+
14
+ #### What belongs at each level
15
+
16
+ **Unit tests** (`tests/unit/`):
17
+ - Complex parsing logic (YAML parsing, JSONPath resolution, variable substitution)
18
+ - State transition rules and algorithms
19
+ - Pure functions with non-trivial logic
20
+ - NOT: Pydantic model field assignments, default value checks, isinstance checks
21
+
22
+ **Integration tests** (`tests/integration/`):
23
+ - Complete workflow execution via `engine.run_flow()`
24
+ - Feature-centered tests: each file answers "Does feature X work correctly?"
25
+ - Checkpoint persistence and recovery
26
+ - State variable mutations and result paths
27
+ - Tests using `CliRunner` for testing CLI behavior with mocked internals
28
+
29
+ **E2E tests** (`tests/e2e/`):
30
+ - CLI surface tests via `run_fdsx()` subprocess calls
31
+ - Exit codes, stderr/stdout format validation
32
+ - CLI argument parsing and mutual exclusion
33
+ - Signal handling
34
+
35
+ #### Anti-patterns to avoid
36
+
37
+ - **Trivial field assertion tests**: Don't test that `TaskState(type="task").type == "task"`. Pydantic guarantees this.
38
+ - **isinstance checks**: Don't test `isinstance(generate_thread_id(), str)`. The type system handles this.
39
+ - **Default value tests**: Don't test that `ClaudeOptions().permission_mode is None`. This is framework behavior.
40
+ - **Unnecessary real-time waits**: Mock `time.sleep` for in-process delays. Minimize subprocess sleep durations.
41
+ - **Writing artifacts to project root**: Tests must never create `.fdsx/` artifacts in the project root. Always use `monkeypatch.chdir(tmp_path)` or `cwd=tmp_dir` for subprocess tests.
42
+
43
+ #### Naming conventions
44
+
45
+ - Test files: `test_<feature>.py` (never `test_phase1.py` or `test_e2e_phase2.py`)
46
+ - Test functions: `test_<scenario>_<expected_outcome>`
47
+ - Test classes: `Test<Feature><Aspect>` (e.g., `TestCheckpointResume`, `TestChoiceStateValidation`)
48
+
49
+ #### Integration Test Feature-Centeredness Assessment
50
+
51
+ All integration tests are already feature-centered. No files need restructuring beyond the e2e moves. Each integration test file is organized around a specific feature:
52
+
53
+ - `test_checkpoint_resume.py` — checkpoint and resume behavior
54
+ - `test_choice_flow.py` — choice state routing
55
+ - `test_parallel_flow.py` — parallel execution
56
+ - `test_linear_flow.py` — linear workflow execution
57
+ - `test_loop_flow.py` — loop state behavior
58
+ - `test_extraction_flow.py` — data extraction
59
+ - `test_quiet_mode.py` — quiet mode flag
60
+ - `test_result_file.py` — result file output
61
+ - `test_resume_interrupt.py` — interrupted workflow recovery
62
+ - `test_split.py` — batch split behavior
63
+ - `test_tasks_dir.py` — tasks directory handling
64
+ - `test_auto_select.py` — auto-select logic
65
+ - `test_lock_atomicity.py` — lock file atomicity
66
+ - `test_workflow_persistence.py` — workflow state persistence
67
+ - `test_inactivity_timeout.py` — inactivity timeout handling
68
+ - `test_scenario_flows.py` — cross-cutting scenario flows
69
+
70
+ The integration test suite is well-organized around features (checkpoint, choice, parallel, loop, extraction, etc.) rather than implementation phases. No restructuring was required.
fdsx-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kenfdev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
fdsx-0.1.0/MANIFEST.in ADDED
@@ -0,0 +1,19 @@
1
+ graft src
2
+ include pyproject.toml
3
+ include README.md
4
+ include LICENSE
5
+
6
+ prune .claude
7
+ prune .takt
8
+ prune .specify
9
+ prune .worktree
10
+ prune .fdsx
11
+ prune specs
12
+
13
+ exclude .gitignore
14
+ exclude .worktreeinclude
15
+ exclude docker-compose.yml
16
+ exclude uv.lock
17
+
18
+ global-exclude *.pyc
19
+ global-exclude __pycache__
fdsx-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: fdsx
3
+ Version: 0.1.0
4
+ Summary: Declarative AI agent workflow execution framework
5
+ Author: kenfdev
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/kenfdev/fdsx
8
+ Project-URL: Repository, https://github.com/kenfdev/fdsx
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Requires-Python: >=3.10
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: langgraph<2,>=1.0
24
+ Requires-Dist: langgraph-checkpoint-sqlite<5,>=3
25
+ Requires-Dist: pyyaml>=6
26
+ Requires-Dist: typer>=0.9
27
+ Requires-Dist: httpx>=0.27
28
+ Requires-Dist: structlog>=24
29
+ Requires-Dist: uuid-utils>=0.9
30
+ Provides-Extra: dev
31
+ Requires-Dist: pytest>=8; extra == "dev"
32
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
33
+ Requires-Dist: ruff>=0.4; extra == "dev"
34
+ Requires-Dist: mypy>=1.10; extra == "dev"
35
+ Requires-Dist: types-PyYAML>=6; extra == "dev"
36
+ Requires-Dist: pre-commit>=3; extra == "dev"
37
+ Dynamic: license-file
38
+
39
+ # fdsx — Flow-Driven Stateful eXecution
40
+
41
+ [![PyPI version](https://img.shields.io/pypi/v/fdsx.svg)](https://pypi.org/project/fdsx/)
42
+
43
+ A lightweight framework for building and executing complex AI agent workflows using declarative YAML definitions.
44
+
45
+ ## Overview
46
+
47
+ fdsx enables you to define AI agent workflows in YAML, combining the durability of LangGraph (checkpoint, interrupt, conditional routing) with the declarative structure of AWS Step Functions.
48
+
49
+ **Key features:**
50
+ - Declarative YAML-based workflow definition
51
+ - Stateful execution with checkpoint/resume
52
+ - Parallel execution with branch aggregation
53
+ - Batch task processing
54
+ - Multiple LLM provider support (Claude, OpenCode, and more)
55
+
56
+ ## Installation
57
+
58
+ ```bash
59
+ pip install fdsx
60
+ ```
61
+
62
+ Or with [uv](https://docs.astral.sh/uv/):
63
+
64
+ ```bash
65
+ uv tool install fdsx
66
+ ```
67
+
68
+ ## Quick Start
69
+
70
+ Create a simple YAML workflow file:
71
+
72
+ ```yaml
73
+ name: SimpleFlow
74
+ start_at: greet
75
+ version: "1.0"
76
+
77
+ states:
78
+ greet:
79
+ type: task
80
+ provider: system
81
+ command: "echo 'Hello from fdsx!'"
82
+ result_path: $.message
83
+ end: true
84
+ ```
85
+
86
+ Run it:
87
+
88
+ ```bash
89
+ fdsx run simple_flow.yaml
90
+ ```
91
+
92
+ ## Feature Overview
93
+
94
+ ### State Types
95
+ - **task** — Execute LLM or CLI commands
96
+ - **parallel** — Run multiple branches concurrently
97
+ - **choice** — Conditional routing based on variables
98
+ - **wait** — Pause for human approval or webhook callback
99
+ - **pass** — Pass-through state for data transformation
100
+
101
+ ### Parallel Execution
102
+ Define parallel branches that execute simultaneously with aggregation strategies (majority vote, all, any).
103
+
104
+ ### Checkpoint & Resume
105
+ Flows automatically persist state. Resume from interruption with:
106
+ ```bash
107
+ fdsx resume --thread-id <thread_id>
108
+ ```
109
+
110
+ ### Batch Tasks
111
+ Process multiple tasks in batch mode:
112
+ ```bash
113
+ fdsx run workflow.yaml --tasks tasks.md
114
+ ```
115
+
116
+ ### Structured Logging
117
+ All execution details are logged to `runs/<thread_id>.json`.
118
+
119
+ ### Provider Support
120
+ Use any CLI-based LLM provider: Claude, Codex, OpenCode, or system commands.
121
+
122
+ ## CLI Reference
123
+
124
+ | Command | Description |
125
+ |---------|-------------|
126
+ | `fdsx run <workflow.yaml>` | Execute a workflow |
127
+ | `fdsx run <workflow.yaml> --input key=value` | Pass input variables |
128
+ | `fdsx resume --thread-id <thread_id>` | Resume from checkpoint |
129
+ | `fdsx validate <workflow.yaml>` | Validate YAML syntax |
130
+ | `fdsx list` | List recent runs |
131
+
132
+ ## Example Workflow
133
+
134
+ ```yaml
135
+ name: Plan-Implement-Review Loop
136
+ start_at: plan
137
+ version: "1.0"
138
+ max_loop: 3
139
+
140
+ states:
141
+ plan:
142
+ type: task
143
+ provider: claude
144
+ model: claude-sonnet-4-6
145
+ prompt_template: |
146
+ You are a planning agent. Break down the following task into clear,
147
+ actionable implementation steps.
148
+
149
+ Task: {task}
150
+ result_path: $.plan
151
+ next: implement
152
+
153
+ implement:
154
+ type: task
155
+ provider: opencode
156
+ model: opencode/minimax-m2.5-free
157
+ prompt_template: |
158
+ You are an implementation agent. Follow this plan exactly.
159
+
160
+ Plan: {plan}
161
+ result_path: $.implementation
162
+ next: review
163
+
164
+ review:
165
+ type: task
166
+ provider: codex
167
+ model: gpt-5.4
168
+ prompt_template: |
169
+ Review the implementation against the plan.
170
+
171
+ Plan: {plan}
172
+ Implementation: {implementation}
173
+ result_path: $.review
174
+ next: check_review
175
+
176
+ check_review:
177
+ type: choice
178
+ choices:
179
+ - variable: $.review
180
+ operator: contains
181
+ value: "APPROVED"
182
+ next: done
183
+ default: implement
184
+
185
+ done:
186
+ type: pass
187
+ end: true
188
+ ```
189
+
190
+ Run this example:
191
+ ```bash
192
+ fdsx run examples/workflows/plan-implement-review.yaml --input task="Build a web calculator"
193
+ ```
194
+
195
+ ## License
196
+
197
+ MIT License.
fdsx-0.1.0/README.md ADDED
@@ -0,0 +1,159 @@
1
+ # fdsx — Flow-Driven Stateful eXecution
2
+
3
+ [![PyPI version](https://img.shields.io/pypi/v/fdsx.svg)](https://pypi.org/project/fdsx/)
4
+
5
+ A lightweight framework for building and executing complex AI agent workflows using declarative YAML definitions.
6
+
7
+ ## Overview
8
+
9
+ fdsx enables you to define AI agent workflows in YAML, combining the durability of LangGraph (checkpoint, interrupt, conditional routing) with the declarative structure of AWS Step Functions.
10
+
11
+ **Key features:**
12
+ - Declarative YAML-based workflow definition
13
+ - Stateful execution with checkpoint/resume
14
+ - Parallel execution with branch aggregation
15
+ - Batch task processing
16
+ - Multiple LLM provider support (Claude, OpenCode, and more)
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install fdsx
22
+ ```
23
+
24
+ Or with [uv](https://docs.astral.sh/uv/):
25
+
26
+ ```bash
27
+ uv tool install fdsx
28
+ ```
29
+
30
+ ## Quick Start
31
+
32
+ Create a simple YAML workflow file:
33
+
34
+ ```yaml
35
+ name: SimpleFlow
36
+ start_at: greet
37
+ version: "1.0"
38
+
39
+ states:
40
+ greet:
41
+ type: task
42
+ provider: system
43
+ command: "echo 'Hello from fdsx!'"
44
+ result_path: $.message
45
+ end: true
46
+ ```
47
+
48
+ Run it:
49
+
50
+ ```bash
51
+ fdsx run simple_flow.yaml
52
+ ```
53
+
54
+ ## Feature Overview
55
+
56
+ ### State Types
57
+ - **task** — Execute LLM or CLI commands
58
+ - **parallel** — Run multiple branches concurrently
59
+ - **choice** — Conditional routing based on variables
60
+ - **wait** — Pause for human approval or webhook callback
61
+ - **pass** — Pass-through state for data transformation
62
+
63
+ ### Parallel Execution
64
+ Define parallel branches that execute simultaneously with aggregation strategies (majority vote, all, any).
65
+
66
+ ### Checkpoint & Resume
67
+ Flows automatically persist state. Resume from interruption with:
68
+ ```bash
69
+ fdsx resume --thread-id <thread_id>
70
+ ```
71
+
72
+ ### Batch Tasks
73
+ Process multiple tasks in batch mode:
74
+ ```bash
75
+ fdsx run workflow.yaml --tasks tasks.md
76
+ ```
77
+
78
+ ### Structured Logging
79
+ All execution details are logged to `runs/<thread_id>.json`.
80
+
81
+ ### Provider Support
82
+ Use any CLI-based LLM provider: Claude, Codex, OpenCode, or system commands.
83
+
84
+ ## CLI Reference
85
+
86
+ | Command | Description |
87
+ |---------|-------------|
88
+ | `fdsx run <workflow.yaml>` | Execute a workflow |
89
+ | `fdsx run <workflow.yaml> --input key=value` | Pass input variables |
90
+ | `fdsx resume --thread-id <thread_id>` | Resume from checkpoint |
91
+ | `fdsx validate <workflow.yaml>` | Validate YAML syntax |
92
+ | `fdsx list` | List recent runs |
93
+
94
+ ## Example Workflow
95
+
96
+ ```yaml
97
+ name: Plan-Implement-Review Loop
98
+ start_at: plan
99
+ version: "1.0"
100
+ max_loop: 3
101
+
102
+ states:
103
+ plan:
104
+ type: task
105
+ provider: claude
106
+ model: claude-sonnet-4-6
107
+ prompt_template: |
108
+ You are a planning agent. Break down the following task into clear,
109
+ actionable implementation steps.
110
+
111
+ Task: {task}
112
+ result_path: $.plan
113
+ next: implement
114
+
115
+ implement:
116
+ type: task
117
+ provider: opencode
118
+ model: opencode/minimax-m2.5-free
119
+ prompt_template: |
120
+ You are an implementation agent. Follow this plan exactly.
121
+
122
+ Plan: {plan}
123
+ result_path: $.implementation
124
+ next: review
125
+
126
+ review:
127
+ type: task
128
+ provider: codex
129
+ model: gpt-5.4
130
+ prompt_template: |
131
+ Review the implementation against the plan.
132
+
133
+ Plan: {plan}
134
+ Implementation: {implementation}
135
+ result_path: $.review
136
+ next: check_review
137
+
138
+ check_review:
139
+ type: choice
140
+ choices:
141
+ - variable: $.review
142
+ operator: contains
143
+ value: "APPROVED"
144
+ next: done
145
+ default: implement
146
+
147
+ done:
148
+ type: pass
149
+ end: true
150
+ ```
151
+
152
+ Run this example:
153
+ ```bash
154
+ fdsx run examples/workflows/plan-implement-review.yaml --input task="Build a web calculator"
155
+ ```
156
+
157
+ ## License
158
+
159
+ MIT License.