whiletrue 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 (191) hide show
  1. whiletrue-0.1.0/.editorconfig +11 -0
  2. whiletrue-0.1.0/.envrc +8 -0
  3. whiletrue-0.1.0/.github/ISSUE_TEMPLATE/task.md +16 -0
  4. whiletrue-0.1.0/.github/pull_request_template.md +10 -0
  5. whiletrue-0.1.0/.github/workflows/ci.yml +13 -0
  6. whiletrue-0.1.0/.github/workflows/release.yml +41 -0
  7. whiletrue-0.1.0/.gitignore +20 -0
  8. whiletrue-0.1.0/CHANGELOG.md +25 -0
  9. whiletrue-0.1.0/CLAUDE.md +19 -0
  10. whiletrue-0.1.0/LICENSE +21 -0
  11. whiletrue-0.1.0/PKG-INFO +48 -0
  12. whiletrue-0.1.0/README.md +23 -0
  13. whiletrue-0.1.0/devenv.lock +131 -0
  14. whiletrue-0.1.0/devenv.nix +28 -0
  15. whiletrue-0.1.0/devenv.yaml +13 -0
  16. whiletrue-0.1.0/docs/README.md +18 -0
  17. whiletrue-0.1.0/docs/architecture.md +516 -0
  18. whiletrue-0.1.0/docs/authoring.md +123 -0
  19. whiletrue-0.1.0/docs/cli.md +74 -0
  20. whiletrue-0.1.0/docs/conventions.md +10 -0
  21. whiletrue-0.1.0/docs/developing.md +77 -0
  22. whiletrue-0.1.0/docs/getting-started.md +205 -0
  23. whiletrue-0.1.0/docs/m0-smoke.md +42 -0
  24. whiletrue-0.1.0/docs/open-questions.md +40 -0
  25. whiletrue-0.1.0/docs/plan.md +104 -0
  26. whiletrue-0.1.0/docs/plugins.md +157 -0
  27. whiletrue-0.1.0/docs/reference.md +176 -0
  28. whiletrue-0.1.0/docs/spike-interactive.md +44 -0
  29. whiletrue-0.1.0/docs/todo.md +110 -0
  30. whiletrue-0.1.0/examples/issue-loop/README.md +26 -0
  31. whiletrue-0.1.0/examples/issue-loop/agents/fix.md +10 -0
  32. whiletrue-0.1.0/examples/issue-loop/agents/implement.md +12 -0
  33. whiletrue-0.1.0/examples/issue-loop/agents/respond.md +11 -0
  34. whiletrue-0.1.0/examples/issue-loop/whiletrue.yaml +15 -0
  35. whiletrue-0.1.0/pyproject.toml +104 -0
  36. whiletrue-0.1.0/scripts/docs_check.py +46 -0
  37. whiletrue-0.1.0/tests/conftest.py +11 -0
  38. whiletrue-0.1.0/tests/fixtures/fake_interactive_claude.py +89 -0
  39. whiletrue-0.1.0/tests/integration/test_cli.py +559 -0
  40. whiletrue-0.1.0/tests/integration/test_cli_surface.py +50 -0
  41. whiletrue-0.1.0/tests/integration/test_gates_cli.py +210 -0
  42. whiletrue-0.1.0/tests/integration/test_interactive_run.py +107 -0
  43. whiletrue-0.1.0/tests/integration/test_issue_loop.py +196 -0
  44. whiletrue-0.1.0/tests/integration/test_m3_exit.py +113 -0
  45. whiletrue-0.1.0/tests/integration/test_ops_cli.py +298 -0
  46. whiletrue-0.1.0/tests/integration/test_recipes.py +135 -0
  47. whiletrue-0.1.0/tests/live/test_live_backends.py +85 -0
  48. whiletrue-0.1.0/tests/unit/basics/test_agent.py +401 -0
  49. whiletrue-0.1.0/tests/unit/basics/test_exec.py +68 -0
  50. whiletrue-0.1.0/tests/unit/basics/test_gates.py +101 -0
  51. whiletrue-0.1.0/tests/unit/basics/test_history.py +78 -0
  52. whiletrue-0.1.0/tests/unit/basics/test_human.py +463 -0
  53. whiletrue-0.1.0/tests/unit/basics/test_json_source.py +58 -0
  54. whiletrue-0.1.0/tests/unit/basics/test_markdown_source.py +62 -0
  55. whiletrue-0.1.0/tests/unit/basics/test_plugin.py +23 -0
  56. whiletrue-0.1.0/tests/unit/basics/test_process.py +62 -0
  57. whiletrue-0.1.0/tests/unit/basics/test_sessions.py +45 -0
  58. whiletrue-0.1.0/tests/unit/basics/test_shell.py +72 -0
  59. whiletrue-0.1.0/tests/unit/claude_code/test_endpoint.py +140 -0
  60. whiletrue-0.1.0/tests/unit/claude_code/test_headless.py +234 -0
  61. whiletrue-0.1.0/tests/unit/claude_code/test_interactive.py +413 -0
  62. whiletrue-0.1.0/tests/unit/claude_code/test_panes.py +65 -0
  63. whiletrue-0.1.0/tests/unit/claude_code/test_plugin_scripts.py +168 -0
  64. whiletrue-0.1.0/tests/unit/claude_code/test_session.py +339 -0
  65. whiletrue-0.1.0/tests/unit/claude_code/test_transcript.py +86 -0
  66. whiletrue-0.1.0/tests/unit/codex/test_runner.py +199 -0
  67. whiletrue-0.1.0/tests/unit/control/test_control.py +631 -0
  68. whiletrue-0.1.0/tests/unit/core/test_cache.py +113 -0
  69. whiletrue-0.1.0/tests/unit/core/test_caps.py +120 -0
  70. whiletrue-0.1.0/tests/unit/core/test_composite.py +198 -0
  71. whiletrue-0.1.0/tests/unit/core/test_config.py +241 -0
  72. whiletrue-0.1.0/tests/unit/core/test_context.py +82 -0
  73. whiletrue-0.1.0/tests/unit/core/test_duration.py +38 -0
  74. whiletrue-0.1.0/tests/unit/core/test_events.py +63 -0
  75. whiletrue-0.1.0/tests/unit/core/test_expr.py +64 -0
  76. whiletrue-0.1.0/tests/unit/core/test_history_store.py +161 -0
  77. whiletrue-0.1.0/tests/unit/core/test_lock.py +98 -0
  78. whiletrue-0.1.0/tests/unit/core/test_memory_store.py +48 -0
  79. whiletrue-0.1.0/tests/unit/core/test_module.py +131 -0
  80. whiletrue-0.1.0/tests/unit/core/test_outcomes.py +72 -0
  81. whiletrue-0.1.0/tests/unit/core/test_registry.py +118 -0
  82. whiletrue-0.1.0/tests/unit/core/test_replay.py +86 -0
  83. whiletrue-0.1.0/tests/unit/core/test_runtime.py +683 -0
  84. whiletrue-0.1.0/tests/unit/core/test_template.py +46 -0
  85. whiletrue-0.1.0/tests/unit/core/test_validate.py +197 -0
  86. whiletrue-0.1.0/tests/unit/core/test_wake.py +77 -0
  87. whiletrue-0.1.0/tests/unit/git/test_git.py +223 -0
  88. whiletrue-0.1.0/tests/unit/github/test_client.py +222 -0
  89. whiletrue-0.1.0/tests/unit/github/test_filebacked.py +46 -0
  90. whiletrue-0.1.0/tests/unit/github/test_plugin.py +331 -0
  91. whiletrue-0.1.0/tests/unit/github/test_specs.py +35 -0
  92. whiletrue-0.1.0/tests/unit/opencode/test_runner.py +185 -0
  93. whiletrue-0.1.0/tests/unit/store_sqlite/test_sqlite_store.py +156 -0
  94. whiletrue-0.1.0/tests/unit/test_abort.py +76 -0
  95. whiletrue-0.1.0/tests/unit/test_architecture.py +36 -0
  96. whiletrue-0.1.0/tests/unit/test_panel.py +168 -0
  97. whiletrue-0.1.0/tests/unit/tmux/test_controller.py +184 -0
  98. whiletrue-0.1.0/uv.lock +660 -0
  99. whiletrue-0.1.0/whiletrue/__init__.py +0 -0
  100. whiletrue-0.1.0/whiletrue/__main__.py +3 -0
  101. whiletrue-0.1.0/whiletrue/abort.py +79 -0
  102. whiletrue-0.1.0/whiletrue/basics/__init__.py +99 -0
  103. whiletrue-0.1.0/whiletrue/basics/agent.py +249 -0
  104. whiletrue-0.1.0/whiletrue/basics/comments.py +113 -0
  105. whiletrue-0.1.0/whiletrue/basics/diff_size.py +80 -0
  106. whiletrue-0.1.0/whiletrue/basics/exec_.py +84 -0
  107. whiletrue-0.1.0/whiletrue/basics/history.py +117 -0
  108. whiletrue-0.1.0/whiletrue/basics/human.py +201 -0
  109. whiletrue-0.1.0/whiletrue/basics/json_source.py +35 -0
  110. whiletrue-0.1.0/whiletrue/basics/markdown_source.py +55 -0
  111. whiletrue-0.1.0/whiletrue/basics/process.py +99 -0
  112. whiletrue-0.1.0/whiletrue/basics/sessions.py +62 -0
  113. whiletrue-0.1.0/whiletrue/basics/set_.py +29 -0
  114. whiletrue-0.1.0/whiletrue/basics/shell.py +98 -0
  115. whiletrue-0.1.0/whiletrue/basics/wake.py +27 -0
  116. whiletrue-0.1.0/whiletrue/claude_code/__init__.py +58 -0
  117. whiletrue-0.1.0/whiletrue/claude_code/endpoint.py +143 -0
  118. whiletrue-0.1.0/whiletrue/claude_code/headless.py +181 -0
  119. whiletrue-0.1.0/whiletrue/claude_code/interactive.py +344 -0
  120. whiletrue-0.1.0/whiletrue/claude_code/learnings.py +32 -0
  121. whiletrue-0.1.0/whiletrue/claude_code/panes.py +164 -0
  122. whiletrue-0.1.0/whiletrue/claude_code/plugin/.claude-plugin/plugin.json +5 -0
  123. whiletrue-0.1.0/whiletrue/claude_code/plugin/hook.py +44 -0
  124. whiletrue-0.1.0/whiletrue/claude_code/plugin/hooks/hooks.json +81 -0
  125. whiletrue-0.1.0/whiletrue/claude_code/plugin/mcp_server.py +98 -0
  126. whiletrue-0.1.0/whiletrue/claude_code/session.py +345 -0
  127. whiletrue-0.1.0/whiletrue/claude_code/transcript.py +123 -0
  128. whiletrue-0.1.0/whiletrue/cli/__init__.py +15 -0
  129. whiletrue-0.1.0/whiletrue/cli/__main__.py +3 -0
  130. whiletrue-0.1.0/whiletrue/cli/app.py +550 -0
  131. whiletrue-0.1.0/whiletrue/cli/common.py +36 -0
  132. whiletrue-0.1.0/whiletrue/cli/gates.py +156 -0
  133. whiletrue-0.1.0/whiletrue/cli/ops.py +339 -0
  134. whiletrue-0.1.0/whiletrue/cli/panel.py +198 -0
  135. whiletrue-0.1.0/whiletrue/cli/registry.py +143 -0
  136. whiletrue-0.1.0/whiletrue/cli/templates.py +24 -0
  137. whiletrue-0.1.0/whiletrue/codex/__init__.py +14 -0
  138. whiletrue-0.1.0/whiletrue/codex/runner.py +243 -0
  139. whiletrue-0.1.0/whiletrue/control/__init__.py +38 -0
  140. whiletrue-0.1.0/whiletrue/control/chain.py +61 -0
  141. whiletrue-0.1.0/whiletrue/control/loop.py +139 -0
  142. whiletrue-0.1.0/whiletrue/control/map_.py +101 -0
  143. whiletrue-0.1.0/whiletrue/control/parallel.py +32 -0
  144. whiletrue-0.1.0/whiletrue/control/retry.py +100 -0
  145. whiletrue-0.1.0/whiletrue/control/sequence.py +40 -0
  146. whiletrue-0.1.0/whiletrue/control/switch.py +67 -0
  147. whiletrue-0.1.0/whiletrue/core/__init__.py +260 -0
  148. whiletrue-0.1.0/whiletrue/core/caps.py +139 -0
  149. whiletrue-0.1.0/whiletrue/core/comments.py +80 -0
  150. whiletrue-0.1.0/whiletrue/core/composite.py +140 -0
  151. whiletrue-0.1.0/whiletrue/core/config.py +461 -0
  152. whiletrue-0.1.0/whiletrue/core/context.py +177 -0
  153. whiletrue-0.1.0/whiletrue/core/duration.py +19 -0
  154. whiletrue-0.1.0/whiletrue/core/events.py +94 -0
  155. whiletrue-0.1.0/whiletrue/core/expr.py +85 -0
  156. whiletrue-0.1.0/whiletrue/core/history.py +83 -0
  157. whiletrue-0.1.0/whiletrue/core/lock.py +86 -0
  158. whiletrue-0.1.0/whiletrue/core/memory_store.py +352 -0
  159. whiletrue-0.1.0/whiletrue/core/module.py +146 -0
  160. whiletrue-0.1.0/whiletrue/core/outcomes.py +82 -0
  161. whiletrue-0.1.0/whiletrue/core/registry.py +129 -0
  162. whiletrue-0.1.0/whiletrue/core/replay.py +58 -0
  163. whiletrue-0.1.0/whiletrue/core/runner.py +98 -0
  164. whiletrue-0.1.0/whiletrue/core/runtime.py +538 -0
  165. whiletrue-0.1.0/whiletrue/core/source.py +45 -0
  166. whiletrue-0.1.0/whiletrue/core/store.py +207 -0
  167. whiletrue-0.1.0/whiletrue/core/template.py +60 -0
  168. whiletrue-0.1.0/whiletrue/core/validate.py +142 -0
  169. whiletrue-0.1.0/whiletrue/core/wake.py +117 -0
  170. whiletrue-0.1.0/whiletrue/core/workspace.py +55 -0
  171. whiletrue-0.1.0/whiletrue/git/__init__.py +31 -0
  172. whiletrue-0.1.0/whiletrue/git/modules.py +128 -0
  173. whiletrue-0.1.0/whiletrue/git/workspaces.py +77 -0
  174. whiletrue-0.1.0/whiletrue/github/__init__.py +30 -0
  175. whiletrue-0.1.0/whiletrue/github/client.py +269 -0
  176. whiletrue-0.1.0/whiletrue/github/filebacked.py +87 -0
  177. whiletrue-0.1.0/whiletrue/github/memory.py +96 -0
  178. whiletrue-0.1.0/whiletrue/github/plugin.py +343 -0
  179. whiletrue-0.1.0/whiletrue/github/specs.py +39 -0
  180. whiletrue-0.1.0/whiletrue/opencode/__init__.py +25 -0
  181. whiletrue-0.1.0/whiletrue/opencode/runner.py +186 -0
  182. whiletrue-0.1.0/whiletrue/py.typed +0 -0
  183. whiletrue-0.1.0/whiletrue/recipes/issue-loop.yaml +59 -0
  184. whiletrue-0.1.0/whiletrue/recipes/ralph.yaml +14 -0
  185. whiletrue-0.1.0/whiletrue/recipes/review-pass.yaml +27 -0
  186. whiletrue-0.1.0/whiletrue/recipes/review-respond.yaml +22 -0
  187. whiletrue-0.1.0/whiletrue/store_sqlite/__init__.py +6 -0
  188. whiletrue-0.1.0/whiletrue/store_sqlite/migrations.py +132 -0
  189. whiletrue-0.1.0/whiletrue/store_sqlite/sqlite_store.py +537 -0
  190. whiletrue-0.1.0/whiletrue/tmux/__init__.py +11 -0
  191. whiletrue-0.1.0/whiletrue/tmux/controller.py +197 -0
@@ -0,0 +1,11 @@
1
+ root = true
2
+ [*]
3
+ indent_style = space
4
+ indent_size = 2
5
+ end_of_line = lf
6
+ charset = utf-8
7
+ insert_final_newline = true
8
+ trim_trailing_whitespace = true
9
+
10
+ [*.py]
11
+ indent_size = 4
whiletrue-0.1.0/.envrc ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ export DIRENV_WARN_TIMEOUT=20s
3
+
4
+ eval "$(devenv direnvrc)"
5
+
6
+ # The use_devenv function supports passing flags to the devenv command
7
+ # For example: use devenv --impure --option services.postgres.enable:bool true
8
+ use devenv
@@ -0,0 +1,16 @@
1
+ ---
2
+ name: Task
3
+ about: A numbered item from docs/todo.md
4
+ labels: task
5
+ ---
6
+
7
+ **Todo item #:**
8
+
9
+ **Milestone:** M0 / M1 / M2 / M3 / M4 / v0.1
10
+
11
+ ## Scope
12
+
13
+ ## Acceptance criteria
14
+
15
+ - [ ] Tests
16
+ - [ ] Docs
@@ -0,0 +1,10 @@
1
+ ## Summary
2
+
3
+ Closes #
4
+
5
+ ## Checklist
6
+
7
+ - [ ] Tests written first; `poe check` passes
8
+ - [ ] User docs and `docs/architecture.md` updated (or N/A, with reason)
9
+ - [ ] `docs/todo.md` item(s) ticked
10
+ - [ ] Human has reviewed every line
@@ -0,0 +1,13 @@
1
+ name: CI
2
+ on:
3
+ push: { branches: [main] }
4
+ pull_request:
5
+ jobs:
6
+ check:
7
+ runs-on: ubuntu-latest
8
+ steps:
9
+ - uses: actions/checkout@v4
10
+ - uses: astral-sh/setup-uv@v5
11
+ with: { enable-cache: true }
12
+ - run: uv sync --all-groups --locked
13
+ - run: uv run poe check
@@ -0,0 +1,41 @@
1
+ name: Release
2
+ # Pushing a tag like v0.1.0 checks, builds and publishes to PyPI (trusted publishing: no token
3
+ # is stored; configure the project on PyPI first), then creates the GitHub release.
4
+ on:
5
+ push:
6
+ tags: ["v*"]
7
+ jobs:
8
+ build:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: astral-sh/setup-uv@v5
13
+ with: { enable-cache: true }
14
+ - run: uv sync --all-groups --locked
15
+ - run: uv run poe check
16
+ - name: The tag must match the package version
17
+ run: test "v$(uv run python -c 'import importlib.metadata as m; print(m.version("whiletrue"))')" = "${GITHUB_REF_NAME}"
18
+ - run: uv build
19
+ - uses: actions/upload-artifact@v4
20
+ with: { name: dist, path: dist/ }
21
+ publish:
22
+ needs: build
23
+ runs-on: ubuntu-latest
24
+ environment: pypi
25
+ permissions:
26
+ id-token: write
27
+ steps:
28
+ - uses: actions/download-artifact@v4
29
+ with: { name: dist, path: dist/ }
30
+ - uses: pypa/gh-action-pypi-publish@release/v1
31
+ github-release:
32
+ needs: publish
33
+ runs-on: ubuntu-latest
34
+ permissions:
35
+ contents: write
36
+ steps:
37
+ - uses: actions/checkout@v4
38
+ - uses: actions/download-artifact@v4
39
+ with: { name: dist, path: dist/ }
40
+ - run: gh release create "$GITHUB_REF_NAME" dist/* --title "$GITHUB_REF_NAME" --notes-file CHANGELOG.md
41
+ env: { GH_TOKEN: "${{ github.token }}" }
@@ -0,0 +1,20 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ .venv/
4
+ dist/
5
+ .coverage
6
+ coverage/
7
+ .pytest_cache/
8
+ .ruff_cache/
9
+ .whiletrue/
10
+ .env
11
+ .env.*
12
+ .DS_Store
13
+ *.log
14
+
15
+ # devenv / direnv
16
+ .devenv*
17
+ devenv.local.nix
18
+ devenv.local.yaml
19
+ .direnv/
20
+ human-test/
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 (first release)
4
+
5
+ whiletrue runs configurable pipelines of agentic and deterministic steps around coding agents.
6
+
7
+ **Engine**
8
+ - Typed modules with outcome ports (`ok`, `fail`, `needs_human`, `skip`, `rejected`), a plugin API (entry points), a static validator, and a SQLite-backed runtime with an append-only event log.
9
+ - Control flow: `sequence`, `tap`, `loop`, `map` (optionally parallel), `parallel`, `switch`, `retry`, `try`; CEL expressions; composites with params and ports; recipes `ralph`, `review-pass`, `review-respond`, `issue-loop`.
10
+ - Reproducibility: `whiletrue.lock`, run hashes, result cache, record and `replay`.
11
+ - Parallel items with dependencies, `max_agents`, an item state machine, workspaces (git worktree, directory copy), crash recovery, and `resume`, `rerun`, `cancel`, `logs`, `cost`.
12
+
13
+ **Agent backends**
14
+ - Claude Code: headless (`claude -p`) and interactive (live tmux panes with hooks, an MCP result tool, limits without headless flags, steering).
15
+ - opencode and Codex CLI runners, with structured output and session resume.
16
+
17
+ **People in the loop**
18
+ - `human.approve` gates with park/resume, approve/reject with notes, wake conditions (CLI, file, timer, GitHub review/merge), per-item history, comments that must be answered (`[whiletrue]`-prefixed replies, never resolving human threads), lessons proposed from rejections and steers that need approval, and a tmux control panel.
19
+
20
+ **Integrations**
21
+ - GitHub through the `gh` CLI: issues as items (blocked-by as dependencies, `spec:` links), PRs, sync with base, merge under a lock, review-comment replies. A file-backed fake GitHub for dry runs.
22
+
23
+ **Known limits**
24
+ - The Codex success path has not been run against a live account in CI (only its failure path and a stand-in); the real-GitHub path has been exercised only through a stand-in `gh`.
25
+ - A watching gate keeps its parallel slot; locks are per process; interactive agents ask to trust each new worktree once.
@@ -0,0 +1,19 @@
1
+ # whiletrue — agent guide
2
+
3
+ Local Python orchestrator that runs pipelines around coding agents. Design: `docs/architecture.md`. Plan: `docs/plan.md`. Work order: `docs/todo.md` (numbered; do items in order, tick when done).
4
+
5
+ ## Commands
6
+
7
+ Use uv inside the devenv shell (`devenv.nix`, same format as `~/dotfiles/devenv/python`): `devenv shell -- uv run poe <task>`, or `direnv allow` once and run `poe <task>` / `pytest` directly (the venv is `.devenv/state/venv`).
8
+
9
+ - `poe check` — format check, lint, typecheck, tests with coverage, docs check (run before every commit)
10
+ - `poe test` / `poe coverage` / `poe typecheck` / `poe lint` / `poe format` / `poe docs-check`
11
+
12
+ ## Rules (see `docs/conventions.md`)
13
+
14
+ - TDD; unit tests in `tests/unit/<pkg>/`, cross-package tests in `tests/integration/` (never beside source); coverage floor is `fail_under` in `pyproject.toml`, ratchet it up, never down.
15
+ - Update user docs and `docs/architecture.md` in the same change as behavior.
16
+ - `whiletrue.core` must not import git, GitHub, tmux, or any agent. Built-ins use only the public plugin API.
17
+ - Track work in `docs/todo.md` (no GitHub issues for now). One todo item (or small group) per commit/PR. The human reviews every line before merge.
18
+ - Never commit or push without showing the user the diff and getting explicit approval.
19
+ - Commit trailer: `Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>`.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Darius Singh
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.
@@ -0,0 +1,48 @@
1
+ Metadata-Version: 2.5
2
+ Name: whiletrue
3
+ Version: 0.1.0
4
+ Summary: Run configurable loops of agentic and deterministic steps around coding agents.
5
+ Project-URL: Repository, https://github.com/dariussingh/whiletrue
6
+ Project-URL: Changelog, https://github.com/dariussingh/whiletrue/blob/main/CHANGELOG.md
7
+ Project-URL: Documentation, https://github.com/dariussingh/whiletrue/tree/main/docs
8
+ Author: Darius Singh
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,claude-code,codex,opencode,orchestration,pipelines,ralph
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Operating System :: POSIX
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Software Development :: Build Tools
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.12
21
+ Requires-Dist: common-expression-language<1,>=0.10
22
+ Requires-Dist: pydantic<3,>=2.9
23
+ Requires-Dist: pyyaml<7,>=6
24
+ Description-Content-Type: text/markdown
25
+
26
+ # whiletrue
27
+
28
+ A local, single-machine Python orchestrator that runs configurable pipelines of agentic and deterministic steps around coding agents such as Claude Code and opencode.
29
+
30
+ > LangGraph builds the agent; whiletrue runs the loop around agents you already have.
31
+
32
+ **Status:** M0 (core engine), M1 (control flow, composites, recipes, replay), M2 (interactive Claude Code in tmux panes) M3 (parallel items in git worktrees, crash recovery) and M4 (GitHub issues and PRs, human gates, review comments, opencode) are built in Python. `whiletrue init | validate | plan | run | resume | rerun | cancel | logs | cost | status | lock | replay | attach | panel | approve | reject | comment | history | learnings` work with the headless and interactive Claude Code runners and opencode. Start with the [reference pipeline](examples/issue-loop/README.md). See [`docs/`](docs/README.md): [getting started](docs/getting-started.md), [authoring guide](docs/authoring.md), [CLI](docs/cli.md), [reference](docs/reference.md), [architecture](docs/architecture.md), [plan](docs/plan.md), [todo](docs/todo.md).
33
+
34
+ ## Development
35
+
36
+ See [developing.md](docs/developing.md) and, to extend whiletrue, [plugins.md](docs/plugins.md).
37
+
38
+ Requires [devenv](https://devenv.sh) (or Python 3.12 + [uv](https://docs.astral.sh/uv/)).
39
+
40
+ ```bash
41
+ direnv allow # or: devenv shell
42
+ poe check # format check, lint, pyright, tests + coverage, docs check
43
+ whiletrue --help # the CLI, installed editable into .devenv/state/venv
44
+ ```
45
+
46
+ ## License
47
+
48
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,23 @@
1
+ # whiletrue
2
+
3
+ A local, single-machine Python orchestrator that runs configurable pipelines of agentic and deterministic steps around coding agents such as Claude Code and opencode.
4
+
5
+ > LangGraph builds the agent; whiletrue runs the loop around agents you already have.
6
+
7
+ **Status:** M0 (core engine), M1 (control flow, composites, recipes, replay), M2 (interactive Claude Code in tmux panes) M3 (parallel items in git worktrees, crash recovery) and M4 (GitHub issues and PRs, human gates, review comments, opencode) are built in Python. `whiletrue init | validate | plan | run | resume | rerun | cancel | logs | cost | status | lock | replay | attach | panel | approve | reject | comment | history | learnings` work with the headless and interactive Claude Code runners and opencode. Start with the [reference pipeline](examples/issue-loop/README.md). See [`docs/`](docs/README.md): [getting started](docs/getting-started.md), [authoring guide](docs/authoring.md), [CLI](docs/cli.md), [reference](docs/reference.md), [architecture](docs/architecture.md), [plan](docs/plan.md), [todo](docs/todo.md).
8
+
9
+ ## Development
10
+
11
+ See [developing.md](docs/developing.md) and, to extend whiletrue, [plugins.md](docs/plugins.md).
12
+
13
+ Requires [devenv](https://devenv.sh) (or Python 3.12 + [uv](https://docs.astral.sh/uv/)).
14
+
15
+ ```bash
16
+ direnv allow # or: devenv shell
17
+ poe check # format check, lint, pyright, tests + coverage, docs check
18
+ whiletrue --help # the CLI, installed editable into .devenv/state/venv
19
+ ```
20
+
21
+ ## License
22
+
23
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,131 @@
1
+ {
2
+ "nodes": {
3
+ "devenv": {
4
+ "locked": {
5
+ "dir": "src/modules",
6
+ "lastModified": 1792016320,
7
+ "owner": "cachix",
8
+ "repo": "devenv",
9
+ "rev": "03582faca930c95cb28d5d3cd2370325b0072fde",
10
+ "type": "github"
11
+ },
12
+ "original": {
13
+ "dir": "src/modules",
14
+ "owner": "cachix",
15
+ "repo": "devenv",
16
+ "type": "github"
17
+ }
18
+ },
19
+ "flake-compat": {
20
+ "flake": false,
21
+ "locked": {
22
+ "lastModified": 1767039857,
23
+ "owner": "NixOS",
24
+ "repo": "flake-compat",
25
+ "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
26
+ "type": "github"
27
+ },
28
+ "original": {
29
+ "owner": "NixOS",
30
+ "repo": "flake-compat",
31
+ "type": "github"
32
+ }
33
+ },
34
+ "flake-compat_2": {
35
+ "flake": false,
36
+ "locked": {
37
+ "lastModified": 1767039857,
38
+ "owner": "edolstra",
39
+ "repo": "flake-compat",
40
+ "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
41
+ "type": "github"
42
+ },
43
+ "original": {
44
+ "owner": "edolstra",
45
+ "repo": "flake-compat",
46
+ "type": "github"
47
+ }
48
+ },
49
+ "git-hooks": {
50
+ "inputs": {
51
+ "flake-compat": "flake-compat",
52
+ "nixpkgs": [
53
+ "nixpkgs"
54
+ ]
55
+ },
56
+ "locked": {
57
+ "lastModified": 1791909798,
58
+ "owner": "cachix",
59
+ "repo": "git-hooks.nix",
60
+ "rev": "1ba1dbfe28738c9a71c266be6efa5b89e75491a9",
61
+ "type": "github"
62
+ },
63
+ "original": {
64
+ "owner": "cachix",
65
+ "repo": "git-hooks.nix",
66
+ "type": "github"
67
+ }
68
+ },
69
+ "nixpkgs": {
70
+ "locked": {
71
+ "lastModified": 1791637130,
72
+ "owner": "NixOS",
73
+ "repo": "nixpkgs",
74
+ "rev": "ca1659429c950a11a565b5764e37a1b704e17ec8",
75
+ "type": "github"
76
+ },
77
+ "original": {
78
+ "owner": "NixOS",
79
+ "ref": "nixpkgs-unstable",
80
+ "repo": "nixpkgs",
81
+ "type": "github"
82
+ }
83
+ },
84
+ "nixpkgs-python": {
85
+ "inputs": {
86
+ "flake-compat": "flake-compat_2",
87
+ "nixpkgs": "nixpkgs_2"
88
+ },
89
+ "locked": {
90
+ "lastModified": 1791208659,
91
+ "owner": "cachix",
92
+ "repo": "nixpkgs-python",
93
+ "rev": "5821ac5267b0dc89e48705407206e3c88ee3e0ad",
94
+ "type": "github"
95
+ },
96
+ "original": {
97
+ "owner": "cachix",
98
+ "repo": "nixpkgs-python",
99
+ "type": "github"
100
+ }
101
+ },
102
+ "nixpkgs_2": {
103
+ "locked": {
104
+ "lastModified": 1782847189,
105
+ "owner": "NixOS",
106
+ "repo": "nixpkgs",
107
+ "rev": "b6018f87da91d19d0ab4cf979885689b469cdd41",
108
+ "type": "github"
109
+ },
110
+ "original": {
111
+ "owner": "NixOS",
112
+ "ref": "nixos-25.11",
113
+ "repo": "nixpkgs",
114
+ "type": "github"
115
+ }
116
+ },
117
+ "root": {
118
+ "inputs": {
119
+ "devenv": "devenv",
120
+ "git-hooks": "git-hooks",
121
+ "nixpkgs": "nixpkgs",
122
+ "nixpkgs-python": "nixpkgs-python",
123
+ "pre-commit-hooks": [
124
+ "git-hooks"
125
+ ]
126
+ }
127
+ }
128
+ },
129
+ "root": "root",
130
+ "version": 7
131
+ }
@@ -0,0 +1,28 @@
1
+ {
2
+ pkgs,
3
+ ...
4
+ }:
5
+ {
6
+ packages = with pkgs; [
7
+ git
8
+ gh
9
+ tmux
10
+ ];
11
+
12
+ languages.python = {
13
+ enable = true;
14
+ version = "3.12";
15
+ uv = {
16
+ enable = true;
17
+ sync.enable = true;
18
+ sync.allGroups = true;
19
+ };
20
+ };
21
+
22
+ scripts.check.exec = "uv run poe check";
23
+
24
+ enterShell = ''
25
+ . .devenv/state/venv/bin/activate
26
+ echo "whiletrue devenv: $(python --version), uv $(uv --version | cut -d' ' -f2)"
27
+ '';
28
+ }
@@ -0,0 +1,13 @@
1
+ inputs:
2
+ nixpkgs:
3
+ url: github:NixOS/nixpkgs/nixpkgs-unstable
4
+ nixpkgs-python:
5
+ url: github:cachix/nixpkgs-python
6
+
7
+ # If you're willing to use a package that's vulnerable
8
+ # permittedInsecurePackages:
9
+ # - "openssl-1.1.1w"
10
+
11
+ # If you have more than one devenv you can merge them
12
+ #imports:
13
+ # - ./backend
@@ -0,0 +1,18 @@
1
+ # whiletrue docs
2
+
3
+ | Doc | Purpose |
4
+ | -------------------------------------- | --------------------------------------------------------------------------------- |
5
+ | [architecture.md](architecture.md) | Full design: core model, runtime, state, agents, human gates, packages |
6
+ | [getting-started.md](getting-started.md) | User guide: install, first loop, commands, exit codes, safety defaults |
7
+ | [authoring.md](authoring.md) | Authoring guide: pipelines, composites, agents, choosing a backend |
8
+ | [cli.md](cli.md) | CLI reference: every command, option, exit code and environment variable |
9
+ | [reference.md](reference.md) | User reference: modules, control flow, expressions, composites, recipes, replay |
10
+ | [plugins.md](plugins.md) | Extending whiletrue: modules, strategies, runners, caps, entry points |
11
+ | [developing.md](developing.md) | Contributing: setup, layout, run flow, workflow |
12
+ | [plan.md](plan.md) | Implementation plan: milestones M0–M4, dependencies, exit criteria, risks, spikes |
13
+ | [todo.md](todo.md) | Numbered, ordered implementation checklist (work top to bottom) |
14
+ | [open-questions.md](open-questions.md) | Undecided design questions, each tied to the milestone that forces the decision |
15
+ | [spike-interactive.md](spike-interactive.md) | Findings: plugin hooks and MCP in interactive Claude Code (OQ-1) |
16
+ | [conventions.md](conventions.md) | Engineering conventions, test and docs rules (the non-negotiables made concrete) |
17
+
18
+ Non-negotiables (every change must honor them): human keeps context; maximal test coverage; user and architecture docs stay current; human is accountable for every line.