<p align="center">
<img src="assets/prompt_runner_sdk.svg" alt="Prompt Runner SDK" width="200" height="200">
</p>
<h1 align="center">Prompt Runner SDK</h1>
<p align="center">
<strong>An Elixir toolkit for orchestrating multi-step prompt executions with Claude Agent SDK and Codex SDK</strong>
</p>
<p align="center">
<a href="https://hex.pm/packages/prompt_runner_sdk"><img src="https://img.shields.io/hexpm/v/prompt_runner_sdk.svg" alt="Hex.pm"></a>
<a href="https://hexdocs.pm/prompt_runner_sdk"><img src="https://img.shields.io/badge/docs-hexdocs-blue.svg" alt="Documentation"></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License"></a>
</p>
---
## Overview
**Prompt Runner SDK** is a CLI-first Elixir tool for running ordered prompt sets with
streaming output, repeatable configuration, and per-prompt git commits. It supports
both Claude Agent SDK and Codex SDK through a single facade.
### Start Here (Recommended)
Use the multi-repo example as the reference implementation. It shows the full
structure (config + prompts + commit messages) and runs against two dummy repos:
```bash
cd /home/home/p/g/n/prompt_runner_sdk
bash examples/multi_repo_dummy/setup.sh
mix run run_prompts.exs --config examples/multi_repo_dummy/runner_config.exs --run 01
mix run run_prompts.exs --config examples/multi_repo_dummy/runner_config.exs --run 02
```
Read the walkthrough in `examples/multi_repo_dummy/README.md`.
### What You Create
You provide three files plus the prompt markdown files:
```
runner_config.exs # settings + LLM defaults
prompts.txt # prompt list (order, file, repo targets)
commit-messages.txt # per-prompt commit messages
001-setup.md # actual prompt content
002-feature.md
...
```
All paths in `runner_config.exs` are relative to the config file.
### How Prompt Runner Uses Them
- `runner_config.exs`: overall settings, default LLM, repo paths, logging.
- `prompts.txt`: ordered list of prompts with file names and optional repo targets.
- `commit-messages.txt`: the commit message for each prompt (per-repo if needed).
- `NNN-*.md`: the actual prompt instructions that the LLM executes.
## Features
### Dual LLM Backend Support
Prompt Runner SDK provides a unified facade for both **Claude Agent SDK** (Anthropic) and **Codex SDK** (OpenAI), allowing you to:
- Configure a default LLM backend at the project level
- Override the LLM on a per-prompt basis
- Mix and match Claude and Codex within the same execution run
```elixir
%{
llm: %{
sdk: "claude_agent_sdk",
model: "sonnet",
prompt_overrides: %{
"02" => %{sdk: "codex_sdk", model: "gpt-5.1-codex"}
}
}
}
```
### Real-time Streaming Output
Experience AI responses as they're generated with our advanced streaming renderer:
- **Compact Mode**: Token-based display showing messages, tools, and thinking indicators
- **Verbose Mode**: Full event details for debugging and analysis
- **Color-coded Output**: Instantly distinguish between roles, tools, and status
- **Event Logging**: Capture all events in JSON format for post-processing
### Persistent Progress Tracking
Never lose your place in a long-running prompt sequence:
- Tracks completion status for each prompt
- Supports `--continue` to resume from the last successful prompt
- Handles partial successes when working with multiple repositories
- Status markers: `[ ]` pending, `[/]` in-progress, `[x]` completed, `[!]` failed
### Multi-Repository Support
Execute prompts that affect multiple codebases simultaneously:
```elixir
%{
target_repos: [
%{name: "frontend", path: "/path/to/frontend", default: true},
%{name: "backend", path: "/path/to/backend"},
%{name: "shared", path: "/path/to/shared-lib"}
]
}
```
Each prompt can specify which repositories it should modify, with automatic git commit coordination.
### Automatic Git Integration
Streamline your development workflow with built-in git operations:
- Pre-configured commit messages for each prompt
- Support for multi-repo commits with repo-specific messages
- Automatic staging and committing after successful prompt execution
- `--no-commit` option for dry runs and testing
### Phase-Based Organization
Organize complex prompt sequences into logical phases:
```
# prompts.txt (Format: NUM|PHASE|SP|NAME|FILE[|TARGET_REPOS])
01|1|5|Schema Design|001-schema.md
02|1|8|Database Setup|002-database.md
03|2|13|API Layer|003-api.md|backend
04|2|8|Frontend Components|004-components.md|frontend,shared
05|3|21|Integration Tests|005-tests.md|backend,frontend
```
Run entire phases with `--phase N` or continue from a specific point with `--continue`.
## Installation
Add `prompt_runner_sdk` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:prompt_runner_sdk, "~> 0.1.0"}
]
end
```
Then run:
```bash
mix deps.get
```
## Configuration Structure (Essentials)
### runner_config.exs
```elixir
%{
project_dir: "/path/to/workspace",
prompts_file: "prompts.txt",
commit_messages_file: "commit-messages.txt",
progress_file: ".progress",
log_dir: "logs",
model: "sonnet",
allowed_tools: ["Read", "Write", "Bash"],
permission_mode: :accept_edits,
target_repos: [
%{name: "app", path: "/path/to/app", default: true},
%{name: "lib", path: "/path/to/lib"}
],
llm: %{
sdk: "claude_agent_sdk",
model: "sonnet",
prompt_overrides: %{
"02" => %{sdk: "codex_sdk", model: "gpt-5.1-codex"}
}
}
}
```
### prompts.txt
Format: `NUM|PHASE|SP|NAME|FILE[|TARGET_REPOS]`
```
01|1|5|Initial Setup|001-setup.md
02|1|8|Core Module|002-core.md|app,lib
```
### commit-messages.txt
Single-repo:
```
=== COMMIT 01 ===
feat(init): set up project structure
```
Multi-repo:
```
=== COMMIT 02:app ===
feat(app): implement core module
=== COMMIT 02:lib ===
feat(lib): update shared utilities
```
### Run prompts
```bash
mix run run_prompts.exs --config runner_config.exs --list
mix run run_prompts.exs --config runner_config.exs --run 01
mix run run_prompts.exs --config runner_config.exs --run --all
```
## CLI Reference
### Commands
| Command | Description |
|---------|-------------|
| `--list` | Display all prompts with their current status |
| `--validate` | Run full configuration validation |
| `--dry-run TARGET` | Preview execution without running |
| `--plan-only` | Generate execution plan only |
| `--run TARGET` | Execute prompts with streaming output |
### Targets
| Target | Description |
|--------|-------------|
| `NN` | Single prompt by number (e.g., `01`, `15`) |
| `--phase N` | All prompts in phase N |
| `--all` | All prompts in sequence |
| `--continue` | Resume from last completed prompt |
| `--partial-continue` | Resume failed repos from partial success |
### Options
| Option | Description |
|--------|-------------|
| `--config FILE` | Configuration file path (required) |
| `--no-commit` | Skip git commits after prompts |
| `--project-dir DIR` | Override project directory |
| `--repo-override N:P` | Override repo path by name |
| `--log-mode MODE` | Output mode: `compact` or `verbose` |
| `--log-meta MODE` | Event metadata: `none` or `full` |
| `--events-mode MODE` | Events log: `compact`, `full`, or `off` |
| `--branch-strategy MODE` | Branch mode: `direct`, `feature_branch`, `per_prompt` |
| `--branch-name NAME` | Override branch name |
| `--auto-pr` | Create PRs after completion |
## Configuration Reference
### Full Configuration Example
```elixir
%{
# Project settings
project_dir: "/path/to/project",
# Multi-repo configuration
target_repos: [
%{name: "main", path: "/path/to/main", default: true},
%{name: "lib", path: "/path/to/lib"}
],
# LLM configuration
llm: %{
sdk: "claude_agent_sdk", # or "codex_sdk"
model: "sonnet", # model identifier
permission_mode: :accept_edits, # :plan, :accept_edits, :bypass_permissions
allowed_tools: ["Read", "Write", "Bash", "Computer"],
# Claude-specific options
claude_opts: %{},
# Codex-specific options
codex_opts: %{},
codex_thread_opts: %{
sandbox: :workspace_write,
ask_for_approval: :never
},
# Per-prompt overrides
prompt_overrides: %{
"05" => %{sdk: "codex_sdk", model: "gpt-5.1-codex"},
"10" => %{model: "opus", permission_mode: :plan}
}
},
# File paths
prompts_file: "prompts.txt",
commit_messages_file: "commit-messages.txt",
progress_file: ".progress",
log_dir: "logs",
# Display settings
log_mode: :compact, # :compact or :verbose
log_meta: :none, # :none or :full
events_mode: :compact, # :compact, :full, or :off
# Organization
phase_names: %{
1 => "Setup & Configuration",
2 => "Core Implementation",
3 => "Testing & Integration",
4 => "Documentation",
5 => "Release Preparation"
}
}
```
## Architecture
<p align="center">
<img src="assets/architecture.svg" alt="Prompt Runner SDK Architecture" width="700">
</p>
## Examples
Each example has its own README under `examples/`. Start with `examples/README.md`.
**Recommended:** `examples/multi_repo_dummy` is the full reference example. It shows
multi-repo targeting, per-repo commits, and SDK overrides:
```bash
cd examples/multi_repo_dummy
bash setup.sh
mix run ../../run_prompts.exs --config runner_config.exs --run 01
mix run ../../run_prompts.exs --config runner_config.exs --run 02
bash cleanup.sh
```
`examples/simple` is a minimal two-prompt demo that writes small files into the repo:
```bash
cd examples/simple
mix run ../../run_prompts.exs --config runner_config.exs --run 01
mix run ../../run_prompts.exs --config runner_config.exs --run 02
```
## Stream Renderer Output
### Compact Mode Legend
```
legend: m:s=system m:u=user m:a=assistant th:=thinking t+=tool_start t-=tool_end
```
- `m:s` - System message
- `m:u` - User message
- `m:a` - Assistant message
- `th:` - Thinking/reasoning
- `t+name` - Tool use started
- `t-name` - Tool use completed
- `✓` - Success indicator
- `!` - Error indicator
### Verbose Mode
Provides full event details including:
- Complete tool input/output
- Token counts and timing
- Metadata and debugging information
## Development
```bash
# Clone the repository
git clone https://github.com/nshkrdotcom/prompt_runner_sdk.git
cd prompt_runner_sdk
# Install dependencies
mix deps.get
# Run tests
mix test
# Run Credo
mix credo --strict
# Run Dialyzer
mix dialyzer
# Generate documentation
mix docs
```
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'feat: add amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
## Acknowledgments
- [Claude Agent SDK](https://hex.pm/packages/claude_agent_sdk) - Anthropic's Claude integration for Elixir
- [Codex SDK](https://hex.pm/packages/codex_sdk) - OpenAI's Codex integration for Elixir
- The Elixir community for their excellent tooling and ecosystem
---
<p align="center">
Made with 💚 by <a href="https://github.com/nshkrdotcom">nshkrdotcom</a>
</p>