robot_lab-to 0.2.6
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.
- checksums.yaml +7 -0
- data/.envrc +1 -0
- data/.github/workflows/deploy-github-pages.yml +52 -0
- data/.loki +21 -0
- data/.quality/reek_baseline.txt +17 -0
- data/.rubocop.yml +7 -0
- data/CHANGELOG.md +67 -0
- data/CLAUDE.md +74 -0
- data/COMMITS.md +27 -0
- data/README.md +352 -0
- data/Rakefile +132 -0
- data/bin/robot-to +14 -0
- data/docs/about/changelog.md +82 -0
- data/docs/assets/architecture.svg +110 -0
- data/docs/assets/images/robot_lab-to.jpg +0 -0
- data/docs/assets/iteration-loop.svg +97 -0
- data/docs/concepts/evals.md +254 -0
- data/docs/concepts/iteration-loop.md +128 -0
- data/docs/concepts/notes.md +91 -0
- data/docs/concepts/run-state.md +93 -0
- data/docs/concepts/stop-conditions.md +111 -0
- data/docs/concepts/verification.md +75 -0
- data/docs/configuration/cli.md +111 -0
- data/docs/configuration/index.md +93 -0
- data/docs/configuration/settings.md +270 -0
- data/docs/getting-started/anatomy-of-a-run.md +111 -0
- data/docs/getting-started/installation.md +78 -0
- data/docs/getting-started/quick-start.md +105 -0
- data/docs/index.md +96 -0
- data/docs/local-models/guardrails.md +117 -0
- data/docs/local-models/index.md +88 -0
- data/docs/local-models/ollama.md +122 -0
- data/docs/local-models/tools.md +92 -0
- data/docs/reference/architecture.md +139 -0
- data/examples/01_basic_usage/.gitignore +9 -0
- data/examples/01_basic_usage/README.md +173 -0
- data/examples/01_basic_usage/basic_usage.rb +386 -0
- data/examples/02_advanced_usage/.gitignore +8 -0
- data/examples/02_advanced_usage/README.md +117 -0
- data/examples/02_advanced_usage/advanced_usage.rb +308 -0
- data/examples/02_advanced_usage/quality_gate.rb +99 -0
- data/examples/03_scored/.gitignore +2 -0
- data/examples/03_scored/README.md +117 -0
- data/examples/03_scored/scored_run.rb +325 -0
- data/examples/04_prose/.gitignore +2 -0
- data/examples/04_prose/README.md +43 -0
- data/examples/04_prose/prompts_dir/grade_message.md +14 -0
- data/examples/04_prose/prompts_dir/judge.md +11 -0
- data/examples/04_prose/prompts_dir/outline_criteria.md +9 -0
- data/examples/04_prose/prompts_dir/outline_objective.md +11 -0
- data/examples/04_prose/prompts_dir/section_criteria.md +7 -0
- data/examples/04_prose/prompts_dir/sections_objective.md +14 -0
- data/examples/04_prose/prose_run.rb +302 -0
- data/lib/robot_lab/to/atomic_file.rb +69 -0
- data/lib/robot_lab/to/backoff.rb +46 -0
- data/lib/robot_lab/to/cli.rb +176 -0
- data/lib/robot_lab/to/commit_manager.rb +135 -0
- data/lib/robot_lab/to/config/defaults.yml +27 -0
- data/lib/robot_lab/to/config.rb +86 -0
- data/lib/robot_lab/to/decision.rb +40 -0
- data/lib/robot_lab/to/decision_manager.rb +193 -0
- data/lib/robot_lab/to/errors.rb +30 -0
- data/lib/robot_lab/to/evals/base.rb +23 -0
- data/lib/robot_lab/to/evals/code.rb +77 -0
- data/lib/robot_lab/to/evals/context.rb +17 -0
- data/lib/robot_lab/to/evals/factory.rb +84 -0
- data/lib/robot_lab/to/evals/null.rb +17 -0
- data/lib/robot_lab/to/evals/prose.rb +110 -0
- data/lib/robot_lab/to/evals/score.rb +22 -0
- data/lib/robot_lab/to/exit_summary.rb +75 -0
- data/lib/robot_lab/to/guards/checkpoint.rb +84 -0
- data/lib/robot_lab/to/guards/grader_lock.rb +62 -0
- data/lib/robot_lab/to/guards/path_resolution.rb +61 -0
- data/lib/robot_lab/to/guards/quality_monitor.rb +113 -0
- data/lib/robot_lab/to/guards/read_before_edit.rb +83 -0
- data/lib/robot_lab/to/guards/run_store.rb +31 -0
- data/lib/robot_lab/to/guards/write_guard.rb +71 -0
- data/lib/robot_lab/to/guards.rb +54 -0
- data/lib/robot_lab/to/iteration_result.rb +29 -0
- data/lib/robot_lab/to/jsonl_logger.rb +59 -0
- data/lib/robot_lab/to/notes_manager.rb +121 -0
- data/lib/robot_lab/to/orchestrator.rb +642 -0
- data/lib/robot_lab/to/prompt_builder.rb +208 -0
- data/lib/robot_lab/to/run.rb +109 -0
- data/lib/robot_lab/to/stop_conditions.rb +71 -0
- data/lib/robot_lab/to/tools/bash.rb +75 -0
- data/lib/robot_lab/to/tools/edit.rb +52 -0
- data/lib/robot_lab/to/tools/file_tool.rb +32 -0
- data/lib/robot_lab/to/tools/read.rb +57 -0
- data/lib/robot_lab/to/tools/request_decision.rb +66 -0
- data/lib/robot_lab/to/tools/submit_result.rb +50 -0
- data/lib/robot_lab/to/tools/write.rb +32 -0
- data/lib/robot_lab/to/verifier.rb +63 -0
- data/lib/robot_lab/to/version.rb +7 -0
- data/lib/robot_lab/to.rb +81 -0
- data/mkdocs.yml +145 -0
- metadata +175 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# Verification Gate
|
|
2
|
+
|
|
3
|
+
A robot reporting `success: true` is a *claim*, not a fact. The verification gate
|
|
4
|
+
makes that claim count only when an independent command — one you choose — agrees.
|
|
5
|
+
|
|
6
|
+
This is separation of duties applied to a single agent: the **robot does the
|
|
7
|
+
work**, but the **orchestrator runs the deciding command**. The robot cannot
|
|
8
|
+
self-certify a passing verdict.
|
|
9
|
+
|
|
10
|
+
## Enabling it
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
robot-to "Fix the failing parser tests" \
|
|
14
|
+
--verify-command "bundle exec rake test" \
|
|
15
|
+
--verify-timeout 600
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
When `--verify-command` is set, every iteration the robot marks successful is
|
|
19
|
+
gated:
|
|
20
|
+
|
|
21
|
+
```
|
|
22
|
+
robot says success ──► run verify-command ──► exit 0 ? ──► COMMIT
|
|
23
|
+
│
|
|
24
|
+
│ non-zero / timeout
|
|
25
|
+
▼
|
|
26
|
+
ROLLBACK (recorded as [VERIFY FAILED])
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
If verification fails, the working tree is reset with `git reset --hard`, the
|
|
30
|
+
iteration counts as a failure (incrementing the consecutive-failure counter), and
|
|
31
|
+
the verification output is written to `notes.md` so the next robot can see *why*
|
|
32
|
+
it failed.
|
|
33
|
+
|
|
34
|
+
## How it runs
|
|
35
|
+
|
|
36
|
+
The `Verifier`:
|
|
37
|
+
|
|
38
|
+
- Runs the command in the project working directory via `Open3.popen2e`.
|
|
39
|
+
- Launches it in its own **process group** so a timeout can kill the whole
|
|
40
|
+
process tree — test runners that spawn children won't survive a timeout.
|
|
41
|
+
- Enforces `--verify-timeout` seconds (default **600**). On timeout the process
|
|
42
|
+
group is terminated and the gate fails.
|
|
43
|
+
- Captures combined stdout+stderr, clamped to ~4 000 characters for the notes.
|
|
44
|
+
|
|
45
|
+
A non-zero exit **or** a timeout fails the gate.
|
|
46
|
+
|
|
47
|
+
## Choosing a verify command
|
|
48
|
+
|
|
49
|
+
The command should be the real signal of correctness for your objective:
|
|
50
|
+
|
|
51
|
+
| Objective | Good `--verify-command` |
|
|
52
|
+
|-----------|-------------------------|
|
|
53
|
+
| Fix failing tests | `bundle exec rake test` |
|
|
54
|
+
| Keep the build green | `npm run build` |
|
|
55
|
+
| Don't regress lint | `bundle exec rubocop` |
|
|
56
|
+
| Full quality bar | `bundle exec rake` (tests + lint + coverage) |
|
|
57
|
+
|
|
58
|
+
Tips:
|
|
59
|
+
|
|
60
|
+
- Make it **fast enough to run every iteration** — it runs on each claimed
|
|
61
|
+
success.
|
|
62
|
+
- Make it **deterministic** — flaky commands cause spurious rollbacks.
|
|
63
|
+
- Combine checks with `&&` if you want several gates: `--verify-command "bundle
|
|
64
|
+
exec rake test && bundle exec rubocop"`.
|
|
65
|
+
|
|
66
|
+
## Without a verify command
|
|
67
|
+
|
|
68
|
+
If you don't set `--verify-command`, the robot's self-reported `success` is taken
|
|
69
|
+
at face value and committed. This is fine for low-risk objectives (docs,
|
|
70
|
+
comments, scaffolding) but for anything that must keep working, a verification
|
|
71
|
+
gate is strongly recommended.
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
Next: [Evals: Scoring Iterations](evals.md).
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# CLI Reference
|
|
2
|
+
|
|
3
|
+
The `robot-to` executable runs an autonomous loop toward an objective.
|
|
4
|
+
|
|
5
|
+
## Synopsis
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
robot-to [objective] [options]
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
The **objective** is a single argument (quote it). If omitted, `robot-to` reads
|
|
12
|
+
the objective from standard input — handy for long objectives:
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
robot-to "Add request logging middleware and tests"
|
|
16
|
+
|
|
17
|
+
# or via stdin
|
|
18
|
+
echo "Add request logging middleware and tests" | robot-to
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Options
|
|
22
|
+
|
|
23
|
+
| Flag | Argument | Default | Description |
|
|
24
|
+
|------|----------|---------|-------------|
|
|
25
|
+
| `--provider` | `NAME` | `openai` | LLM provider (`anthropic`, `openai`, …). |
|
|
26
|
+
| `--model` | `MODEL` | `gpt-5.5` | Model identifier for the provider. |
|
|
27
|
+
| `--max-iterations` | `N` | *unlimited* | Stop after `N` iterations. |
|
|
28
|
+
| `--max-tokens` | `N` | *unlimited* | Stop after `N` total tokens. |
|
|
29
|
+
| `--stop-when` | `CONDITION` | *unset* | Natural-language stop condition the robot evaluates. |
|
|
30
|
+
| `--max-consecutive-failures` | `N` | `3` | Abort after `N` consecutive failures. |
|
|
31
|
+
| `--verify-command` | `CMD` | *unset* | Command that must pass before a success is committed. |
|
|
32
|
+
| `--verify-timeout` | `SECONDS` | `600` | Timeout for `--verify-command`. |
|
|
33
|
+
| `--max-verify-repairs` | `N` | `2` | Repair-in-place attempts when the eval's gate fails before rolling back. |
|
|
34
|
+
| `--eval` | `code`\|`null`\|`prose` | *code if verify/measure/target set, else null* | Eval strategy — see [Evals](../concepts/evals.md). |
|
|
35
|
+
| `--measure` | `CMD` | *unset* | Command printing a numeric score (higher = better); drives `Evals::Code`. |
|
|
36
|
+
| `--target` | `FLOAT` | *unset* | Stop once the measured score reaches this. |
|
|
37
|
+
| `--spec` | `PATH` | *unset* | Spec/outline artifact `Evals::Prose`'s judge measures against. |
|
|
38
|
+
| `--floor` | `CMD` | *unset* | Mechanizable floor check for prose (links, outline coverage, AI-tells). |
|
|
39
|
+
| `--judge-model` | `MODEL` | *`--model`* | Model for the pairwise prose judge. |
|
|
40
|
+
| `--stop-on-plateau` | `N` | *unset — off* | Stop after `N` iterations with no committed improvement. |
|
|
41
|
+
| `--[no-]require-improvement` | — | on | Roll back gate-passing iterations that don't beat the parent (default on). |
|
|
42
|
+
| `--protect-path` | `GLOB` (repeatable) | *none* | Lock a grader file from robot edits (always-on `GraderLock`). |
|
|
43
|
+
| `--commit-format` | `default`\|`conventional` | `default` | Commit message format. |
|
|
44
|
+
| `--run-dir` | `PATH` | `.robot_lab_to` | Directory for run state. |
|
|
45
|
+
| `--local-guards` | — | off | Add built-in file tools + small-model guardrails. |
|
|
46
|
+
| `--no-stream` | — | streaming on | Disable streaming (required for local Ollama tool calls). |
|
|
47
|
+
| `--debug` | — | off | Keep verbose provider logging enabled. |
|
|
48
|
+
| `--version` | — | — | Print version and exit. |
|
|
49
|
+
| `-h`, `--help` | — | — | Show help and exit. |
|
|
50
|
+
|
|
51
|
+
See the [Settings Reference](settings.md) for the full meaning of each option and
|
|
52
|
+
its config-file / environment-variable equivalents.
|
|
53
|
+
|
|
54
|
+
## Examples
|
|
55
|
+
|
|
56
|
+
A bounded run with a verification gate:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
robot-to "Fix the failing parser tests" \
|
|
60
|
+
--provider anthropic \
|
|
61
|
+
--model claude-sonnet-4-6 \
|
|
62
|
+
--max-iterations 15 \
|
|
63
|
+
--verify-command "bundle exec rake test"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
An overnight migration with a natural-language stop condition:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
robot-to "Migrate from Minitest to RSpec" \
|
|
70
|
+
--max-iterations 60 \
|
|
71
|
+
--max-tokens 3000000 \
|
|
72
|
+
--verify-command "bundle exec rake" \
|
|
73
|
+
--stop-when "every test file is RSpec and the suite passes" \
|
|
74
|
+
--commit-format conventional
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A scored run that descends toward a measured target (see [Evals](../concepts/evals.md)):
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
robot-to "Raise parser coverage to 90%" \
|
|
81
|
+
--verify "bundle exec rake test" \
|
|
82
|
+
--measure "bundle exec rake coverage" \
|
|
83
|
+
--target 90 \
|
|
84
|
+
--protect-path test/coverage_helper.rb
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A judged prose run that ends on plateau instead of a target:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
robot-to "Write an opinionated guide to the Viable Systems Model" \
|
|
91
|
+
--eval prose --spec outline.md --floor "rake docs:lint" \
|
|
92
|
+
--stop-on-plateau 3
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
A fully local run on Ollama (see [Local Models](../local-models/index.md)):
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
robot-to "Add a greet(name) method in greeter.rb" \
|
|
99
|
+
--provider openai \
|
|
100
|
+
--model gpt-oss:20b \
|
|
101
|
+
--local-guards \
|
|
102
|
+
--no-stream \
|
|
103
|
+
--max-iterations 5
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Exit behavior
|
|
107
|
+
|
|
108
|
+
`robot-to` runs to completion or until a stop condition trips, then prints an
|
|
109
|
+
[exit summary](../getting-started/anatomy-of-a-run.md#the-exit-summary). Press
|
|
110
|
+
**Ctrl-C** for a graceful stop — the in-flight iteration is rolled back, the loop
|
|
111
|
+
exits, and the summary still prints.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# Configuration
|
|
2
|
+
|
|
3
|
+
`robot_lab-to` is configured through a layered cascade built on
|
|
4
|
+
[`myway_config`](https://github.com/MadBomber/myway_config). Lower layers provide
|
|
5
|
+
defaults; higher layers override them.
|
|
6
|
+
|
|
7
|
+
## The cascade
|
|
8
|
+
|
|
9
|
+
From lowest to highest precedence:
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
1. Bundled defaults lib/robot_lab/to/config/defaults.yml
|
|
13
|
+
2. User config file ~/.config/robot_lab/to.yml
|
|
14
|
+
3. Environment variables ROBOT_LAB_TO_*
|
|
15
|
+
4. CLI flags / To.run args (highest — always wins)
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
A value set at a higher layer overrides the same value from any lower layer.
|
|
19
|
+
|
|
20
|
+
## 1. Bundled defaults
|
|
21
|
+
|
|
22
|
+
Shipped with the gem. You never edit these, but they define the baseline:
|
|
23
|
+
|
|
24
|
+
```yaml
|
|
25
|
+
defaults:
|
|
26
|
+
provider: openai
|
|
27
|
+
model: gpt-5.5
|
|
28
|
+
max_tool_rounds: 100
|
|
29
|
+
max_consecutive_failures: 3
|
|
30
|
+
max_retries: 2
|
|
31
|
+
max_submit_nudges: 1
|
|
32
|
+
verify_timeout: 600
|
|
33
|
+
commit_format: default
|
|
34
|
+
run_dir: .robot_lab_to
|
|
35
|
+
local_guards: false
|
|
36
|
+
stream: true
|
|
37
|
+
debug: false
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## 2. User config file
|
|
41
|
+
|
|
42
|
+
Create `~/.config/robot_lab/to.yml` to set your own defaults — for example, to
|
|
43
|
+
always use a local model:
|
|
44
|
+
|
|
45
|
+
```yaml
|
|
46
|
+
provider: openai # routes to Ollama's OpenAI-compatible endpoint
|
|
47
|
+
model: gpt-oss:20b
|
|
48
|
+
local_guards: true
|
|
49
|
+
stream: false
|
|
50
|
+
max_consecutive_failures: 4
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
These apply to every `robot-to` run unless overridden by an env var or CLI flag.
|
|
54
|
+
|
|
55
|
+
## 3. Environment variables
|
|
56
|
+
|
|
57
|
+
Every setting can be set via an environment variable prefixed with
|
|
58
|
+
`ROBOT_LAB_TO_`. Nested keys use a double underscore (rare here, since the config
|
|
59
|
+
is flat):
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
export ROBOT_LAB_TO_MODEL="gpt-oss:20b"
|
|
63
|
+
export ROBOT_LAB_TO_LOCAL_GUARDS=true
|
|
64
|
+
export ROBOT_LAB_TO_MAX_CONSECUTIVE_FAILURES=4
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Provider **API keys** are *not* `robot_lab-to` settings — they are read by the
|
|
68
|
+
underlying provider (e.g. `ANTHROPIC_API_KEY`, `OPENAI_API_KEY`).
|
|
69
|
+
|
|
70
|
+
## 4. CLI flags / `To.run` arguments
|
|
71
|
+
|
|
72
|
+
The highest-precedence layer. Anything passed on the command line (or as a keyword
|
|
73
|
+
to `RobotLab::To.run`) wins over all other layers:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
robot-to "..." --model claude-sonnet-4-6 --max-iterations 20
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
RobotLab::To.run("...", model: "claude-sonnet-4-6", max_iterations: 20)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Some options are **CLI-only** (no YAML default) because they are run-specific:
|
|
84
|
+
`--max-iterations`, `--max-tokens`, `--stop-when`, `--verify-command`, and the
|
|
85
|
+
whole [Evals](../concepts/evals.md) family (`--eval`, `--measure`, `--target`,
|
|
86
|
+
`--spec`, `--floor`, `--judge-model`, `--stop-on-plateau`,
|
|
87
|
+
`--[no-]require-improvement`, `--protect-path`). When unset they mean "no limit
|
|
88
|
+
/ not configured".
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
- See the [Settings Reference](settings.md) for every option in detail.
|
|
93
|
+
- See the [CLI Reference](cli.md) for every flag.
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
# Settings Reference
|
|
2
|
+
|
|
3
|
+
Every `robot_lab-to` setting, its default, and what it controls. Each setting can
|
|
4
|
+
be supplied via the user config file, an `ROBOT_LAB_TO_*` environment variable, a
|
|
5
|
+
CLI flag, or a `RobotLab::To.run` keyword argument (see
|
|
6
|
+
[the cascade](index.md#the-cascade)).
|
|
7
|
+
|
|
8
|
+
## Model & provider
|
|
9
|
+
|
|
10
|
+
### `provider`
|
|
11
|
+
|
|
12
|
+
- **Default:** `openai`
|
|
13
|
+
- **CLI:** `--provider NAME`
|
|
14
|
+
|
|
15
|
+
The LLM provider, passed through to RobotLab / RubyLLM. Use `anthropic`,
|
|
16
|
+
`openai`, etc. For **local Ollama models**, set this to `openai` and point
|
|
17
|
+
RubyLLM at Ollama's OpenAI-compatible endpoint — see [Ollama Setup](../local-models/ollama.md).
|
|
18
|
+
|
|
19
|
+
### `model`
|
|
20
|
+
|
|
21
|
+
- **Default:** `gpt-5.5`
|
|
22
|
+
- **CLI:** `--model MODEL`
|
|
23
|
+
|
|
24
|
+
The model identifier for the chosen provider (e.g. `claude-sonnet-4-6`,
|
|
25
|
+
`gpt-5.5`, `gpt-oss:20b`).
|
|
26
|
+
|
|
27
|
+
### `stream`
|
|
28
|
+
|
|
29
|
+
- **Default:** `true`
|
|
30
|
+
- **CLI:** `--no-stream` to disable
|
|
31
|
+
|
|
32
|
+
Whether to stream the model response. Streaming enables per-chunk token
|
|
33
|
+
accounting and mid-iteration token-budget enforcement. **Local Ollama models must
|
|
34
|
+
run with `--no-stream`** — Ollama suppresses tool calls when streaming. With
|
|
35
|
+
streaming off, tokens are accounted from each iteration's result instead. See
|
|
36
|
+
[Streaming and tool calls](../local-models/ollama.md#streaming-and-tool-calls).
|
|
37
|
+
|
|
38
|
+
## Loop control
|
|
39
|
+
|
|
40
|
+
### `max_iterations`
|
|
41
|
+
|
|
42
|
+
- **Default:** *(unset — no limit)*
|
|
43
|
+
- **CLI:** `--max-iterations N`
|
|
44
|
+
|
|
45
|
+
Stop after `N` iterations. CLI-only; strongly recommended for unattended runs.
|
|
46
|
+
|
|
47
|
+
### `max_tokens`
|
|
48
|
+
|
|
49
|
+
- **Default:** *(unset — no limit)*
|
|
50
|
+
- **CLI:** `--max-tokens N`
|
|
51
|
+
|
|
52
|
+
Stop once cumulative input+output tokens reach `N`. CLI-only.
|
|
53
|
+
|
|
54
|
+
### `max_consecutive_failures`
|
|
55
|
+
|
|
56
|
+
- **Default:** `3`
|
|
57
|
+
- **CLI:** `--max-consecutive-failures N`
|
|
58
|
+
|
|
59
|
+
Abort after `N` consecutive failed iterations. Resets to zero on each successful,
|
|
60
|
+
committed iteration. The primary safety net against a run going nowhere.
|
|
61
|
+
|
|
62
|
+
### `max_verify_repairs`
|
|
63
|
+
|
|
64
|
+
- **Default:** `2`
|
|
65
|
+
- **CLI:** `--max-verify-repairs N`
|
|
66
|
+
|
|
67
|
+
When the robot claims success but `verify_command` fails, the orchestrator hands
|
|
68
|
+
the failure output back to the **same** robot — its chat and working tree intact —
|
|
69
|
+
and lets it fix the code, re-verifying after each attempt, up to `N` times before
|
|
70
|
+
rolling the iteration back. Nothing commits until the gate is green, so the git
|
|
71
|
+
history stays clean; a near-miss just isn't discarded. Set to `0` to roll back
|
|
72
|
+
immediately on the first verify failure. See [Verification Gate](../concepts/verification.md).
|
|
73
|
+
|
|
74
|
+
### `stop_when`
|
|
75
|
+
|
|
76
|
+
- **Default:** *(unset)*
|
|
77
|
+
- **CLI:** `--stop-when "<condition>"`
|
|
78
|
+
|
|
79
|
+
A natural-language condition the robot evaluates after each successful iteration.
|
|
80
|
+
When the robot judges it met, the run stops. CLI-only. See
|
|
81
|
+
[Stop Conditions](../concepts/stop-conditions.md).
|
|
82
|
+
|
|
83
|
+
### `max_submit_nudges`
|
|
84
|
+
|
|
85
|
+
- **Default:** `1`
|
|
86
|
+
|
|
87
|
+
How many times to re-prompt a robot that finished without calling
|
|
88
|
+
`submit_iteration_result`. Recovers the "thinks but doesn't act" case before
|
|
89
|
+
counting the iteration as a failure.
|
|
90
|
+
|
|
91
|
+
### `max_retries`
|
|
92
|
+
|
|
93
|
+
- **Default:** `2`
|
|
94
|
+
|
|
95
|
+
How many consecutive *errors* (exceptions, e.g. transient API failures) to retry
|
|
96
|
+
before aborting. Retries use an interruptible exponential backoff
|
|
97
|
+
(`60 × 2ⁿ` seconds).
|
|
98
|
+
|
|
99
|
+
### `max_tool_rounds`
|
|
100
|
+
|
|
101
|
+
- **Default:** `100`
|
|
102
|
+
|
|
103
|
+
Passed to the robot — the maximum number of tool-call rounds within a single
|
|
104
|
+
iteration before RobotLab's circuit breaker stops it.
|
|
105
|
+
|
|
106
|
+
## Verification
|
|
107
|
+
|
|
108
|
+
### `verify_command`
|
|
109
|
+
|
|
110
|
+
- **Default:** *(unset — no verification)*
|
|
111
|
+
- **CLI:** `--verify-command "CMD"`
|
|
112
|
+
|
|
113
|
+
A command that must exit `0` before a robot's claimed success is committed.
|
|
114
|
+
CLI-only. See [Verification Gate](../concepts/verification.md).
|
|
115
|
+
|
|
116
|
+
### `verify_timeout`
|
|
117
|
+
|
|
118
|
+
- **Default:** `600` (seconds)
|
|
119
|
+
- **CLI:** `--verify-timeout SECONDS`
|
|
120
|
+
|
|
121
|
+
Maximum time `verify_command` may run before it is killed (whole process group)
|
|
122
|
+
and the gate fails.
|
|
123
|
+
|
|
124
|
+
## Evals (scoring)
|
|
125
|
+
|
|
126
|
+
CLI-only (no YAML default) unless noted. See [Evals](../concepts/evals.md) for
|
|
127
|
+
the full behavioral model.
|
|
128
|
+
|
|
129
|
+
### `eval`
|
|
130
|
+
|
|
131
|
+
- **Default:** *(unset — `Evals::Code` if `verify_command`/`eval_measure`/
|
|
132
|
+
`eval_target` is set, else the unscored `Evals::Null`)*
|
|
133
|
+
- **CLI:** `--eval code|null|prose`
|
|
134
|
+
|
|
135
|
+
Selects the scoring strategy. Via the Ruby API, `eval:` also accepts an instance
|
|
136
|
+
responding to `#score`, a proc, or a `Symbol` registered with
|
|
137
|
+
`RobotLab::To.register_eval` — the CLI flag itself only resolves the three named
|
|
138
|
+
strings.
|
|
139
|
+
|
|
140
|
+
### `eval_measure`
|
|
141
|
+
|
|
142
|
+
- **Default:** *(unset)*
|
|
143
|
+
- **CLI:** `--measure CMD`
|
|
144
|
+
|
|
145
|
+
A command that prints a number to stdout (higher = better) — the descent signal
|
|
146
|
+
for `Evals::Code`. Setting this alone (without `verify_command`) still selects
|
|
147
|
+
`Evals::Code`, not `Evals::Null`.
|
|
148
|
+
|
|
149
|
+
### `eval_target`
|
|
150
|
+
|
|
151
|
+
- **Default:** *(unset)*
|
|
152
|
+
- **CLI:** `--target FLOAT`
|
|
153
|
+
|
|
154
|
+
Stop the run once `eval_measure`'s value reaches this (`Evals::Code`).
|
|
155
|
+
|
|
156
|
+
### `eval_spec`
|
|
157
|
+
|
|
158
|
+
- **Default:** *(unset)*
|
|
159
|
+
- **CLI:** `--spec PATH`
|
|
160
|
+
|
|
161
|
+
The spec/outline artifact `Evals::Prose`'s judge measures the draft against.
|
|
162
|
+
Automatically added to `Evals::Prose#protected_paths` — locked from robot edits
|
|
163
|
+
by `GraderLock`.
|
|
164
|
+
|
|
165
|
+
### `eval_floor`
|
|
166
|
+
|
|
167
|
+
- **Default:** *(unset)*
|
|
168
|
+
- **CLI:** `--floor CMD`
|
|
169
|
+
|
|
170
|
+
An optional mechanizable check (e.g. link validation, outline coverage) that
|
|
171
|
+
must pass before `Evals::Prose` calls the judge at all. A failing floor is
|
|
172
|
+
scored `:worse` without spending a judge call.
|
|
173
|
+
|
|
174
|
+
### `eval_judge_model`
|
|
175
|
+
|
|
176
|
+
- **Default:** *(unset — falls back to `model`)*
|
|
177
|
+
- **CLI:** `--judge-model MODEL`
|
|
178
|
+
|
|
179
|
+
The model used for `Evals::Prose`'s pairwise judge. Defaults to the doer's own
|
|
180
|
+
`model`; set this to use a different (often cheaper, or deliberately more
|
|
181
|
+
skeptical) model for the judge role.
|
|
182
|
+
|
|
183
|
+
### `stop_on_plateau`
|
|
184
|
+
|
|
185
|
+
- **Default:** *(unset — off)*
|
|
186
|
+
- **CLI:** `--stop-on-plateau N`
|
|
187
|
+
|
|
188
|
+
Stop after `N` consecutive iterations with no committed improvement. The
|
|
189
|
+
primary terminator for `Evals::Prose`, which never sets a measurable target. See
|
|
190
|
+
[Stop Conditions](../concepts/stop-conditions.md#plateau-no-improvement).
|
|
191
|
+
|
|
192
|
+
### `require_improvement`
|
|
193
|
+
|
|
194
|
+
- **Default:** `true` (CLI/Ruby-only hardcoded default; not in `defaults.yml`)
|
|
195
|
+
- **CLI:** `--[no-]require-improvement`
|
|
196
|
+
|
|
197
|
+
When true, a gate-passing iteration that doesn't beat the parent commit's score
|
|
198
|
+
is rolled back rather than committed. `--no-require-improvement` restores
|
|
199
|
+
"commit any gate-passing success."
|
|
200
|
+
|
|
201
|
+
### `protect_paths`
|
|
202
|
+
|
|
203
|
+
- **Default:** `[]`
|
|
204
|
+
- **CLI:** `--protect-path GLOB` (repeatable)
|
|
205
|
+
|
|
206
|
+
Extra grader files (globs) locked from robot writes/edits/bash, on top of
|
|
207
|
+
whatever the configured eval's `#protected_paths` already locks. Always
|
|
208
|
+
enforced via `Guards::GraderLock` when the resolved set is non-empty —
|
|
209
|
+
independent of `local_guards`.
|
|
210
|
+
|
|
211
|
+
## Local models
|
|
212
|
+
|
|
213
|
+
### `local_guards`
|
|
214
|
+
|
|
215
|
+
- **Default:** `false`
|
|
216
|
+
- **CLI:** `--local-guards`
|
|
217
|
+
|
|
218
|
+
Attach the built-in file tools (`read`, `write`, `edit`, `bash`) and the
|
|
219
|
+
small-model guardrail hooks. Designed for local models that need a more
|
|
220
|
+
constrained, forgiving tool surface. See [Local Models](../local-models/index.md).
|
|
221
|
+
|
|
222
|
+
### `write_guard`
|
|
223
|
+
|
|
224
|
+
- **Default:** `true` (Ruby-only — no CLI flag)
|
|
225
|
+
- **Ruby:** `RobotLab::To.run(..., write_guard: false)`
|
|
226
|
+
|
|
227
|
+
When `local_guards` is on, `write_guard: false` drops `Guards::WriteGuard` from
|
|
228
|
+
the installed set (`Guards.install(..., except: [Guards::WriteGuard])`), letting
|
|
229
|
+
the robot freely overwrite a file it is iteratively refining — WriteGuard
|
|
230
|
+
otherwise refuses `write` on a file that already exists and redirects to `edit`,
|
|
231
|
+
which is unhelpful for a robot rewriting a whole prose draft each pass. See
|
|
232
|
+
[Guardrails](../local-models/guardrails.md).
|
|
233
|
+
|
|
234
|
+
## Git & output
|
|
235
|
+
|
|
236
|
+
### `commit_format`
|
|
237
|
+
|
|
238
|
+
- **Default:** `default`
|
|
239
|
+
- **CLI:** `--commit-format default|conventional`
|
|
240
|
+
|
|
241
|
+
How commit messages are formatted:
|
|
242
|
+
|
|
243
|
+
=== "default"
|
|
244
|
+
|
|
245
|
+
`robot-to <iteration>: <summary>`
|
|
246
|
+
|
|
247
|
+
=== "conventional"
|
|
248
|
+
|
|
249
|
+
`<type>(<scope>): <summary>` — `type`/`scope` come from the robot's result
|
|
250
|
+
(defaulting to `chore`). Follows [Conventional Commits](https://www.conventionalcommits.org/).
|
|
251
|
+
|
|
252
|
+
### `run_dir`
|
|
253
|
+
|
|
254
|
+
- **Default:** `.robot_lab_to`
|
|
255
|
+
- **CLI:** `--run-dir PATH`
|
|
256
|
+
|
|
257
|
+
Where run state (`runs/<run_id>/`) is written. Added to `.git/info/exclude`
|
|
258
|
+
automatically.
|
|
259
|
+
|
|
260
|
+
### `debug`
|
|
261
|
+
|
|
262
|
+
- **Default:** `false`
|
|
263
|
+
- **CLI:** `--debug`
|
|
264
|
+
|
|
265
|
+
Keep verbose RubyLLM/RobotLab provider logging enabled. The JSONL event log is
|
|
266
|
+
written regardless.
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
See the [CLI Reference](cli.md) for the command-line form of every option.
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Anatomy of a Run
|
|
2
|
+
|
|
3
|
+
A single `robot-to` invocation produces a git branch, a run directory, and a
|
|
4
|
+
post-run summary. This page walks through each artifact.
|
|
5
|
+
|
|
6
|
+
## The branch
|
|
7
|
+
|
|
8
|
+
On startup the orchestrator:
|
|
9
|
+
|
|
10
|
+
1. Verifies `HEAD` exists (at least one commit).
|
|
11
|
+
2. Creates a branch named `robot-to/<slug>-<timestamp>` from the current `HEAD`.
|
|
12
|
+
3. Records the `base_commit` SHA so the exit summary can diff the whole run.
|
|
13
|
+
|
|
14
|
+
Every successful iteration is committed onto this branch. Your original branch is
|
|
15
|
+
untouched.
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
* 6a7137c robot-to 2: add docstring and confirm behavior ← iteration 2
|
|
19
|
+
* 5810ae0 robot-to 1: create greeter.rb with greet method ← iteration 1
|
|
20
|
+
* 362b8d9 initial ← base_commit
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Commit message format
|
|
24
|
+
|
|
25
|
+
Controlled by `--commit-format`:
|
|
26
|
+
|
|
27
|
+
=== "default"
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
robot-to 1: <result summary>
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
=== "conventional"
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
feat(scope): <result summary>
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
The `type` and `scope` come from the robot's submitted result (defaulting to
|
|
40
|
+
`chore`). See [Commit conventions](../configuration/settings.md#commit_format).
|
|
41
|
+
|
|
42
|
+
## The run directory
|
|
43
|
+
|
|
44
|
+
All run state lives under `.robot_lab_to/runs/<run_id>/` (the directory is added
|
|
45
|
+
to `.git/info/exclude` automatically):
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
.robot_lab_to/
|
|
49
|
+
└── runs/
|
|
50
|
+
└── 20260623-144554-3e5c27/
|
|
51
|
+
├── notes.md # cross-iteration memory (human-readable)
|
|
52
|
+
├── run.log # JSONL event log (machine-readable)
|
|
53
|
+
└── checkpoints/ # pre-edit file snapshots (local_guards only)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
- **`notes.md`** — written by the orchestrator after each iteration; read by the
|
|
57
|
+
robot at the start of the next. See [Cross-Iteration Memory](../concepts/notes.md).
|
|
58
|
+
- **`run.log`** — one JSON object per line, one per lifecycle event. See
|
|
59
|
+
[Run State & Event Log](../concepts/run-state.md).
|
|
60
|
+
- **`checkpoints/`** — first-write-wins file snapshots taken before a Write/Edit,
|
|
61
|
+
created only when `--local-guards` is active. See [Guardrails](../local-models/guardrails.md).
|
|
62
|
+
|
|
63
|
+
## One iteration, step by step
|
|
64
|
+
|
|
65
|
+
```
|
|
66
|
+
iteration:start → fresh robot built with prompt + notes
|
|
67
|
+
agent:run:start → robot.run() begins
|
|
68
|
+
(robot uses tools, calls submit_iteration_result)
|
|
69
|
+
agent:run:end
|
|
70
|
+
agent:nudge? → if no result submitted, re-ask (max_submit_nudges)
|
|
71
|
+
eval → the configured eval scores the working tree (if reported success)
|
|
72
|
+
commit:success → git add -A && commit (gate ok + improved)
|
|
73
|
+
— or —
|
|
74
|
+
iteration:no_improvement → git reset --hard (gate ok, not improved)
|
|
75
|
+
iteration:gate_failure → git reset --hard (after eval:repair) (gate failed)
|
|
76
|
+
iteration:failure → git reset --hard (robot reported failure / no submit)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
A committed iteration resets the consecutive-failure counter and the plateau
|
|
80
|
+
counter; a failure or gate failure increments consecutive-failures, and any
|
|
81
|
+
non-committing outcome increments the plateau counter (may trip
|
|
82
|
+
`--max-consecutive-failures` or `--stop-on-plateau`). See
|
|
83
|
+
[Evals](../concepts/evals.md) for the full scoring model — by default (no
|
|
84
|
+
`--verify-command`/`--eval`), every reported success commits, matching this
|
|
85
|
+
page's simpler mental model.
|
|
86
|
+
|
|
87
|
+
## The exit summary
|
|
88
|
+
|
|
89
|
+
When the loop ends — whether it completed, hit a stop condition, or aborted —
|
|
90
|
+
`robot-to` prints a summary to stdout:
|
|
91
|
+
|
|
92
|
+
```
|
|
93
|
+
robot-to complete — claude-sonnet-4-6 — 4m 12s
|
|
94
|
+
Branch: robot-to/migrate-to-rspec-20260623-144554
|
|
95
|
+
|
|
96
|
+
Iterations: 8 (6 committed, 2 rolled back)
|
|
97
|
+
Changes: +312 / -47 across 14 files
|
|
98
|
+
Tokens: 1,204,883 in / 38,902 out
|
|
99
|
+
|
|
100
|
+
Run state: .robot_lab_to/runs/20260623-144554-3e5c27/
|
|
101
|
+
Next steps:
|
|
102
|
+
git log robot-to/migrate-to-rspec-20260623-144554
|
|
103
|
+
git diff 362b8d9..HEAD
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
If the run was stopped early, the header shows the reason (e.g. `max iterations
|
|
107
|
+
reached (8)`, `4 consecutive failures`, or `stop condition met: ...`).
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
Next: the full lifecycle in [The Iteration Loop](../concepts/iteration-loop.md).
|