whiletrue 0.1.0__tar.gz → 0.1.1__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.
- {whiletrue-0.1.0 → whiletrue-0.1.1}/CHANGELOG.md +5 -0
- whiletrue-0.1.1/PKG-INFO +268 -0
- whiletrue-0.1.1/README.md +243 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/README.md +1 -0
- whiletrue-0.1.1/docs/assets/architecture.svg +48 -0
- whiletrue-0.1.1/docs/assets/demo-real.svg +1 -0
- whiletrue-0.1.1/docs/assets/issue-loop.svg +17 -0
- whiletrue-0.1.1/docs/assets/logo.svg +7 -0
- whiletrue-0.1.1/docs/assets/ralph-loop.svg +17 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/getting-started.md +2 -0
- whiletrue-0.1.1/docs/tutorial.md +250 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/pyproject.toml +3 -3
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/tmux/test_controller.py +37 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/uv.lock +1 -1
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/tmux/controller.py +13 -0
- whiletrue-0.1.0/PKG-INFO +0 -48
- whiletrue-0.1.0/README.md +0 -23
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.editorconfig +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.envrc +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.github/ISSUE_TEMPLATE/task.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.github/pull_request_template.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.github/workflows/ci.yml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.github/workflows/release.yml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/.gitignore +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/CLAUDE.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/LICENSE +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/devenv.lock +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/devenv.nix +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/devenv.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/architecture.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/authoring.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/cli.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/conventions.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/developing.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/m0-smoke.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/open-questions.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/plan.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/plugins.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/reference.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/spike-interactive.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/docs/todo.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/examples/issue-loop/README.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/examples/issue-loop/agents/fix.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/examples/issue-loop/agents/implement.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/examples/issue-loop/agents/respond.md +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/examples/issue-loop/whiletrue.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/scripts/docs_check.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/conftest.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/fixtures/fake_interactive_claude.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_cli.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_cli_surface.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_gates_cli.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_interactive_run.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_issue_loop.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_m3_exit.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_ops_cli.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/integration/test_recipes.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/live/test_live_backends.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_agent.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_exec.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_gates.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_history.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_human.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_json_source.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_markdown_source.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_plugin.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_process.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_sessions.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/basics/test_shell.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_endpoint.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_headless.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_interactive.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_panes.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_plugin_scripts.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_session.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/claude_code/test_transcript.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/codex/test_runner.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/control/test_control.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_cache.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_caps.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_composite.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_config.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_context.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_duration.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_events.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_expr.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_history_store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_lock.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_memory_store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_module.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_outcomes.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_registry.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_replay.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_runtime.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_template.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_validate.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/core/test_wake.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/git/test_git.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/github/test_client.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/github/test_filebacked.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/github/test_plugin.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/github/test_specs.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/opencode/test_runner.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/store_sqlite/test_sqlite_store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/test_abort.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/test_architecture.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/tests/unit/test_panel.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/__main__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/abort.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/agent.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/comments.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/diff_size.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/exec_.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/history.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/human.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/json_source.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/markdown_source.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/process.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/sessions.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/set_.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/shell.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/basics/wake.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/endpoint.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/headless.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/interactive.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/learnings.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/panes.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/plugin/.claude-plugin/plugin.json +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/plugin/hook.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/plugin/hooks/hooks.json +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/plugin/mcp_server.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/session.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/claude_code/transcript.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/__main__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/app.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/common.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/gates.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/ops.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/panel.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/registry.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/cli/templates.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/codex/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/codex/runner.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/chain.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/loop.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/map_.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/parallel.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/retry.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/sequence.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/control/switch.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/caps.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/comments.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/composite.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/config.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/context.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/duration.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/events.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/expr.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/history.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/lock.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/memory_store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/module.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/outcomes.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/registry.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/replay.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/runner.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/runtime.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/source.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/template.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/validate.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/wake.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/core/workspace.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/git/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/git/modules.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/git/workspaces.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/client.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/filebacked.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/memory.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/plugin.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/github/specs.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/opencode/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/opencode/runner.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/py.typed +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/recipes/issue-loop.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/recipes/ralph.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/recipes/review-pass.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/recipes/review-respond.yaml +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/store_sqlite/__init__.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/store_sqlite/migrations.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/store_sqlite/sqlite_store.py +0 -0
- {whiletrue-0.1.0 → whiletrue-0.1.1}/whiletrue/tmux/__init__.py +0 -0
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.1
|
|
4
|
+
|
|
5
|
+
- Fixed: parallel interactive items raced to create the tmux session. The loser failed with `duplicate session` and that error was fed to the agent as its previous failure. Session and pane creation now run one at a time, and parallel agents share one window grid.
|
|
6
|
+
- Docs: a new README with a recording of a real run, architecture and flow diagrams, and a step-by-step tutorial (`docs/tutorial.md`).
|
|
7
|
+
|
|
3
8
|
## 0.1.0 (first release)
|
|
4
9
|
|
|
5
10
|
whiletrue runs configurable pipelines of agentic and deterministic steps around coding agents.
|
whiletrue-0.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: whiletrue
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Local orchestrator that runs pipelines of agent and deterministic steps around Claude Code, opencode and Codex, with gates, human approval, parallel git worktrees and crash-safe resume.
|
|
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,ai-agents,claude-code,codex,coding-agents,git-worktree,human-in-the-loop,opencode,orchestration,pipelines,ralph,tmux
|
|
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
|
+
<div align="center">
|
|
27
|
+
|
|
28
|
+
<img src="docs/assets/logo.svg" alt="whiletrue logo" width="96" height="96">
|
|
29
|
+
|
|
30
|
+
# whiletrue
|
|
31
|
+
|
|
32
|
+
**The loop around your coding agents.**
|
|
33
|
+
|
|
34
|
+
Run pipelines of agentic and deterministic steps around Claude Code, opencode and Codex, locally, with gates, humans in the loop, and crash-safe resume.
|
|
35
|
+
|
|
36
|
+
[](https://pypi.org/project/whiletrue/)
|
|
37
|
+
[](https://pypi.org/project/whiletrue/)
|
|
38
|
+
[](LICENSE)
|
|
39
|
+
[](docs/README.md)
|
|
40
|
+
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
> LangGraph builds the agent; whiletrue runs the loop around agents you already have.
|
|
44
|
+
|
|
45
|
+
<div align="center">
|
|
46
|
+
|
|
47
|
+
<img src="docs/assets/demo-real.svg" alt="Recording of a real run: two Claude Code agents work in parallel in tmux panes while a control panel and shell show status, both items pass their pytest gate and park for human approval, then approve and resume finish them" width="900">
|
|
48
|
+
|
|
49
|
+
<sub>A real run, not a mock-up: two Claude Code agents in parallel, a pytest gate, a human approval and a resume, about $0.23 in total. Captured from the live tmux panes; the two tmux windows are drawn side by side.</sub>
|
|
50
|
+
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
uvx whiletrue init # scaffold a Ralph loop
|
|
55
|
+
uvx whiletrue run # agent -> pytest gate -> repeat until green
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Overview
|
|
59
|
+
|
|
60
|
+
Coding agents are good at one task and bad at finishing a backlog unattended. whiletrue is the orchestrator you put around them. You describe the loop in a single `whiletrue.yaml`: which agent does the work, which deterministic gate checks it, when to retry, when to ask a person. whiletrue validates the config before spending a token, runs it, and records every step so you can inspect, replay or resume it.
|
|
61
|
+
|
|
62
|
+
- **Pipelines, not prompts.** Agent steps, shell and git steps, and gates compose with `sequence`, `loop`, `map`, `parallel`, `switch`, `retry`, `try` and `human.approve`. Every loop is bounded.
|
|
63
|
+
- **Any backend.** `claude-code-headless`, `claude-code` (the real interactive CLI in a tmux pane you can type into), `opencode` and `codex`. Mix them in one pipeline.
|
|
64
|
+
- **Many items at once.** One item per task or GitHub issue, each in its own git worktree, with `parallel: N` and a cap on live agent sessions.
|
|
65
|
+
- **Humans in the loop.** A gate parks an item until a person approves, rejects or comments; other items keep running. Every review comment gets an answer.
|
|
66
|
+
- **Durable.** State lives in SQLite. Kill the process at any point and `whiletrue resume` replays finished steps instead of redoing them; side effects (PRs, merges, replies) happen exactly once.
|
|
67
|
+
- **Local.** One machine, no server, no account. Everything is a file in your repo plus `.whiletrue/`.
|
|
68
|
+
|
|
69
|
+
## Contents
|
|
70
|
+
|
|
71
|
+
- [Install](#install)
|
|
72
|
+
- [Quickstart](#quickstart)
|
|
73
|
+
- [Architecture](#architecture)
|
|
74
|
+
- [Concepts](#concepts)
|
|
75
|
+
- [Examples](#examples)
|
|
76
|
+
- [Backends](#backends)
|
|
77
|
+
- [CLI](#cli)
|
|
78
|
+
- [Documentation](#documentation)
|
|
79
|
+
- [Development](#development)
|
|
80
|
+
- [License](#license)
|
|
81
|
+
|
|
82
|
+
## Install
|
|
83
|
+
|
|
84
|
+
Requires Python 3.12+ and at least one agent CLI on your `PATH` ([Claude Code](https://claude.com/claude-code), [opencode](https://opencode.ai) or [Codex](https://github.com/openai/codex)). `git` is needed for worktrees, `tmux` for interactive agents, and `gh` for the GitHub integration.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
uv tool install whiletrue # or: pip install whiletrue
|
|
88
|
+
whiletrue --help
|
|
89
|
+
|
|
90
|
+
uvx whiletrue --help # or run it without installing
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
If an agent CLI is not on `PATH`, set `WHILETRUE_CLAUDE_BIN`, `WHILETRUE_OPENCODE_BIN` or `WHILETRUE_CODEX_BIN`.
|
|
94
|
+
|
|
95
|
+
## Quickstart
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
cd my-project
|
|
99
|
+
whiletrue init # writes whiletrue.yaml and agents/ralph.md
|
|
100
|
+
whiletrue validate # config, wiring, limits and safety rules; spends nothing
|
|
101
|
+
whiletrue plan # prints the expanded step tree; spends nothing
|
|
102
|
+
whiletrue run # runs it
|
|
103
|
+
whiletrue status # steps, outcomes and cost of the latest run
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
The scaffold is a Ralph loop. The agent runs in a fresh context, a deterministic `pytest` gate checks the result, and the loop repeats (at most 5 times) until the gate is green:
|
|
107
|
+
|
|
108
|
+
```yaml
|
|
109
|
+
# whiletrue.yaml
|
|
110
|
+
name: ralph
|
|
111
|
+
pipeline:
|
|
112
|
+
loop:
|
|
113
|
+
max: 5 # every loop is bounded; `max: unbounded` is an explicit opt-out
|
|
114
|
+
do:
|
|
115
|
+
- agent: { uses: ./agents/ralph.md }
|
|
116
|
+
- gate.shell: { run: "pytest" }
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
```markdown
|
|
120
|
+
---
|
|
121
|
+
# agents/ralph.md
|
|
122
|
+
agent: ralph
|
|
123
|
+
runner: claude-code-headless
|
|
124
|
+
permission_mode: acceptEdits
|
|
125
|
+
tools: [Read, Edit, Write, "Bash(pytest*)", "Bash(git *)"]
|
|
126
|
+
limits: { budget_usd: 2, turns: 40, wall: 20m }
|
|
127
|
+
---
|
|
128
|
+
Work through the next unfinished item in TODO.md. Make the tests pass.
|
|
129
|
+
|
|
130
|
+
Failure output from the previous attempt (empty on the first try):
|
|
131
|
+
{{iter.previous}}
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Every agent must declare `limits`; `validate` refuses the config otherwise.
|
|
135
|
+
|
|
136
|
+
## Architecture
|
|
137
|
+
|
|
138
|
+
<img src="docs/assets/architecture.svg" alt="Architecture: whiletrue.yaml and the CLI drive the core engine (loader, scheduler, pipeline runtime, park and resume, plugin registry, SQLite store); built-in plugins connect it to agent CLIs, git, GitHub and tmux" width="900">
|
|
139
|
+
|
|
140
|
+
The core knows nothing about git, GitHub, tmux or any agent. Every integration is a plugin built on the public plugin API, so you can add your own ([plugins](docs/plugins.md), [architecture](docs/architecture.md)).
|
|
141
|
+
|
|
142
|
+
## Concepts
|
|
143
|
+
|
|
144
|
+
| Concept | What it is |
|
|
145
|
+
| --- | --- |
|
|
146
|
+
| **Pipeline** | A list of steps, or one strategy, in `whiletrue.yaml`. |
|
|
147
|
+
| **Step** | An action: `agent`, a shell command, a git or GitHub operation, a gate. Pure, deterministic, agentic or side-effecting. |
|
|
148
|
+
| **Strategy** | Control flow over steps: `sequence`, `tap`, `loop`, `map`, `parallel`, `switch`, `retry`, `try`, `human.approve`. |
|
|
149
|
+
| **Outcome ports** | Every step ends on `ok`, `fail`, `needs_human`, `skip` or `rejected`. `wires:` routes a port to another step; back-wires make loops. |
|
|
150
|
+
| **Item** | One unit of work from a `source:` (`json`, `markdown_tasks`, `github_issues`). Items run in parallel, in dependency order. |
|
|
151
|
+
| **Workspace** | Per-item checkout: `git-worktree`, `dir-copy` or `none`. |
|
|
152
|
+
| **Gate** | A deterministic check, or a human decision, that an item must pass. |
|
|
153
|
+
| **Recipe** | A ready-made composite: `ralph`, `review-pass`, `review-respond`, `issue-loop`. |
|
|
154
|
+
| **Run record** | The SQLite log of steps, parks, effects, comments and cost that makes replay and resume possible. |
|
|
155
|
+
|
|
156
|
+
Details: [reference](docs/reference.md), [authoring guide](docs/authoring.md), [architecture](docs/architecture.md).
|
|
157
|
+
|
|
158
|
+
## Examples
|
|
159
|
+
|
|
160
|
+
### A Ralph loop
|
|
161
|
+
|
|
162
|
+
<img src="docs/assets/ralph-loop.svg" alt="Ralph loop: agent in a fresh context, then a pytest gate; green ends the loop, red feeds the output back to the agent" width="900">
|
|
163
|
+
|
|
164
|
+
This is what `whiletrue init` scaffolds. See the YAML under [Quickstart](#quickstart).
|
|
165
|
+
|
|
166
|
+
### Review loop with a read-only reviewer
|
|
167
|
+
|
|
168
|
+
```yaml
|
|
169
|
+
pipeline:
|
|
170
|
+
composite:
|
|
171
|
+
uses: "recipe:review-pass"
|
|
172
|
+
params: { reviewer: ./agents/review.md, fixer: ./agents/fix.md, max_rounds: 3 }
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### A backlog in parallel worktrees
|
|
176
|
+
|
|
177
|
+
```yaml
|
|
178
|
+
parallel: 4
|
|
179
|
+
max_agents: 4
|
|
180
|
+
source: { markdown_tasks: { path: TASKS.md } } # - [ ] Title {#id after=other}
|
|
181
|
+
workspace: { git-worktree: { branch: "wt/{{item.id}}" } }
|
|
182
|
+
pipeline:
|
|
183
|
+
loop:
|
|
184
|
+
max: 5
|
|
185
|
+
do:
|
|
186
|
+
- agent: { uses: ./agents/implement.md }
|
|
187
|
+
- gate.shell: { run: "pytest" }
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### A human gate on a pull request
|
|
191
|
+
|
|
192
|
+
```yaml
|
|
193
|
+
- id: review
|
|
194
|
+
human.approve:
|
|
195
|
+
what: pr
|
|
196
|
+
wake: { any: [cli, { github.pr_review: any }] }
|
|
197
|
+
do:
|
|
198
|
+
- composite: { uses: "recipe:review-respond", params: { responder: ./agents/respond.md } }
|
|
199
|
+
wires: { rejected: fix }
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
whiletrue run # parks at the gate and exits with code 2
|
|
204
|
+
whiletrue status # lists what is waiting
|
|
205
|
+
whiletrue approve 12 # or: reject 12 --note "what to change"
|
|
206
|
+
whiletrue resume # finished steps are replayed, never redone
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### The reference pipeline: issues with a human in the loop
|
|
210
|
+
|
|
211
|
+
[`examples/issue-loop`](examples/issue-loop/README.md) takes every issue in a GitHub milestone from open to merged: implement in a worktree, run the gate, open a PR, answer review comments, merge, close. You review every PR, and every comment you leave gets an answer.
|
|
212
|
+
|
|
213
|
+
<img src="docs/assets/issue-loop.svg" alt="Issue loop flow: implement with retry and a gate, open a PR, a human review gate with comment replies and a fix branch on rejection, then sync, a merge approval and the merge" width="900">
|
|
214
|
+
|
|
215
|
+
## Backends
|
|
216
|
+
|
|
217
|
+
Choose per agent with `runner:`.
|
|
218
|
+
|
|
219
|
+
| Runner | Runs | Notes |
|
|
220
|
+
| --- | --- | --- |
|
|
221
|
+
| `claude-code-headless` | `claude -p` | Default. Budget, turns and wall limits enforced. |
|
|
222
|
+
| `claude-code` | Interactive Claude Code in a tmux pane | Watch it, type into it (recorded as a *steer*). Submits through a bundled MCP tool and hooks. |
|
|
223
|
+
| `opencode` | `opencode run` | Structured output checked against the step's cap. |
|
|
224
|
+
| `codex` | `codex exec` | Sandbox derived from `permission_mode`. No budget enforcement. |
|
|
225
|
+
|
|
226
|
+
Structured `outputs:` work on all of them. See [choosing a backend](docs/authoring.md#choosing-a-backend).
|
|
227
|
+
|
|
228
|
+
## CLI
|
|
229
|
+
|
|
230
|
+
| Command | Purpose |
|
|
231
|
+
| --- | --- |
|
|
232
|
+
| `init`, `validate`, `plan` | Scaffold, check and preview a pipeline without spending tokens. |
|
|
233
|
+
| `run`, `resume`, `rerun`, `cancel` | Start, continue after a park or crash, redo, or stop items. |
|
|
234
|
+
| `status`, `logs`, `cost`, `replay` | Inspect runs, steps and spend; replay a recorded run. |
|
|
235
|
+
| `approve`, `reject`, `comment` | Decide human gates and talk to waiting items. |
|
|
236
|
+
| `attach`, `panel` | Open the tmux session and the live control panel. |
|
|
237
|
+
| `history`, `learnings` | Audit trail and approved lessons for future agents. |
|
|
238
|
+
| `lock` | Show or clear the run lock. |
|
|
239
|
+
|
|
240
|
+
Full reference: [docs/cli.md](docs/cli.md). New here? Follow the [tutorial](docs/tutorial.md).
|
|
241
|
+
|
|
242
|
+
## Documentation
|
|
243
|
+
|
|
244
|
+
Start at [docs/README.md](docs/README.md).
|
|
245
|
+
|
|
246
|
+
- [Tutorial](docs/tutorial.md): from an empty folder to your own loop with gates, a reviewer, parallel tasks and a human approval.
|
|
247
|
+
- [Getting started](docs/getting-started.md): a longer walkthrough, including interactive agents, gates and parallel items.
|
|
248
|
+
- [Authoring guide](docs/authoring.md): writing pipelines and agents.
|
|
249
|
+
- [Reference](docs/reference.md): every module, strategy, provider and config key.
|
|
250
|
+
- [CLI](docs/cli.md) and [plugins](docs/plugins.md): the command line and extending whiletrue.
|
|
251
|
+
- [Architecture](docs/architecture.md), [plan](docs/plan.md), [todo](docs/todo.md) and [changelog](CHANGELOG.md).
|
|
252
|
+
|
|
253
|
+
## Development
|
|
254
|
+
|
|
255
|
+
Requires [devenv](https://devenv.sh) (or Python 3.12 + [uv](https://docs.astral.sh/uv/)). See [developing.md](docs/developing.md).
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
git clone https://github.com/dariussingh/whiletrue && cd whiletrue
|
|
259
|
+
direnv allow # or: devenv shell
|
|
260
|
+
poe check # format check, lint, pyright, tests + coverage, docs check
|
|
261
|
+
whiletrue --help # installed editable into .devenv/state/venv
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
Live tests against real agent CLIs are opt-in: `WHILETRUE_LIVE=1 uv run pytest tests/live -v`.
|
|
265
|
+
|
|
266
|
+
## License
|
|
267
|
+
|
|
268
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
<img src="docs/assets/logo.svg" alt="whiletrue logo" width="96" height="96">
|
|
4
|
+
|
|
5
|
+
# whiletrue
|
|
6
|
+
|
|
7
|
+
**The loop around your coding agents.**
|
|
8
|
+
|
|
9
|
+
Run pipelines of agentic and deterministic steps around Claude Code, opencode and Codex, locally, with gates, humans in the loop, and crash-safe resume.
|
|
10
|
+
|
|
11
|
+
[](https://pypi.org/project/whiletrue/)
|
|
12
|
+
[](https://pypi.org/project/whiletrue/)
|
|
13
|
+
[](LICENSE)
|
|
14
|
+
[](docs/README.md)
|
|
15
|
+
|
|
16
|
+
</div>
|
|
17
|
+
|
|
18
|
+
> LangGraph builds the agent; whiletrue runs the loop around agents you already have.
|
|
19
|
+
|
|
20
|
+
<div align="center">
|
|
21
|
+
|
|
22
|
+
<img src="docs/assets/demo-real.svg" alt="Recording of a real run: two Claude Code agents work in parallel in tmux panes while a control panel and shell show status, both items pass their pytest gate and park for human approval, then approve and resume finish them" width="900">
|
|
23
|
+
|
|
24
|
+
<sub>A real run, not a mock-up: two Claude Code agents in parallel, a pytest gate, a human approval and a resume, about $0.23 in total. Captured from the live tmux panes; the two tmux windows are drawn side by side.</sub>
|
|
25
|
+
|
|
26
|
+
</div>
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
uvx whiletrue init # scaffold a Ralph loop
|
|
30
|
+
uvx whiletrue run # agent -> pytest gate -> repeat until green
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Overview
|
|
34
|
+
|
|
35
|
+
Coding agents are good at one task and bad at finishing a backlog unattended. whiletrue is the orchestrator you put around them. You describe the loop in a single `whiletrue.yaml`: which agent does the work, which deterministic gate checks it, when to retry, when to ask a person. whiletrue validates the config before spending a token, runs it, and records every step so you can inspect, replay or resume it.
|
|
36
|
+
|
|
37
|
+
- **Pipelines, not prompts.** Agent steps, shell and git steps, and gates compose with `sequence`, `loop`, `map`, `parallel`, `switch`, `retry`, `try` and `human.approve`. Every loop is bounded.
|
|
38
|
+
- **Any backend.** `claude-code-headless`, `claude-code` (the real interactive CLI in a tmux pane you can type into), `opencode` and `codex`. Mix them in one pipeline.
|
|
39
|
+
- **Many items at once.** One item per task or GitHub issue, each in its own git worktree, with `parallel: N` and a cap on live agent sessions.
|
|
40
|
+
- **Humans in the loop.** A gate parks an item until a person approves, rejects or comments; other items keep running. Every review comment gets an answer.
|
|
41
|
+
- **Durable.** State lives in SQLite. Kill the process at any point and `whiletrue resume` replays finished steps instead of redoing them; side effects (PRs, merges, replies) happen exactly once.
|
|
42
|
+
- **Local.** One machine, no server, no account. Everything is a file in your repo plus `.whiletrue/`.
|
|
43
|
+
|
|
44
|
+
## Contents
|
|
45
|
+
|
|
46
|
+
- [Install](#install)
|
|
47
|
+
- [Quickstart](#quickstart)
|
|
48
|
+
- [Architecture](#architecture)
|
|
49
|
+
- [Concepts](#concepts)
|
|
50
|
+
- [Examples](#examples)
|
|
51
|
+
- [Backends](#backends)
|
|
52
|
+
- [CLI](#cli)
|
|
53
|
+
- [Documentation](#documentation)
|
|
54
|
+
- [Development](#development)
|
|
55
|
+
- [License](#license)
|
|
56
|
+
|
|
57
|
+
## Install
|
|
58
|
+
|
|
59
|
+
Requires Python 3.12+ and at least one agent CLI on your `PATH` ([Claude Code](https://claude.com/claude-code), [opencode](https://opencode.ai) or [Codex](https://github.com/openai/codex)). `git` is needed for worktrees, `tmux` for interactive agents, and `gh` for the GitHub integration.
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
uv tool install whiletrue # or: pip install whiletrue
|
|
63
|
+
whiletrue --help
|
|
64
|
+
|
|
65
|
+
uvx whiletrue --help # or run it without installing
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
If an agent CLI is not on `PATH`, set `WHILETRUE_CLAUDE_BIN`, `WHILETRUE_OPENCODE_BIN` or `WHILETRUE_CODEX_BIN`.
|
|
69
|
+
|
|
70
|
+
## Quickstart
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
cd my-project
|
|
74
|
+
whiletrue init # writes whiletrue.yaml and agents/ralph.md
|
|
75
|
+
whiletrue validate # config, wiring, limits and safety rules; spends nothing
|
|
76
|
+
whiletrue plan # prints the expanded step tree; spends nothing
|
|
77
|
+
whiletrue run # runs it
|
|
78
|
+
whiletrue status # steps, outcomes and cost of the latest run
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The scaffold is a Ralph loop. The agent runs in a fresh context, a deterministic `pytest` gate checks the result, and the loop repeats (at most 5 times) until the gate is green:
|
|
82
|
+
|
|
83
|
+
```yaml
|
|
84
|
+
# whiletrue.yaml
|
|
85
|
+
name: ralph
|
|
86
|
+
pipeline:
|
|
87
|
+
loop:
|
|
88
|
+
max: 5 # every loop is bounded; `max: unbounded` is an explicit opt-out
|
|
89
|
+
do:
|
|
90
|
+
- agent: { uses: ./agents/ralph.md }
|
|
91
|
+
- gate.shell: { run: "pytest" }
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```markdown
|
|
95
|
+
---
|
|
96
|
+
# agents/ralph.md
|
|
97
|
+
agent: ralph
|
|
98
|
+
runner: claude-code-headless
|
|
99
|
+
permission_mode: acceptEdits
|
|
100
|
+
tools: [Read, Edit, Write, "Bash(pytest*)", "Bash(git *)"]
|
|
101
|
+
limits: { budget_usd: 2, turns: 40, wall: 20m }
|
|
102
|
+
---
|
|
103
|
+
Work through the next unfinished item in TODO.md. Make the tests pass.
|
|
104
|
+
|
|
105
|
+
Failure output from the previous attempt (empty on the first try):
|
|
106
|
+
{{iter.previous}}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Every agent must declare `limits`; `validate` refuses the config otherwise.
|
|
110
|
+
|
|
111
|
+
## Architecture
|
|
112
|
+
|
|
113
|
+
<img src="docs/assets/architecture.svg" alt="Architecture: whiletrue.yaml and the CLI drive the core engine (loader, scheduler, pipeline runtime, park and resume, plugin registry, SQLite store); built-in plugins connect it to agent CLIs, git, GitHub and tmux" width="900">
|
|
114
|
+
|
|
115
|
+
The core knows nothing about git, GitHub, tmux or any agent. Every integration is a plugin built on the public plugin API, so you can add your own ([plugins](docs/plugins.md), [architecture](docs/architecture.md)).
|
|
116
|
+
|
|
117
|
+
## Concepts
|
|
118
|
+
|
|
119
|
+
| Concept | What it is |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| **Pipeline** | A list of steps, or one strategy, in `whiletrue.yaml`. |
|
|
122
|
+
| **Step** | An action: `agent`, a shell command, a git or GitHub operation, a gate. Pure, deterministic, agentic or side-effecting. |
|
|
123
|
+
| **Strategy** | Control flow over steps: `sequence`, `tap`, `loop`, `map`, `parallel`, `switch`, `retry`, `try`, `human.approve`. |
|
|
124
|
+
| **Outcome ports** | Every step ends on `ok`, `fail`, `needs_human`, `skip` or `rejected`. `wires:` routes a port to another step; back-wires make loops. |
|
|
125
|
+
| **Item** | One unit of work from a `source:` (`json`, `markdown_tasks`, `github_issues`). Items run in parallel, in dependency order. |
|
|
126
|
+
| **Workspace** | Per-item checkout: `git-worktree`, `dir-copy` or `none`. |
|
|
127
|
+
| **Gate** | A deterministic check, or a human decision, that an item must pass. |
|
|
128
|
+
| **Recipe** | A ready-made composite: `ralph`, `review-pass`, `review-respond`, `issue-loop`. |
|
|
129
|
+
| **Run record** | The SQLite log of steps, parks, effects, comments and cost that makes replay and resume possible. |
|
|
130
|
+
|
|
131
|
+
Details: [reference](docs/reference.md), [authoring guide](docs/authoring.md), [architecture](docs/architecture.md).
|
|
132
|
+
|
|
133
|
+
## Examples
|
|
134
|
+
|
|
135
|
+
### A Ralph loop
|
|
136
|
+
|
|
137
|
+
<img src="docs/assets/ralph-loop.svg" alt="Ralph loop: agent in a fresh context, then a pytest gate; green ends the loop, red feeds the output back to the agent" width="900">
|
|
138
|
+
|
|
139
|
+
This is what `whiletrue init` scaffolds. See the YAML under [Quickstart](#quickstart).
|
|
140
|
+
|
|
141
|
+
### Review loop with a read-only reviewer
|
|
142
|
+
|
|
143
|
+
```yaml
|
|
144
|
+
pipeline:
|
|
145
|
+
composite:
|
|
146
|
+
uses: "recipe:review-pass"
|
|
147
|
+
params: { reviewer: ./agents/review.md, fixer: ./agents/fix.md, max_rounds: 3 }
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### A backlog in parallel worktrees
|
|
151
|
+
|
|
152
|
+
```yaml
|
|
153
|
+
parallel: 4
|
|
154
|
+
max_agents: 4
|
|
155
|
+
source: { markdown_tasks: { path: TASKS.md } } # - [ ] Title {#id after=other}
|
|
156
|
+
workspace: { git-worktree: { branch: "wt/{{item.id}}" } }
|
|
157
|
+
pipeline:
|
|
158
|
+
loop:
|
|
159
|
+
max: 5
|
|
160
|
+
do:
|
|
161
|
+
- agent: { uses: ./agents/implement.md }
|
|
162
|
+
- gate.shell: { run: "pytest" }
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### A human gate on a pull request
|
|
166
|
+
|
|
167
|
+
```yaml
|
|
168
|
+
- id: review
|
|
169
|
+
human.approve:
|
|
170
|
+
what: pr
|
|
171
|
+
wake: { any: [cli, { github.pr_review: any }] }
|
|
172
|
+
do:
|
|
173
|
+
- composite: { uses: "recipe:review-respond", params: { responder: ./agents/respond.md } }
|
|
174
|
+
wires: { rejected: fix }
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
whiletrue run # parks at the gate and exits with code 2
|
|
179
|
+
whiletrue status # lists what is waiting
|
|
180
|
+
whiletrue approve 12 # or: reject 12 --note "what to change"
|
|
181
|
+
whiletrue resume # finished steps are replayed, never redone
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### The reference pipeline: issues with a human in the loop
|
|
185
|
+
|
|
186
|
+
[`examples/issue-loop`](examples/issue-loop/README.md) takes every issue in a GitHub milestone from open to merged: implement in a worktree, run the gate, open a PR, answer review comments, merge, close. You review every PR, and every comment you leave gets an answer.
|
|
187
|
+
|
|
188
|
+
<img src="docs/assets/issue-loop.svg" alt="Issue loop flow: implement with retry and a gate, open a PR, a human review gate with comment replies and a fix branch on rejection, then sync, a merge approval and the merge" width="900">
|
|
189
|
+
|
|
190
|
+
## Backends
|
|
191
|
+
|
|
192
|
+
Choose per agent with `runner:`.
|
|
193
|
+
|
|
194
|
+
| Runner | Runs | Notes |
|
|
195
|
+
| --- | --- | --- |
|
|
196
|
+
| `claude-code-headless` | `claude -p` | Default. Budget, turns and wall limits enforced. |
|
|
197
|
+
| `claude-code` | Interactive Claude Code in a tmux pane | Watch it, type into it (recorded as a *steer*). Submits through a bundled MCP tool and hooks. |
|
|
198
|
+
| `opencode` | `opencode run` | Structured output checked against the step's cap. |
|
|
199
|
+
| `codex` | `codex exec` | Sandbox derived from `permission_mode`. No budget enforcement. |
|
|
200
|
+
|
|
201
|
+
Structured `outputs:` work on all of them. See [choosing a backend](docs/authoring.md#choosing-a-backend).
|
|
202
|
+
|
|
203
|
+
## CLI
|
|
204
|
+
|
|
205
|
+
| Command | Purpose |
|
|
206
|
+
| --- | --- |
|
|
207
|
+
| `init`, `validate`, `plan` | Scaffold, check and preview a pipeline without spending tokens. |
|
|
208
|
+
| `run`, `resume`, `rerun`, `cancel` | Start, continue after a park or crash, redo, or stop items. |
|
|
209
|
+
| `status`, `logs`, `cost`, `replay` | Inspect runs, steps and spend; replay a recorded run. |
|
|
210
|
+
| `approve`, `reject`, `comment` | Decide human gates and talk to waiting items. |
|
|
211
|
+
| `attach`, `panel` | Open the tmux session and the live control panel. |
|
|
212
|
+
| `history`, `learnings` | Audit trail and approved lessons for future agents. |
|
|
213
|
+
| `lock` | Show or clear the run lock. |
|
|
214
|
+
|
|
215
|
+
Full reference: [docs/cli.md](docs/cli.md). New here? Follow the [tutorial](docs/tutorial.md).
|
|
216
|
+
|
|
217
|
+
## Documentation
|
|
218
|
+
|
|
219
|
+
Start at [docs/README.md](docs/README.md).
|
|
220
|
+
|
|
221
|
+
- [Tutorial](docs/tutorial.md): from an empty folder to your own loop with gates, a reviewer, parallel tasks and a human approval.
|
|
222
|
+
- [Getting started](docs/getting-started.md): a longer walkthrough, including interactive agents, gates and parallel items.
|
|
223
|
+
- [Authoring guide](docs/authoring.md): writing pipelines and agents.
|
|
224
|
+
- [Reference](docs/reference.md): every module, strategy, provider and config key.
|
|
225
|
+
- [CLI](docs/cli.md) and [plugins](docs/plugins.md): the command line and extending whiletrue.
|
|
226
|
+
- [Architecture](docs/architecture.md), [plan](docs/plan.md), [todo](docs/todo.md) and [changelog](CHANGELOG.md).
|
|
227
|
+
|
|
228
|
+
## Development
|
|
229
|
+
|
|
230
|
+
Requires [devenv](https://devenv.sh) (or Python 3.12 + [uv](https://docs.astral.sh/uv/)). See [developing.md](docs/developing.md).
|
|
231
|
+
|
|
232
|
+
```bash
|
|
233
|
+
git clone https://github.com/dariussingh/whiletrue && cd whiletrue
|
|
234
|
+
direnv allow # or: devenv shell
|
|
235
|
+
poe check # format check, lint, pyright, tests + coverage, docs check
|
|
236
|
+
whiletrue --help # installed editable into .devenv/state/venv
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
Live tests against real agent CLIs are opt-in: `WHILETRUE_LIVE=1 uv run pytest tests/live -v`.
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
MIT. See [LICENSE](LICENSE).
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
| -------------------------------------- | --------------------------------------------------------------------------------- |
|
|
5
5
|
| [architecture.md](architecture.md) | Full design: core model, runtime, state, agents, human gates, packages |
|
|
6
6
|
| [getting-started.md](getting-started.md) | User guide: install, first loop, commands, exit codes, safety defaults |
|
|
7
|
+
| [tutorial.md](tutorial.md) | Tutorial: install, first loop, then build your own gates, review, parallel and human steps |
|
|
7
8
|
| [authoring.md](authoring.md) | Authoring guide: pipelines, composites, agents, choosing a backend |
|
|
8
9
|
| [cli.md](cli.md) | CLI reference: every command, option, exit code and environment variable |
|
|
9
10
|
| [reference.md](reference.md) | User reference: modules, control flow, expressions, composites, recipes, replay |
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 600" width="960" height="600" role="img" aria-label="whiletrue architecture: CLI and whiletrue.yaml feed the core engine, which uses plugins to drive agent CLIs, git, GitHub and tmux, with state in SQLite">
|
|
2
|
+
<style>
|
|
3
|
+
text{font:13px ui-monospace,SFMono-Regular,Menlo,Consolas,'DejaVu Sans Mono',monospace;fill:#d5dbe3}
|
|
4
|
+
.t{font-size:15px;font-weight:700}.d{fill:#7d8896}.b{fill:#151b23;stroke:#2b3440;stroke-width:1.5}
|
|
5
|
+
.g{fill:#12251a;stroke:#3f7a50;stroke-width:1.5}.c{fill:#10222b;stroke:#3a7f96;stroke-width:1.5}.o{fill:#2a1f14;stroke:#a8683a;stroke-width:1.5}
|
|
6
|
+
.l{stroke:#7d8896;stroke-width:1.5;fill:none;marker-end:url(#a)}
|
|
7
|
+
</style>
|
|
8
|
+
<defs><marker id="a" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto"><path d="M0 0L10 5L0 10z" fill="#7d8896"/></marker></defs>
|
|
9
|
+
<rect width="960" height="600" rx="10" fill="#0f1419"/>
|
|
10
|
+
|
|
11
|
+
<rect class="b" x="30" y="24" width="900" height="64" rx="6"/>
|
|
12
|
+
<text class="t" x="48" y="50">You</text>
|
|
13
|
+
<text class="d" x="48" y="72">whiletrue.yaml · agents/*.md · whiletrue CLI (run resume approve status panel)</text>
|
|
14
|
+
|
|
15
|
+
<path class="l" d="M480 88V112"/>
|
|
16
|
+
|
|
17
|
+
<rect class="g" x="30" y="114" width="900" height="206" rx="6"/>
|
|
18
|
+
<text class="t" x="48" y="140">whiletrue.core (knows no git, GitHub, tmux or agent)</text>
|
|
19
|
+
<rect class="b" x="48" y="156" width="196" height="64" rx="5"/>
|
|
20
|
+
<text x="62" y="182">Loader + validator</text><text class="d" x="62" y="202">config, wiring, limits</text>
|
|
21
|
+
<rect class="b" x="260" y="156" width="196" height="64" rx="5"/>
|
|
22
|
+
<text x="274" y="182">Scheduler</text><text class="d" x="274" y="202">items, parallel, deps</text>
|
|
23
|
+
<rect class="b" x="472" y="156" width="196" height="64" rx="5"/>
|
|
24
|
+
<text x="486" y="182">Pipeline runtime</text><text class="d" x="486" y="202">strategies, journal</text>
|
|
25
|
+
<rect class="b" x="684" y="156" width="228" height="64" rx="5"/>
|
|
26
|
+
<text x="698" y="182">Park / resume / replay</text><text class="d" x="698" y="202">gates, crash recovery</text>
|
|
27
|
+
<rect class="b" x="48" y="236" width="420" height="64" rx="5"/>
|
|
28
|
+
<text x="62" y="262">Plugin API + registry</text><text class="d" x="62" y="282">action modules · strategies · providers · runners</text>
|
|
29
|
+
<rect class="b" x="484" y="236" width="428" height="64" rx="5"/>
|
|
30
|
+
<text x="498" y="262">State store (SQLite, .whiletrue/)</text><text class="d" x="498" y="282">steps · parks · effects · comments · cost</text>
|
|
31
|
+
|
|
32
|
+
<path class="l" d="M480 320V346"/>
|
|
33
|
+
|
|
34
|
+
<rect class="c" x="30" y="348" width="900" height="122" rx="6"/>
|
|
35
|
+
<text class="t" x="48" y="374">Built-in plugins (public plugin API only)</text>
|
|
36
|
+
<rect class="b" x="48" y="388" width="140" height="64" rx="5"/><text x="60" y="414">control</text><text class="d" x="60" y="434">loop map switch</text>
|
|
37
|
+
<rect class="b" x="200" y="388" width="140" height="64" rx="5"/><text x="212" y="414">basics</text><text class="d" x="212" y="434">agent shell</text>
|
|
38
|
+
<rect class="b" x="352" y="388" width="140" height="64" rx="5"/><text x="364" y="414">git</text><text class="d" x="364" y="434">worktrees</text>
|
|
39
|
+
<rect class="b" x="504" y="388" width="140" height="64" rx="5"/><text x="516" y="414">github</text><text class="d" x="516" y="434">issues, PRs</text>
|
|
40
|
+
<rect class="b" x="656" y="388" width="130" height="64" rx="5"/><text x="668" y="414">claude_code</text><text class="d" x="668" y="434">headless tmux</text>
|
|
41
|
+
<rect class="b" x="798" y="388" width="114" height="64" rx="5"/><text x="810" y="414">opencode</text><text class="d" x="810" y="434">codex</text>
|
|
42
|
+
|
|
43
|
+
<path class="l" d="M480 470V496"/>
|
|
44
|
+
|
|
45
|
+
<rect class="o" x="30" y="498" width="900" height="74" rx="6"/>
|
|
46
|
+
<text class="t" x="48" y="524">Outside world</text>
|
|
47
|
+
<text class="d" x="48" y="546">claude · opencode · codex CLIs | git | gh (GitHub) | tmux | your tests and scripts</text>
|
|
48
|
+
</svg>
|