fdsx 0.2.2__tar.gz → 0.2.3__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 (269) hide show
  1. {fdsx-0.2.2 → fdsx-0.2.3}/PKG-INFO +27 -7
  2. {fdsx-0.2.2 → fdsx-0.2.3}/README.md +27 -7
  3. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/data/skills/fdsx/SKILL.md +47 -6
  4. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/data/skills/fdsx/references/yaml-schema.md +76 -0
  5. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/PKG-INFO +27 -7
  6. {fdsx-0.2.2 → fdsx-0.2.3}/.github/dependabot.yml +0 -0
  7. {fdsx-0.2.2 → fdsx-0.2.3}/.github/workflows/publish.yml +0 -0
  8. {fdsx-0.2.2 → fdsx-0.2.3}/.github/workflows/test.yml +0 -0
  9. {fdsx-0.2.2 → fdsx-0.2.3}/.pre-commit-config.yaml +0 -0
  10. {fdsx-0.2.2 → fdsx-0.2.3}/AGENTS.md +0 -0
  11. {fdsx-0.2.2 → fdsx-0.2.3}/CLAUDE.md +0 -0
  12. {fdsx-0.2.2 → fdsx-0.2.3}/GEMINI.md +0 -0
  13. {fdsx-0.2.2 → fdsx-0.2.3}/LICENSE +0 -0
  14. {fdsx-0.2.2 → fdsx-0.2.3}/MANIFEST.in +0 -0
  15. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/README.md +0 -0
  16. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/analyze.md +0 -0
  17. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/collect_data.sh +0 -0
  18. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/research.md +0 -0
  19. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/workflow.yaml +0 -0
  20. {fdsx-0.2.2 → fdsx-0.2.3}/examples/self-improve/write_lessons.md +0 -0
  21. {fdsx-0.2.2 → fdsx-0.2.3}/pyproject.toml +0 -0
  22. {fdsx-0.2.2 → fdsx-0.2.3}/setup.cfg +0 -0
  23. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/__init__.py +0 -0
  24. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/checkpoint/__init__.py +0 -0
  25. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/checkpoint/manager.py +0 -0
  26. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/cli/__init__.py +0 -0
  27. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/cli/init_interactive.py +0 -0
  28. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/cli/main.py +0 -0
  29. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/__init__.py +0 -0
  30. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/batch.py +0 -0
  31. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/__init__.py +0 -0
  32. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/aggregation.py +0 -0
  33. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/compile.py +0 -0
  34. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/execution.py +0 -0
  35. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/helpers.py +0 -0
  36. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/map_iteration.py +0 -0
  37. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/nodes.py +0 -0
  38. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/parallel.py +0 -0
  39. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/compiler/routing.py +0 -0
  40. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/config.py +0 -0
  41. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/__init__.py +0 -0
  42. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/batch.py +0 -0
  43. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/interrupts.py +0 -0
  44. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/results.py +0 -0
  45. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/resume.py +0 -0
  46. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/run.py +0 -0
  47. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/signals.py +0 -0
  48. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/tasks_dir.py +0 -0
  49. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/engine/validate.py +0 -0
  50. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/extraction.py +0 -0
  51. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/graph_utils.py +0 -0
  52. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/hooks.py +0 -0
  53. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/init.py +0 -0
  54. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/loader.py +0 -0
  55. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/paths.py +0 -0
  56. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/profiles.py +0 -0
  57. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/selector.py +0 -0
  58. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/thread_id.py +0 -0
  59. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/core/variables.py +0 -0
  60. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/data/__init__.py +0 -0
  61. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/data/skills/__init__.py +0 -0
  62. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/display/__init__.py +0 -0
  63. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/display/terminal.py +0 -0
  64. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/__init__.py +0 -0
  65. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/__init__.py +0 -0
  66. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/finalize.md +0 -0
  67. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/fix.md +0 -0
  68. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/implement.md +0 -0
  69. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/plan.md +0 -0
  70. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/replan.md +0 -0
  71. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/review-code-quality.md +0 -0
  72. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/review-security.md +0 -0
  73. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/full-impl/workflow.yaml +0 -0
  74. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/README.md +0 -0
  75. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/analyze.md +0 -0
  76. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/collect_data.sh +0 -0
  77. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/research.md +0 -0
  78. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/workflow.yaml +0 -0
  79. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/self-improve/write_lessons.md +0 -0
  80. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/finalize.md +0 -0
  81. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/fix.md +0 -0
  82. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/implement.md +0 -0
  83. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/plan.md +0 -0
  84. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/replan.md +0 -0
  85. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/review-general.md +0 -0
  86. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/examples/workflows/simple-impl/workflow.yaml +0 -0
  87. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/logging/__init__.py +0 -0
  88. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/logging/recorder.py +0 -0
  89. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/logging/stream_logger.py +0 -0
  90. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/models/__init__.py +0 -0
  91. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/models/flow.py +0 -0
  92. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/models/init.py +0 -0
  93. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/models/task.py +0 -0
  94. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/models/validators.py +0 -0
  95. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/notify/__init__.py +0 -0
  96. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/notify/webhook.py +0 -0
  97. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/__init__.py +0 -0
  98. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/base.py +0 -0
  99. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/claude.py +0 -0
  100. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/codex.py +0 -0
  101. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/gemini.py +0 -0
  102. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/opencode.py +0 -0
  103. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/providers/system.py +0 -0
  104. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx/py.typed +0 -0
  105. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/SOURCES.txt +0 -0
  106. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/dependency_links.txt +0 -0
  107. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/entry_points.txt +0 -0
  108. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/requires.txt +0 -0
  109. {fdsx-0.2.2 → fdsx-0.2.3}/src/fdsx.egg-info/top_level.txt +0 -0
  110. {fdsx-0.2.2 → fdsx-0.2.3}/tests/__init__.py +0 -0
  111. {fdsx-0.2.2 → fdsx-0.2.3}/tests/conftest.py +0 -0
  112. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/__init__.py +0 -0
  113. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/cli_test_utils.py +0 -0
  114. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/conftest.py +0 -0
  115. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_add_cli.py +0 -0
  116. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_auto_init.py +0 -0
  117. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_batch_backward_compat.py +0 -0
  118. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_batch_edge_cases.py +0 -0
  119. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_batch_error_messages.py +0 -0
  120. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_batch_full_pipeline.py +0 -0
  121. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_batch_split.py +0 -0
  122. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_batch_tasks.py +0 -0
  123. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_flow_types.py +0 -0
  124. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_map_flow.py +0 -0
  125. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_signal_handling.py +0 -0
  126. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_thread_id.py +0 -0
  127. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_validation_and_run.py +0 -0
  128. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_wait_and_resume.py +0 -0
  129. {fdsx-0.2.2 → fdsx-0.2.3}/tests/e2e/test_cli_workflow_name.py +0 -0
  130. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/batch_flow.yaml +0 -0
  131. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/checkpoint_flow.yaml +0 -0
  132. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/choice_flow.yaml +0 -0
  133. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/choice_flow_default.yaml +0 -0
  134. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/claude_stream.ndjson +0 -0
  135. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/codex_stream.jsonl +0 -0
  136. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/extraction_flow.yaml +0 -0
  137. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/input_flow.yaml +0 -0
  138. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/invalid_flows/bad_next_ref.yaml +0 -0
  139. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/invalid_flows/missing_start_at.yaml +0 -0
  140. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/invalid_flows/mutual_exclusive.yaml +0 -0
  141. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/json_codeblock_extraction_flow.yaml +0 -0
  142. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/json_extraction_flow.yaml +0 -0
  143. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/loop_flow.yaml +0 -0
  144. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/map_basic.yaml +0 -0
  145. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/map_empty_items.yaml +0 -0
  146. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/map_fail_fast_false.yaml +0 -0
  147. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/map_inside_parallel.yaml +0 -0
  148. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/max_iterations_flow.yaml +0 -0
  149. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/max_iterations_wait_flow.yaml +0 -0
  150. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/parallel_min_success.yaml +0 -0
  151. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/parallel_review.yaml +0 -0
  152. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/profile_flow.yaml +0 -0
  153. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/profile_parallel_flow.yaml +0 -0
  154. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/prompt_file_test/flow.yaml +0 -0
  155. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/prompt_file_test/prompt.txt +0 -0
  156. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/regex_extraction_flow.yaml +0 -0
  157. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/sample_tasks.md +0 -0
  158. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/self_improve_flow/collect_data.sh +0 -0
  159. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/self_improve_flow/workflow.yaml +0 -0
  160. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/simple_flow.yaml +0 -0
  161. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/wait_approval.yaml +0 -0
  162. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/wait_resume_flow.yaml +0 -0
  163. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/wait_webhook.yaml +0 -0
  164. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/workflows_name_display/alpha.yaml +0 -0
  165. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/workflows_name_display/beta/workflow.yaml +0 -0
  166. {fdsx-0.2.2 → fdsx-0.2.3}/tests/fixtures/workflows_name_display/gamma.yaml +0 -0
  167. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/__init__.py +0 -0
  168. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_add_single_task.py +0 -0
  169. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_auto_init.py +0 -0
  170. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_auto_init_cli.py +0 -0
  171. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_auto_select.py +0 -0
  172. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_checkpoint_resume.py +0 -0
  173. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_choice_flow.py +0 -0
  174. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_claude_streaming.py +0 -0
  175. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_codex_stream_lifecycle.py +0 -0
  176. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_codex_streaming.py +0 -0
  177. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_default_tasks_dir.py +0 -0
  178. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_extraction_flow.py +0 -0
  179. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_gemini_provider.py +0 -0
  180. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_hook_streaming_interaction.py +0 -0
  181. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_hooks_integration.py +0 -0
  182. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_inactivity_timeout.py +0 -0
  183. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_init.py +0 -0
  184. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_init_cli.py +0 -0
  185. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_init_full_flow.py +0 -0
  186. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_init_interactive.py +0 -0
  187. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_init_templates.py +0 -0
  188. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_iteration_logs.py +0 -0
  189. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_large_command.py +0 -0
  190. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_linear_flow.py +0 -0
  191. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_lock_atomicity.py +0 -0
  192. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_loop_enforcement.py +0 -0
  193. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_loop_flow.py +0 -0
  194. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_map_checkpoint.py +0 -0
  195. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_map_flow.py +0 -0
  196. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_max_iterations_flow.py +0 -0
  197. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_parallel_flow.py +0 -0
  198. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_profile_assignment.py +0 -0
  199. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_profile_flow.py +0 -0
  200. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_provider_options.py +0 -0
  201. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_quiet_mode.py +0 -0
  202. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_result_file.py +0 -0
  203. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_resume_interrupt.py +0 -0
  204. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_scaffold_gitignore.py +0 -0
  205. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_scenario_flows.py +0 -0
  206. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_self_improve_flow.py +0 -0
  207. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_single_task_confirm.py +0 -0
  208. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_skill_install.py +0 -0
  209. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_split.py +0 -0
  210. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_split_spinner.py +0 -0
  211. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_stream_output.py +0 -0
  212. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_subprocess_completion.py +0 -0
  213. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_system_prompt.py +0 -0
  214. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_tasks_dir.py +0 -0
  215. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_tool_use_streaming.py +0 -0
  216. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_universal_scaffold_trigger.py +0 -0
  217. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_wait_resume.py +0 -0
  218. {fdsx-0.2.2 → fdsx-0.2.3}/tests/integration/test_workflow_persistence.py +0 -0
  219. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/__init__.py +0 -0
  220. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_aggregation.py +0 -0
  221. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_backoff.py +0 -0
  222. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_batch.py +0 -0
  223. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_checkpoint.py +0 -0
  224. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_claude_options.py +0 -0
  225. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_claude_stream_parser.py +0 -0
  226. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_cli_version.py +0 -0
  227. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_codex_stream_parser.py +0 -0
  228. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_compiler_merge.py +0 -0
  229. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_config.py +0 -0
  230. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_config_generation.py +0 -0
  231. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_engine.py +0 -0
  232. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_execution.py +0 -0
  233. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_extraction.py +0 -0
  234. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_format_tool_input_summary.py +0 -0
  235. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_gemini_options.py +0 -0
  236. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_gemini_stream.py +0 -0
  237. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_gitignore.py +0 -0
  238. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_graph_utils.py +0 -0
  239. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_hooks.py +0 -0
  240. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_loader.py +0 -0
  241. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_map_model.py +0 -0
  242. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_max_iterations.py +0 -0
  243. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_models.py +0 -0
  244. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_paths.py +0 -0
  245. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_profile_fixtures.py +0 -0
  246. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_profiles.py +0 -0
  247. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_prompt_file.py +0 -0
  248. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_provider_options.py +0 -0
  249. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_provider_stdin_fallback.py +0 -0
  250. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_recorder.py +0 -0
  251. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_result_file.py +0 -0
  252. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_resume_display.py +0 -0
  253. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_selector.py +0 -0
  254. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_selector_name.py +0 -0
  255. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_signal_handler.py +0 -0
  256. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_spinner.py +0 -0
  257. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_stream_callback.py +0 -0
  258. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_stream_logger.py +0 -0
  259. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_stream_logger_iteration.py +0 -0
  260. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_subprocess_completion.py +0 -0
  261. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_subprocess_realtime_streaming.py +0 -0
  262. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_subprocess_stdin.py +0 -0
  263. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_task_model.py +0 -0
  264. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_task_splitter_prompt.py +0 -0
  265. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_terminal.py +0 -0
  266. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_thread_id.py +0 -0
  267. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_variables.py +0 -0
  268. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_webhook.py +0 -0
  269. {fdsx-0.2.2 → fdsx-0.2.3}/tests/unit/test_workflow_cui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fdsx
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Declarative AI agent workflow execution framework
5
5
  Author: kenfdev
6
6
  License-Expression: MIT
@@ -50,8 +50,10 @@ fdsx enables you to define AI agent workflows in YAML, combining the durability
50
50
 
51
51
  **Key features:**
52
52
  - Declarative YAML-based workflow definition
53
+ - Interactive project initialization and scaffolding
53
54
  - Stateful execution with checkpoint/resume
54
55
  - Parallel execution with branch aggregation
56
+ - Map state for iterating over arrays with sub-workflows
55
57
  - Batch task processing (in-memory and persistent)
56
58
  - Multiple LLM provider support (Claude, Codex, Gemini, OpenCode, and system commands)
57
59
  - Named profiles for reusable provider/model configuration
@@ -74,6 +76,14 @@ uv tool install fdsx
74
76
 
75
77
  ## Quick Start
76
78
 
79
+ Initialize a new project:
80
+
81
+ ```bash
82
+ fdsx init
83
+ ```
84
+
85
+ This interactively scaffolds a `.fdsx/` directory with configuration and example workflows.
86
+
77
87
  Create a simple YAML workflow file:
78
88
 
79
89
  ```yaml
@@ -286,7 +296,7 @@ states:
286
296
  result_path: $.iter.step2
287
297
  retry: 0
288
298
  fail_fast: true # (bool, default: true) stop all iterations on first failure
289
- result_path: $.map_results # (string, optional) JSONPath for the results array
299
+ result_path: $.map_results # (string, REQUIRED) JSONPath for the results array
290
300
  max_iterations: 10 # (int, optional) max times this state can be re-entered
291
301
  hooks: # (optional)
292
302
  next: after_map # next / end — same rules as task
@@ -446,6 +456,10 @@ workflows_dir: .fdsx/workflows # (string, default: ".fdsx/workflows")
446
456
  # must be relative, no ".." components
447
457
  # where `fdsx run --tasks-dir` discovers workflows
448
458
 
459
+ # --- Default tasks directory ---
460
+ default_tasks_dir: .fdsx/tasks # (string, optional) default directory for bare `fdsx run`
461
+ # when no workflow, --tasks, or --tasks-dir is given
462
+
449
463
  # --- Auto-workflow selection ---
450
464
  auto_workflow: false # (bool, default: false) skip interactive confirmation UI
451
465
 
@@ -457,7 +471,7 @@ workflow_selector:
457
471
  extra_instructions: | # (string, optional) appended to the selection prompt
458
472
  Prefer simple-impl for small tasks.
459
473
 
460
- # --- Task splitter: LLM used by `fdsx split` ---
474
+ # --- Task splitter: LLM used by `fdsx add --split` ---
461
475
  task_splitter:
462
476
  profile: smarty # (string, optional) profile ref — mutually exclusive with provider/model
463
477
  # provider: claude # (string, default: "claude")
@@ -477,6 +491,8 @@ providers:
477
491
  dangerously_skip_permissions: true # (bool, default: false)
478
492
  allowed_tools: [] # (list of strings, default: []) tool allowlist
479
493
  disallowed_tools: [] # (list of strings, default: []) tool denylist
494
+ system_prompt: "Custom system prompt" # (string, optional) override the default system prompt
495
+ append_system_prompt: "Extra instructions" # (string, optional) append to the default system prompt
480
496
  inactivity_timeout: 600 # (int, optional) seconds before killing inactive subprocess
481
497
 
482
498
  codex:
@@ -526,6 +542,9 @@ hooks:
526
542
 
527
543
  | Command | Description |
528
544
  |---------|-------------|
545
+ | `fdsx init` | Initialize a new fdsx project with interactive setup |
546
+ | `fdsx init --skill` | Install the /fdsx Claude Code skill only (skip scaffold) |
547
+ | `fdsx run` | Execute tasks from default tasks directory (`default_tasks_dir` or `.fdsx/tasks/`) |
529
548
  | `fdsx run <workflow.yaml>` | Execute a workflow |
530
549
  | `fdsx run <workflow.yaml> --input key=value` | Pass input variables |
531
550
  | `fdsx run <workflow.yaml> --tasks tasks.yaml` | In-memory batch execution |
@@ -538,8 +557,9 @@ hooks:
538
557
  | `fdsx validate <workflow.yaml>` | Validate YAML syntax |
539
558
  | `fdsx list` | List recent runs |
540
559
  | `fdsx list --base-dir <dir>` | List runs from custom base directory |
541
- | `fdsx split <task_file>` | Split a task file into individual task files |
542
- | `fdsx split <task_file> --force` | Clear existing tasks directory before splitting |
560
+ | `fdsx add <task_file>` | Add a task file to the batch execution queue (single task) |
561
+ | `fdsx add <task_file> --split` | Split a task file into individual task files |
562
+ | `fdsx add <task_file> --split --force` | Clear existing tasks directory before splitting |
543
563
 
544
564
  ## Example Workflow
545
565
 
@@ -610,8 +630,8 @@ states:
610
630
 
611
631
  Run this example:
612
632
  ```bash
613
- # First run in a new directory scaffolds .fdsx/ with example workflows:
614
- fdsx run
633
+ # Initialize the project (creates .fdsx/ with config and example workflows):
634
+ fdsx init
615
635
 
616
636
  # Then run the scaffolded example workflow:
617
637
  fdsx run .fdsx/workflows/plan-implement-review/workflow.yaml --input task="Build a web calculator"
@@ -10,8 +10,10 @@ fdsx enables you to define AI agent workflows in YAML, combining the durability
10
10
 
11
11
  **Key features:**
12
12
  - Declarative YAML-based workflow definition
13
+ - Interactive project initialization and scaffolding
13
14
  - Stateful execution with checkpoint/resume
14
15
  - Parallel execution with branch aggregation
16
+ - Map state for iterating over arrays with sub-workflows
15
17
  - Batch task processing (in-memory and persistent)
16
18
  - Multiple LLM provider support (Claude, Codex, Gemini, OpenCode, and system commands)
17
19
  - Named profiles for reusable provider/model configuration
@@ -34,6 +36,14 @@ uv tool install fdsx
34
36
 
35
37
  ## Quick Start
36
38
 
39
+ Initialize a new project:
40
+
41
+ ```bash
42
+ fdsx init
43
+ ```
44
+
45
+ This interactively scaffolds a `.fdsx/` directory with configuration and example workflows.
46
+
37
47
  Create a simple YAML workflow file:
38
48
 
39
49
  ```yaml
@@ -246,7 +256,7 @@ states:
246
256
  result_path: $.iter.step2
247
257
  retry: 0
248
258
  fail_fast: true # (bool, default: true) stop all iterations on first failure
249
- result_path: $.map_results # (string, optional) JSONPath for the results array
259
+ result_path: $.map_results # (string, REQUIRED) JSONPath for the results array
250
260
  max_iterations: 10 # (int, optional) max times this state can be re-entered
251
261
  hooks: # (optional)
252
262
  next: after_map # next / end — same rules as task
@@ -406,6 +416,10 @@ workflows_dir: .fdsx/workflows # (string, default: ".fdsx/workflows")
406
416
  # must be relative, no ".." components
407
417
  # where `fdsx run --tasks-dir` discovers workflows
408
418
 
419
+ # --- Default tasks directory ---
420
+ default_tasks_dir: .fdsx/tasks # (string, optional) default directory for bare `fdsx run`
421
+ # when no workflow, --tasks, or --tasks-dir is given
422
+
409
423
  # --- Auto-workflow selection ---
410
424
  auto_workflow: false # (bool, default: false) skip interactive confirmation UI
411
425
 
@@ -417,7 +431,7 @@ workflow_selector:
417
431
  extra_instructions: | # (string, optional) appended to the selection prompt
418
432
  Prefer simple-impl for small tasks.
419
433
 
420
- # --- Task splitter: LLM used by `fdsx split` ---
434
+ # --- Task splitter: LLM used by `fdsx add --split` ---
421
435
  task_splitter:
422
436
  profile: smarty # (string, optional) profile ref — mutually exclusive with provider/model
423
437
  # provider: claude # (string, default: "claude")
@@ -437,6 +451,8 @@ providers:
437
451
  dangerously_skip_permissions: true # (bool, default: false)
438
452
  allowed_tools: [] # (list of strings, default: []) tool allowlist
439
453
  disallowed_tools: [] # (list of strings, default: []) tool denylist
454
+ system_prompt: "Custom system prompt" # (string, optional) override the default system prompt
455
+ append_system_prompt: "Extra instructions" # (string, optional) append to the default system prompt
440
456
  inactivity_timeout: 600 # (int, optional) seconds before killing inactive subprocess
441
457
 
442
458
  codex:
@@ -486,6 +502,9 @@ hooks:
486
502
 
487
503
  | Command | Description |
488
504
  |---------|-------------|
505
+ | `fdsx init` | Initialize a new fdsx project with interactive setup |
506
+ | `fdsx init --skill` | Install the /fdsx Claude Code skill only (skip scaffold) |
507
+ | `fdsx run` | Execute tasks from default tasks directory (`default_tasks_dir` or `.fdsx/tasks/`) |
489
508
  | `fdsx run <workflow.yaml>` | Execute a workflow |
490
509
  | `fdsx run <workflow.yaml> --input key=value` | Pass input variables |
491
510
  | `fdsx run <workflow.yaml> --tasks tasks.yaml` | In-memory batch execution |
@@ -498,8 +517,9 @@ hooks:
498
517
  | `fdsx validate <workflow.yaml>` | Validate YAML syntax |
499
518
  | `fdsx list` | List recent runs |
500
519
  | `fdsx list --base-dir <dir>` | List runs from custom base directory |
501
- | `fdsx split <task_file>` | Split a task file into individual task files |
502
- | `fdsx split <task_file> --force` | Clear existing tasks directory before splitting |
520
+ | `fdsx add <task_file>` | Add a task file to the batch execution queue (single task) |
521
+ | `fdsx add <task_file> --split` | Split a task file into individual task files |
522
+ | `fdsx add <task_file> --split --force` | Clear existing tasks directory before splitting |
503
523
 
504
524
  ## Example Workflow
505
525
 
@@ -570,8 +590,8 @@ states:
570
590
 
571
591
  Run this example:
572
592
  ```bash
573
- # First run in a new directory scaffolds .fdsx/ with example workflows:
574
- fdsx run
593
+ # Initialize the project (creates .fdsx/ with config and example workflows):
594
+ fdsx init
575
595
 
576
596
  # Then run the scaffolded example workflow:
577
597
  fdsx run .fdsx/workflows/plan-implement-review/workflow.yaml --input task="Build a web calculator"
@@ -592,4 +612,4 @@ fdsx list
592
612
 
593
613
  ## License
594
614
 
595
- MIT License.
615
+ MIT License.
@@ -4,10 +4,11 @@ description: >
4
4
  Expert guide for authoring, validating, and running fdsx declarative AI agent
5
5
  workflow YAML files. Use when writing fdsx workflows, editing workflow YAML,
6
6
  configuring fdsx providers (claude, codex, opencode, gemini), setting up
7
- profiles, adding hooks, using choice/parallel/loop/wait/pass states, running
7
+ profiles, adding hooks, using choice/parallel/loop/wait/pass/map states, running
8
8
  fdsx CLI commands, debugging workflow validation errors, or asking about fdsx
9
9
  YAML schema. Also triggers on: "fdsx", "workflow YAML", "declarative agent
10
- workflow", "multi-step AI pipeline", "provider options", "checkpoint resume".
10
+ workflow", "multi-step AI pipeline", "provider options", "checkpoint resume",
11
+ "map state", "iterator".
11
12
  ---
12
13
 
13
14
  # fdsx Workflow Authoring Guide
@@ -56,6 +57,7 @@ Read `references/yaml-schema.md` for the complete field-by-field schema referenc
56
57
  | `parallel` | Execute multiple branches concurrently | `branches`, `result_path`, `result_file`, `min_success` |
57
58
  | `pass` | Data transformation / aggregation | `parameters`, `aggregate` |
58
59
  | `wait` | Human input via terminal prompt | `mode: prompt`, `message`, `choices`, `result_path` |
60
+ | `map` | Iterate over an array, execute sub-workflow per item | `items_path`, `iterator`, `result_path`, `fail_fast` |
59
61
 
60
62
  Every state except `choice` supports `next` (go to state) or `end: true` (terminate flow). These are mutually exclusive.
61
63
 
@@ -97,7 +99,7 @@ states:
97
99
 
98
100
  `profile` and explicit `provider`/`model` are mutually exclusive (XOR). Profiles can also be defined in `.fdsx/config.yaml` and are merged (workflow-level overrides config-level).
99
101
 
100
- Profile shorthand is supported on task states, parallel branches, and extract fallback configurations.
102
+ Profile shorthand is supported on task states, parallel branches, and extract fallback configurations. Note: profile shorthand is **not** supported on map iterator task states.
101
103
 
102
104
  ## Variable Substitution
103
105
 
@@ -131,17 +133,24 @@ extract:
131
133
  ## CLI Commands
132
134
 
133
135
  ```
134
- fdsx run <workflow.yaml> [--input KEY=VALUE] [--tasks <file>] [--tasks-dir <dir>] [--thread-id <id>] [--quiet] [--auto-workflow] [--confirm-workflow]
136
+ fdsx run [<workflow.yaml>] [--input KEY=VALUE] [--tasks <file>] [--tasks-dir <dir>] [--thread-id <id>] [--quiet] [--auto-workflow] [--confirm-workflow]
135
137
  fdsx validate <workflow.yaml>
136
138
  fdsx resume --thread-id <id> [--base-dir <path>]
137
139
  fdsx list [--base-dir <path>]
138
- fdsx split <task-file> [--force]
140
+ fdsx add <task-file> [--split] [--force]
141
+ fdsx init [--skill]
139
142
  fdsx --version
140
143
  fdsx --ci | --interactive # global flags (mutually exclusive)
141
144
  ```
142
145
 
143
146
  `--auto-workflow` and `--confirm-workflow` are mutually exclusive. `--auto-workflow` skips interactive workflow confirmation; `--confirm-workflow` forces the confirmation UI.
144
147
 
148
+ When `fdsx run` is invoked with no workflow, no `--tasks-dir`, no `--tasks`, and no `--input`, it falls back to the `default_tasks_dir` config value (default: `.fdsx/tasks/`) and runs in tasks-dir mode.
149
+
150
+ `fdsx add <task-file>` adds a task file to the batch execution queue. Use `--split` to invoke the LLM task splitter to break the file into multiple task files in `.fdsx/tasks/`. Use `--force` to clear existing tasks before writing.
151
+
152
+ `fdsx init` initializes a new fdsx project with interactive provider and template selection. Use `--skill` to install only the Claude Code skill without scaffolding `.fdsx/`.
153
+
145
154
  ## Hooks
146
155
 
147
156
  Shell commands that run before/after state or flow execution:
@@ -169,6 +178,7 @@ Hook data files are written to `.fdsx/runs/<thread-id>/hooks/<state-name>/input.
169
178
  ```yaml
170
179
  auto_workflow: false # skip workflow confirmation UI (default: false)
171
180
  workflows_dir: .fdsx/workflows # directory for workflow discovery
181
+ default_tasks_dir: .fdsx/tasks/ # default tasks directory for no-arg fdsx run
172
182
  workflow_selector:
173
183
  provider: claude # LLM for auto-selecting workflows
174
184
  model: claude-sonnet-4-6
@@ -192,6 +202,36 @@ Use `parallel` → `pass` (with `aggregate`) → `choice` to fan out reviews, ag
192
202
  **Human gate:**
193
203
  Use `wait` state with `mode: prompt` to pause for user input, then route with `choice`.
194
204
 
205
+ **Map over items (e.g., process each file):**
206
+ Use a preceding state to produce an array, then `map` to iterate over it with a sub-workflow per item:
207
+
208
+ ```yaml
209
+ states:
210
+ collect:
211
+ type: task
212
+ provider: system
213
+ command: "echo '[{\"path\":\"a.py\"},{\"path\":\"b.py\"}]'"
214
+ result_path: $.files
215
+ next: process_each
216
+
217
+ process_each:
218
+ type: map
219
+ items_path: $.files
220
+ iterator:
221
+ states:
222
+ - type: task
223
+ name: review
224
+ provider: claude
225
+ model: claude-sonnet-4-6
226
+ prompt_template: "Review file: {item.path}"
227
+ result_path: $.review
228
+ result_path: $.reviews
229
+ fail_fast: true
230
+ end: true
231
+ ```
232
+
233
+ Inside iterator states, `{item}` refers to the current array element. Use `{item.field}` for nested access.
234
+
195
235
  ## Validation Rules
196
236
 
197
237
  - `start_at` must reference an existing state name
@@ -200,4 +240,5 @@ Use `wait` state with `mode: prompt` to pause for user input, then route with `c
200
240
  - `prompt_template` and `prompt_file` are mutually exclusive
201
241
  - `next` and `end` are mutually exclusive
202
242
  - `result_file` must be a top-level `$.varname` path (no nesting)
203
- - Extract `result_path` must not use reserved keys: `output`, `exit_code`, `error`
243
+ - Extract `result_path` must not use reserved keys: `output`, `exit_code`, `error`
244
+ - Map iterator states must all have `type: task` and unique `name` fields
@@ -10,6 +10,9 @@ Complete field-by-field reference for fdsx workflow YAML files, derived from the
10
10
  - [ParallelState](#parallelstate)
11
11
  - [PassState](#passstate)
12
12
  - [WaitState](#waitstate)
13
+ - [MapState](#mapstate)
14
+ - [IteratorDef](#iteratordef)
15
+ - [IteratorTaskState](#iteratortaskstate)
13
16
  - [Branch (parallel)](#branch)
14
17
  - [ExtractRule](#extractrule)
15
18
  - [ChoiceRule](#choicerule)
@@ -35,6 +38,8 @@ hooks?: HookConfig # optional — flow-level hooks
35
38
  profiles?: {name: {k: v}} # optional — raw provider/model/extras dicts
36
39
  ```
37
40
 
41
+ **State** is a discriminated union on the `type` field: `TaskState | ChoiceState | ParallelState | PassState | WaitState | MapState`.
42
+
38
43
  **Profiles at workflow level** are raw YAML dicts (`{provider, model, ...extras}`), not validated `ProfileConfig` objects. Profile resolution happens pre-validation: `profile` references in tasks/branches are expanded into `provider`/`model`/`provider_options` fields before Pydantic validation runs. Workflow-level profiles override config-level profiles (full replacement per name, not deep merge).
39
44
 
40
45
  **Validation:**
@@ -148,6 +153,77 @@ notify:
148
153
 
149
154
  ---
150
155
 
156
+ ## MapState
157
+
158
+ ```yaml
159
+ type: "map" # literal discriminator
160
+ items_path: string # required — JSONPath to input array
161
+ iterator: IteratorDef # required — sub-workflow to execute for each item
162
+ result_path: string # required — JSONPath for results array
163
+ fail_fast?: bool # default: true — stop on first failure
164
+ max_iterations?: int # optional — >=1, max times this state can be entered
165
+ hooks?: HookConfig # optional — per-state hooks
166
+ next?: string # XOR with end — target state
167
+ end?: bool # XOR with next — terminate flow
168
+ ```
169
+
170
+ **Variable context inside iterator:** Each iterator state receives the current array element as `{item}`. References like `{item.field}` access nested fields of the current element. Variables from preceding states in the outer flow are also available.
171
+
172
+ **Validation:**
173
+ - `next` and `end` are mutually exclusive
174
+ - `items_path` must reference a variable set by a preceding state
175
+ - Iterator states must all have `type: "task"` (no nested choice/parallel/pass/wait/map)
176
+ - Iterator state names must be unique within the iterator
177
+
178
+ ---
179
+
180
+ ## IteratorDef
181
+
182
+ Used inside `MapState.iterator`:
183
+
184
+ ```yaml
185
+ iterator:
186
+ states: [IteratorTaskState] # required — min 1 item, ordered list of task states
187
+ ```
188
+
189
+ **Validation:**
190
+ - All states must have `type: "task"` (non-task types are rejected)
191
+ - State names must be unique within the iterator
192
+
193
+ ---
194
+
195
+ ## IteratorTaskState
196
+
197
+ Used inside `IteratorDef.states`:
198
+
199
+ ```yaml
200
+ type: "task" # literal discriminator (only "task" allowed)
201
+ name: string # required — state name within the iterator
202
+ provider: string # required — claude|codex|opencode|gemini|system
203
+ model?: string # required for LLM providers, forbidden for system
204
+ prompt_template?: string # XOR with prompt_file; required for LLM providers
205
+ prompt_file?: string # XOR with prompt_template; relative path
206
+ command?: string # required for system, forbidden for LLM providers
207
+ result_path: string # required — JSONPath for result
208
+ result_file?: string # optional — top-level $.varname only (no nesting)
209
+ extract?: ExtractRule # optional — output extraction
210
+ retry?: int # default: 3
211
+ timeout_seconds?: int # optional — per-state timeout override
212
+ provider_options?: {k: v} # optional — per-task provider option overrides
213
+ ```
214
+
215
+ **Differences from TaskState:** Has a required `name` field. Does not support `max_iterations`, `hooks`, `next`, or `end` (iteration order is determined by list position).
216
+
217
+ **Note:** Profile shorthand (`profile: <name>`) is not currently supported on iterator task states. Use explicit `provider`/`model` fields.
218
+
219
+ **Validation:**
220
+ - `prompt_template` and `prompt_file` are mutually exclusive
221
+ - `result_path` and `extract.result_path` must not overlap
222
+ - `result_file` must match `$.varname` (no dots or brackets after `$.`)
223
+ - Same provider field validation rules as TaskState
224
+
225
+ ---
226
+
151
227
  ## Branch
152
228
 
153
229
  Used inside `ParallelState.branches`:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fdsx
3
- Version: 0.2.2
3
+ Version: 0.2.3
4
4
  Summary: Declarative AI agent workflow execution framework
5
5
  Author: kenfdev
6
6
  License-Expression: MIT
@@ -50,8 +50,10 @@ fdsx enables you to define AI agent workflows in YAML, combining the durability
50
50
 
51
51
  **Key features:**
52
52
  - Declarative YAML-based workflow definition
53
+ - Interactive project initialization and scaffolding
53
54
  - Stateful execution with checkpoint/resume
54
55
  - Parallel execution with branch aggregation
56
+ - Map state for iterating over arrays with sub-workflows
55
57
  - Batch task processing (in-memory and persistent)
56
58
  - Multiple LLM provider support (Claude, Codex, Gemini, OpenCode, and system commands)
57
59
  - Named profiles for reusable provider/model configuration
@@ -74,6 +76,14 @@ uv tool install fdsx
74
76
 
75
77
  ## Quick Start
76
78
 
79
+ Initialize a new project:
80
+
81
+ ```bash
82
+ fdsx init
83
+ ```
84
+
85
+ This interactively scaffolds a `.fdsx/` directory with configuration and example workflows.
86
+
77
87
  Create a simple YAML workflow file:
78
88
 
79
89
  ```yaml
@@ -286,7 +296,7 @@ states:
286
296
  result_path: $.iter.step2
287
297
  retry: 0
288
298
  fail_fast: true # (bool, default: true) stop all iterations on first failure
289
- result_path: $.map_results # (string, optional) JSONPath for the results array
299
+ result_path: $.map_results # (string, REQUIRED) JSONPath for the results array
290
300
  max_iterations: 10 # (int, optional) max times this state can be re-entered
291
301
  hooks: # (optional)
292
302
  next: after_map # next / end — same rules as task
@@ -446,6 +456,10 @@ workflows_dir: .fdsx/workflows # (string, default: ".fdsx/workflows")
446
456
  # must be relative, no ".." components
447
457
  # where `fdsx run --tasks-dir` discovers workflows
448
458
 
459
+ # --- Default tasks directory ---
460
+ default_tasks_dir: .fdsx/tasks # (string, optional) default directory for bare `fdsx run`
461
+ # when no workflow, --tasks, or --tasks-dir is given
462
+
449
463
  # --- Auto-workflow selection ---
450
464
  auto_workflow: false # (bool, default: false) skip interactive confirmation UI
451
465
 
@@ -457,7 +471,7 @@ workflow_selector:
457
471
  extra_instructions: | # (string, optional) appended to the selection prompt
458
472
  Prefer simple-impl for small tasks.
459
473
 
460
- # --- Task splitter: LLM used by `fdsx split` ---
474
+ # --- Task splitter: LLM used by `fdsx add --split` ---
461
475
  task_splitter:
462
476
  profile: smarty # (string, optional) profile ref — mutually exclusive with provider/model
463
477
  # provider: claude # (string, default: "claude")
@@ -477,6 +491,8 @@ providers:
477
491
  dangerously_skip_permissions: true # (bool, default: false)
478
492
  allowed_tools: [] # (list of strings, default: []) tool allowlist
479
493
  disallowed_tools: [] # (list of strings, default: []) tool denylist
494
+ system_prompt: "Custom system prompt" # (string, optional) override the default system prompt
495
+ append_system_prompt: "Extra instructions" # (string, optional) append to the default system prompt
480
496
  inactivity_timeout: 600 # (int, optional) seconds before killing inactive subprocess
481
497
 
482
498
  codex:
@@ -526,6 +542,9 @@ hooks:
526
542
 
527
543
  | Command | Description |
528
544
  |---------|-------------|
545
+ | `fdsx init` | Initialize a new fdsx project with interactive setup |
546
+ | `fdsx init --skill` | Install the /fdsx Claude Code skill only (skip scaffold) |
547
+ | `fdsx run` | Execute tasks from default tasks directory (`default_tasks_dir` or `.fdsx/tasks/`) |
529
548
  | `fdsx run <workflow.yaml>` | Execute a workflow |
530
549
  | `fdsx run <workflow.yaml> --input key=value` | Pass input variables |
531
550
  | `fdsx run <workflow.yaml> --tasks tasks.yaml` | In-memory batch execution |
@@ -538,8 +557,9 @@ hooks:
538
557
  | `fdsx validate <workflow.yaml>` | Validate YAML syntax |
539
558
  | `fdsx list` | List recent runs |
540
559
  | `fdsx list --base-dir <dir>` | List runs from custom base directory |
541
- | `fdsx split <task_file>` | Split a task file into individual task files |
542
- | `fdsx split <task_file> --force` | Clear existing tasks directory before splitting |
560
+ | `fdsx add <task_file>` | Add a task file to the batch execution queue (single task) |
561
+ | `fdsx add <task_file> --split` | Split a task file into individual task files |
562
+ | `fdsx add <task_file> --split --force` | Clear existing tasks directory before splitting |
543
563
 
544
564
  ## Example Workflow
545
565
 
@@ -610,8 +630,8 @@ states:
610
630
 
611
631
  Run this example:
612
632
  ```bash
613
- # First run in a new directory scaffolds .fdsx/ with example workflows:
614
- fdsx run
633
+ # Initialize the project (creates .fdsx/ with config and example workflows):
634
+ fdsx init
615
635
 
616
636
  # Then run the scaffolded example workflow:
617
637
  fdsx run .fdsx/workflows/plan-implement-review/workflow.yaml --input task="Build a web calculator"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes