rangers 0.6.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.
- rangers-0.6.1/LICENSE +21 -0
- rangers-0.6.1/MANIFEST.in +6 -0
- rangers-0.6.1/PKG-INFO +242 -0
- rangers-0.6.1/README.md +210 -0
- rangers-0.6.1/SKILL.md +169 -0
- rangers-0.6.1/docs/API.md +498 -0
- rangers-0.6.1/docs/ARCHITECTURE.md +80 -0
- rangers-0.6.1/docs/PARADIGM.md +98 -0
- rangers-0.6.1/docs/PUBLISHING.md +51 -0
- rangers-0.6.1/docs/cheatsheet.png +0 -0
- rangers-0.6.1/docs/commands.md +173 -0
- rangers-0.6.1/docs/growth-log.md +80 -0
- rangers-0.6.1/pyproject.toml +46 -0
- rangers-0.6.1/ranger/__init__.py +1433 -0
- rangers-0.6.1/ranger/py.typed +0 -0
- rangers-0.6.1/rangers.egg-info/PKG-INFO +242 -0
- rangers-0.6.1/rangers.egg-info/SOURCES.txt +24 -0
- rangers-0.6.1/rangers.egg-info/dependency_links.txt +1 -0
- rangers-0.6.1/rangers.egg-info/requires.txt +5 -0
- rangers-0.6.1/rangers.egg-info/top_level.txt +1 -0
- rangers-0.6.1/scripts/cheatsheet.py +251 -0
- rangers-0.6.1/setup.cfg +4 -0
- rangers-0.6.1/tests/test_docs.py +143 -0
- rangers-0.6.1/tests/test_logic.py +523 -0
- rangers-0.6.1/tests/test_packaging.py +35 -0
- rangers-0.6.1/tests/test_ranger.py +1220 -0
rangers-0.6.1/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 AlexKay28
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
rangers-0.6.1/PKG-INFO
ADDED
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: rangers
|
|
3
|
+
Version: 0.6.1
|
|
4
|
+
Summary: Agent-as-a-library: drive headless coding-agent harnesses from Python
|
|
5
|
+
Author: AlexKay28
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/AlexKay28/ranger
|
|
8
|
+
Project-URL: Documentation, https://github.com/AlexKay28/ranger/tree/main/docs
|
|
9
|
+
Project-URL: Repository, https://github.com/AlexKay28/ranger
|
|
10
|
+
Project-URL: Issues, https://github.com/AlexKay28/ranger/issues
|
|
11
|
+
Keywords: agent,ai,automation,codex,coding-agent,opencode
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE
|
|
27
|
+
Provides-Extra: dev
|
|
28
|
+
Requires-Dist: build>=1.2; extra == "dev"
|
|
29
|
+
Requires-Dist: pytest; extra == "dev"
|
|
30
|
+
Requires-Dist: twine>=6.0; extra == "dev"
|
|
31
|
+
Dynamic: license-file
|
|
32
|
+
|
|
33
|
+
# ranger
|
|
34
|
+
|
|
35
|
+

|
|
36
|
+
|
|
37
|
+
Agent-as-a-library. Run the [opencode](https://opencode.ai) or
|
|
38
|
+
[codex](https://github.com/openai/codex) coding agents headlessly from plain
|
|
39
|
+
Python code — for agentic-loop prototyping. You write code, not chat.
|
|
40
|
+
|
|
41
|
+
The whole design follows one paradigm: **the agent is a function call —
|
|
42
|
+
Python owns the loop, the harness is just the data plane.** Plan → act →
|
|
43
|
+
check → repeat maps 1:1 onto expression, statement and condition. See
|
|
44
|
+
[docs/PARADIGM.md](docs/PARADIGM.md) for the seven laws every feature is
|
|
45
|
+
reviewed against.
|
|
46
|
+
|
|
47
|
+
AI coding agents: start with [SKILL.md](SKILL.md) for the library's safe
|
|
48
|
+
workflow, contracts, and repository contribution rules.
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<img src="https://raw.githubusercontent.com/AlexKay28/ranger/main/docs/cheatsheet.png" alt="ranger command cheatsheet" width="760">
|
|
52
|
+
</p>
|
|
53
|
+
|
|
54
|
+
## Install
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
pip install rangers
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The distribution is named **`rangers`** on PyPI; the Python import remains
|
|
61
|
+
`import ranger`. For development from a clone: `pip install -e .[dev]`.
|
|
62
|
+
Maintainers: see the [publishing checklist](docs/PUBLISHING.md) before any
|
|
63
|
+
release.
|
|
64
|
+
|
|
65
|
+
Requires a harness CLI on PATH: [opencode](https://opencode.ai) (default
|
|
66
|
+
backend) and/or [codex](https://github.com/openai/codex). On a distro-pegged
|
|
67
|
+
pip (e.g. 22.x) an editable install can fail with "build backend is missing
|
|
68
|
+
the build_editable hook" — fix the tool, not the package:
|
|
69
|
+
`pip install -U pip`, then retry.
|
|
70
|
+
|
|
71
|
+
## Quick start (no clone needed)
|
|
72
|
+
|
|
73
|
+
Straight from GitHub, then a one-line sanity check in your terminal:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install git+https://github.com/AlexKay28/ranger
|
|
77
|
+
|
|
78
|
+
python -c "import ranger; print(ranger.Ranger.models(match='claude'))"
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The check needs no model or API budget — it just lists what your local
|
|
82
|
+
opencode CLI offers. Got model ids back? You're ready:
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import ranger
|
|
86
|
+
agent = ranger.Ranger(model="<one of the ids above>")
|
|
87
|
+
print(agent.ask("say ok"))
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Runnable applications live in [examples/](examples/): quickstart, model
|
|
91
|
+
discovery, a full agentic loop, a self-hosted project-growth loop, plus three
|
|
92
|
+
small day-to-day recipes — repair a red test command, independently review a
|
|
93
|
+
local diff before merge, review one file, and draft release notes from git
|
|
94
|
+
history. They are organized by use case in the
|
|
95
|
+
[examples index](examples/README.md): getting started, code work, monitoring,
|
|
96
|
+
multi-agent, backends, and no-model dummy runs.
|
|
97
|
+
|
|
98
|
+
Live progress: each command draws a morphing line on stderr while it runs
|
|
99
|
+
(`⠹ search · TODO items in this repo · 00:03`) and settles as
|
|
100
|
+
`✓ search · 00:07 · <first line of answer>` — opencode-wizard style, colors
|
|
101
|
+
included. It auto-disables in pipes/tests and honors `NO_COLOR`;
|
|
102
|
+
turn it off with `pretty=False`.
|
|
103
|
+
|
|
104
|
+
Model priority: explicit `Ranger(model=...)` → `$RANGER_MODEL` env var →
|
|
105
|
+
package default.
|
|
106
|
+
|
|
107
|
+
## Usage
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
111
|
+
agent.summarize("notes.md") # -> str summary of the file
|
|
112
|
+
agent.write("a one-page report on X") # -> path of the file the agent wrote
|
|
113
|
+
agent.do("rename all *.txt files in data/ to *.md") # -> report of CLI-like work
|
|
114
|
+
agent.search("where do we parse config?") # -> multiline findings report
|
|
115
|
+
agent.ask("anything at all") # -> raw prompt, raw answer
|
|
116
|
+
agent.check("all tests pass") # -> YES/NO verdict as a bool
|
|
117
|
+
agent.gate("python -m pytest -q") # -> exit-code booleans, no model
|
|
118
|
+
agent.until("make the tests green", gate_cmd="python -m pytest -q")
|
|
119
|
+
# -> loop: plan/do/verify until green
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Each call is one fresh headless `opencode run` in the agent's working directory
|
|
123
|
+
(`cwd=`), with permissions auto-approved so it can actually touch the filesystem.
|
|
124
|
+
Pass `session="..."` to share context between calls, `model=` to pick any
|
|
125
|
+
`provider/model` ID from `opencode models`.
|
|
126
|
+
|
|
127
|
+
## Model discovery & configuration
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
import ranger
|
|
131
|
+
|
|
132
|
+
ranger.Ranger.models() # -> all model IDs
|
|
133
|
+
ranger.Ranger.models(match="claude") # -> substring filter
|
|
134
|
+
|
|
135
|
+
smart = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
136
|
+
fast = smart.with_config(model="openrouter/google/gemini-2.5-flash", agent="build")
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Every command method also accepts per-call overrides:
|
|
140
|
+
|
|
141
|
+
```python
|
|
142
|
+
fast.search("todo items", title="quick scan")
|
|
143
|
+
smart.do("refactor auth", timeout=1800)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Overridable: `model`, `timeout`, `auto`, `session`, `agent` (opencode agent
|
|
147
|
+
name like "build"/"plan"), `title`, `thinking`. Unknown keywords raise
|
|
148
|
+
`TypeError` so typos fail loudly.
|
|
149
|
+
|
|
150
|
+
See [docs/commands.md](docs/commands.md) for the full command catalog —
|
|
151
|
+
15 methods at three maturity tiers: what's shipped, what's next, and
|
|
152
|
+
what needs bigger machinery (gates, retries, safety rails) —
|
|
153
|
+
[docs/API.md](docs/API.md) for the complete, per-setting API reference
|
|
154
|
+
(kept mechanically in sync with the code by the test suite), and
|
|
155
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for a high-level tour of
|
|
156
|
+
the codebase and its three architectural decisions.
|
|
157
|
+
|
|
158
|
+
## Context state (memory)
|
|
159
|
+
|
|
160
|
+
The agent remembers. Every command exchange is recorded to
|
|
161
|
+
`agent.context` in classic OpenAI message format
|
|
162
|
+
(`{"role": "user"|"assistant"|"system", "content": ...}`) and recent
|
|
163
|
+
history (within a character budget) is recalled into later runs — so
|
|
164
|
+
follow-ups like "now do the same for tests/" just work.
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
agent.context # the message list
|
|
168
|
+
agent.context_summarize() # -> digest of what happened so far
|
|
169
|
+
agent.context_compact() # collapse history to one system digest
|
|
170
|
+
agent.context_clear() # wipe; returns what was cleared
|
|
171
|
+
agent.ask("...", memory=False) # one stateless run
|
|
172
|
+
ranger.Ranger(memory=False) # or a fully stateless agent
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
Context memory colors your dialogues, never your facts: `ask`/`do`/`write`
|
|
176
|
+
recall the recent conversation; `check`/`search`/`summarize` always run
|
|
177
|
+
history-independent, so a verdict is about the repo, not the chat
|
|
178
|
+
([PARADIGM.md](docs/PARADIGM.md), law 4).
|
|
179
|
+
|
|
180
|
+
## Backends (harness adapters)
|
|
181
|
+
|
|
182
|
+
The same API drives different harnesses; the setting is one constructor
|
|
183
|
+
argument, per-call overridable:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
import ranger
|
|
187
|
+
|
|
188
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5") # opencode (default)
|
|
189
|
+
gpt = ranger.Ranger(backend="codex") # model from ~/.codex/config.toml
|
|
190
|
+
gpt = ranger.Ranger(backend="codex", model="gpt-5.1-codex")
|
|
191
|
+
|
|
192
|
+
ranger.register_backend("mine", MyHarnessAdapter) # your own — one small class
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Harness differences (flags, sessions, sandboxes, output schemas) are
|
|
196
|
+
absorbed by one adapter class per backend — see the Backends section of
|
|
197
|
+
[docs/API.md](docs/API.md) for the full capability map and the recipe for
|
|
198
|
+
adding your own harness.
|
|
199
|
+
|
|
200
|
+
## Multi-agent interactions
|
|
201
|
+
|
|
202
|
+
Two (or three) agents, and the expected patterns as ready-made methods —
|
|
203
|
+
verdicts are grammar, budgets are honest, reviewers run free of their own
|
|
204
|
+
chat history:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
both = builder.second_opinion(critic, prompt) # {mine, theirs, differs}
|
|
208
|
+
verdict = critic.review(subject, author=builder) # APPROVE/REJECT/REQUEST_CHANGES
|
|
209
|
+
outcome = builder.refine_with(critic, goal) # the two-agent until()
|
|
210
|
+
duel = critic.challenge(builder) # adversarial claim attack
|
|
211
|
+
talk = ranger.debate(builder, critic, topic, judge=skeptic)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
See the Multi-agent interactions section of [docs/API.md](docs/API.md)
|
|
215
|
+
and [`examples/multiagent/multi_agent.py`](examples/multiagent/multi_agent.py).
|
|
216
|
+
|
|
217
|
+
## Skills allow-list
|
|
218
|
+
|
|
219
|
+
Grant the agent specific skills or operating rules per run — a markdown
|
|
220
|
+
file or directory rides along via opencode's `--file` attachment; plain
|
|
221
|
+
prose entries are injected as prompt grants.
|
|
222
|
+
|
|
223
|
+
```python
|
|
224
|
+
agent = ranger.Ranger(skills=[
|
|
225
|
+
"skills/haiku/SKILL.md", # file -> --file attachment
|
|
226
|
+
"skills/pack", # dir -> all its *.md attached
|
|
227
|
+
'Always answer in British spelling', # prose -> prompt grant
|
|
228
|
+
])
|
|
229
|
+
agent.do("write the changelog", skills=["docs/changelog_style.md"]) # per call
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
## AGI loop, the point of the whole thing
|
|
233
|
+
|
|
234
|
+
```python
|
|
235
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
236
|
+
|
|
237
|
+
for i in range(10):
|
|
238
|
+
hits = agent.search(f"TODO and unimplemented spots, pass {i}")
|
|
239
|
+
plan = agent.ask(f"Pick ONE thing to fix from:\n{hits}\nReply with a one-line fix plan.")
|
|
240
|
+
report = agent.do(plan)
|
|
241
|
+
print(f"[pass {i}] {report}")
|
|
242
|
+
```
|
rangers-0.6.1/README.md
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
# ranger
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Agent-as-a-library. Run the [opencode](https://opencode.ai) or
|
|
6
|
+
[codex](https://github.com/openai/codex) coding agents headlessly from plain
|
|
7
|
+
Python code — for agentic-loop prototyping. You write code, not chat.
|
|
8
|
+
|
|
9
|
+
The whole design follows one paradigm: **the agent is a function call —
|
|
10
|
+
Python owns the loop, the harness is just the data plane.** Plan → act →
|
|
11
|
+
check → repeat maps 1:1 onto expression, statement and condition. See
|
|
12
|
+
[docs/PARADIGM.md](docs/PARADIGM.md) for the seven laws every feature is
|
|
13
|
+
reviewed against.
|
|
14
|
+
|
|
15
|
+
AI coding agents: start with [SKILL.md](SKILL.md) for the library's safe
|
|
16
|
+
workflow, contracts, and repository contribution rules.
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<img src="https://raw.githubusercontent.com/AlexKay28/ranger/main/docs/cheatsheet.png" alt="ranger command cheatsheet" width="760">
|
|
20
|
+
</p>
|
|
21
|
+
|
|
22
|
+
## Install
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install rangers
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The distribution is named **`rangers`** on PyPI; the Python import remains
|
|
29
|
+
`import ranger`. For development from a clone: `pip install -e .[dev]`.
|
|
30
|
+
Maintainers: see the [publishing checklist](docs/PUBLISHING.md) before any
|
|
31
|
+
release.
|
|
32
|
+
|
|
33
|
+
Requires a harness CLI on PATH: [opencode](https://opencode.ai) (default
|
|
34
|
+
backend) and/or [codex](https://github.com/openai/codex). On a distro-pegged
|
|
35
|
+
pip (e.g. 22.x) an editable install can fail with "build backend is missing
|
|
36
|
+
the build_editable hook" — fix the tool, not the package:
|
|
37
|
+
`pip install -U pip`, then retry.
|
|
38
|
+
|
|
39
|
+
## Quick start (no clone needed)
|
|
40
|
+
|
|
41
|
+
Straight from GitHub, then a one-line sanity check in your terminal:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install git+https://github.com/AlexKay28/ranger
|
|
45
|
+
|
|
46
|
+
python -c "import ranger; print(ranger.Ranger.models(match='claude'))"
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The check needs no model or API budget — it just lists what your local
|
|
50
|
+
opencode CLI offers. Got model ids back? You're ready:
|
|
51
|
+
|
|
52
|
+
```python
|
|
53
|
+
import ranger
|
|
54
|
+
agent = ranger.Ranger(model="<one of the ids above>")
|
|
55
|
+
print(agent.ask("say ok"))
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Runnable applications live in [examples/](examples/): quickstart, model
|
|
59
|
+
discovery, a full agentic loop, a self-hosted project-growth loop, plus three
|
|
60
|
+
small day-to-day recipes — repair a red test command, independently review a
|
|
61
|
+
local diff before merge, review one file, and draft release notes from git
|
|
62
|
+
history. They are organized by use case in the
|
|
63
|
+
[examples index](examples/README.md): getting started, code work, monitoring,
|
|
64
|
+
multi-agent, backends, and no-model dummy runs.
|
|
65
|
+
|
|
66
|
+
Live progress: each command draws a morphing line on stderr while it runs
|
|
67
|
+
(`⠹ search · TODO items in this repo · 00:03`) and settles as
|
|
68
|
+
`✓ search · 00:07 · <first line of answer>` — opencode-wizard style, colors
|
|
69
|
+
included. It auto-disables in pipes/tests and honors `NO_COLOR`;
|
|
70
|
+
turn it off with `pretty=False`.
|
|
71
|
+
|
|
72
|
+
Model priority: explicit `Ranger(model=...)` → `$RANGER_MODEL` env var →
|
|
73
|
+
package default.
|
|
74
|
+
|
|
75
|
+
## Usage
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
79
|
+
agent.summarize("notes.md") # -> str summary of the file
|
|
80
|
+
agent.write("a one-page report on X") # -> path of the file the agent wrote
|
|
81
|
+
agent.do("rename all *.txt files in data/ to *.md") # -> report of CLI-like work
|
|
82
|
+
agent.search("where do we parse config?") # -> multiline findings report
|
|
83
|
+
agent.ask("anything at all") # -> raw prompt, raw answer
|
|
84
|
+
agent.check("all tests pass") # -> YES/NO verdict as a bool
|
|
85
|
+
agent.gate("python -m pytest -q") # -> exit-code booleans, no model
|
|
86
|
+
agent.until("make the tests green", gate_cmd="python -m pytest -q")
|
|
87
|
+
# -> loop: plan/do/verify until green
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Each call is one fresh headless `opencode run` in the agent's working directory
|
|
91
|
+
(`cwd=`), with permissions auto-approved so it can actually touch the filesystem.
|
|
92
|
+
Pass `session="..."` to share context between calls, `model=` to pick any
|
|
93
|
+
`provider/model` ID from `opencode models`.
|
|
94
|
+
|
|
95
|
+
## Model discovery & configuration
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
import ranger
|
|
99
|
+
|
|
100
|
+
ranger.Ranger.models() # -> all model IDs
|
|
101
|
+
ranger.Ranger.models(match="claude") # -> substring filter
|
|
102
|
+
|
|
103
|
+
smart = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
104
|
+
fast = smart.with_config(model="openrouter/google/gemini-2.5-flash", agent="build")
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Every command method also accepts per-call overrides:
|
|
108
|
+
|
|
109
|
+
```python
|
|
110
|
+
fast.search("todo items", title="quick scan")
|
|
111
|
+
smart.do("refactor auth", timeout=1800)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Overridable: `model`, `timeout`, `auto`, `session`, `agent` (opencode agent
|
|
115
|
+
name like "build"/"plan"), `title`, `thinking`. Unknown keywords raise
|
|
116
|
+
`TypeError` so typos fail loudly.
|
|
117
|
+
|
|
118
|
+
See [docs/commands.md](docs/commands.md) for the full command catalog —
|
|
119
|
+
15 methods at three maturity tiers: what's shipped, what's next, and
|
|
120
|
+
what needs bigger machinery (gates, retries, safety rails) —
|
|
121
|
+
[docs/API.md](docs/API.md) for the complete, per-setting API reference
|
|
122
|
+
(kept mechanically in sync with the code by the test suite), and
|
|
123
|
+
[docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for a high-level tour of
|
|
124
|
+
the codebase and its three architectural decisions.
|
|
125
|
+
|
|
126
|
+
## Context state (memory)
|
|
127
|
+
|
|
128
|
+
The agent remembers. Every command exchange is recorded to
|
|
129
|
+
`agent.context` in classic OpenAI message format
|
|
130
|
+
(`{"role": "user"|"assistant"|"system", "content": ...}`) and recent
|
|
131
|
+
history (within a character budget) is recalled into later runs — so
|
|
132
|
+
follow-ups like "now do the same for tests/" just work.
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
agent.context # the message list
|
|
136
|
+
agent.context_summarize() # -> digest of what happened so far
|
|
137
|
+
agent.context_compact() # collapse history to one system digest
|
|
138
|
+
agent.context_clear() # wipe; returns what was cleared
|
|
139
|
+
agent.ask("...", memory=False) # one stateless run
|
|
140
|
+
ranger.Ranger(memory=False) # or a fully stateless agent
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Context memory colors your dialogues, never your facts: `ask`/`do`/`write`
|
|
144
|
+
recall the recent conversation; `check`/`search`/`summarize` always run
|
|
145
|
+
history-independent, so a verdict is about the repo, not the chat
|
|
146
|
+
([PARADIGM.md](docs/PARADIGM.md), law 4).
|
|
147
|
+
|
|
148
|
+
## Backends (harness adapters)
|
|
149
|
+
|
|
150
|
+
The same API drives different harnesses; the setting is one constructor
|
|
151
|
+
argument, per-call overridable:
|
|
152
|
+
|
|
153
|
+
```python
|
|
154
|
+
import ranger
|
|
155
|
+
|
|
156
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5") # opencode (default)
|
|
157
|
+
gpt = ranger.Ranger(backend="codex") # model from ~/.codex/config.toml
|
|
158
|
+
gpt = ranger.Ranger(backend="codex", model="gpt-5.1-codex")
|
|
159
|
+
|
|
160
|
+
ranger.register_backend("mine", MyHarnessAdapter) # your own — one small class
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
Harness differences (flags, sessions, sandboxes, output schemas) are
|
|
164
|
+
absorbed by one adapter class per backend — see the Backends section of
|
|
165
|
+
[docs/API.md](docs/API.md) for the full capability map and the recipe for
|
|
166
|
+
adding your own harness.
|
|
167
|
+
|
|
168
|
+
## Multi-agent interactions
|
|
169
|
+
|
|
170
|
+
Two (or three) agents, and the expected patterns as ready-made methods —
|
|
171
|
+
verdicts are grammar, budgets are honest, reviewers run free of their own
|
|
172
|
+
chat history:
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
both = builder.second_opinion(critic, prompt) # {mine, theirs, differs}
|
|
176
|
+
verdict = critic.review(subject, author=builder) # APPROVE/REJECT/REQUEST_CHANGES
|
|
177
|
+
outcome = builder.refine_with(critic, goal) # the two-agent until()
|
|
178
|
+
duel = critic.challenge(builder) # adversarial claim attack
|
|
179
|
+
talk = ranger.debate(builder, critic, topic, judge=skeptic)
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
See the Multi-agent interactions section of [docs/API.md](docs/API.md)
|
|
183
|
+
and [`examples/multiagent/multi_agent.py`](examples/multiagent/multi_agent.py).
|
|
184
|
+
|
|
185
|
+
## Skills allow-list
|
|
186
|
+
|
|
187
|
+
Grant the agent specific skills or operating rules per run — a markdown
|
|
188
|
+
file or directory rides along via opencode's `--file` attachment; plain
|
|
189
|
+
prose entries are injected as prompt grants.
|
|
190
|
+
|
|
191
|
+
```python
|
|
192
|
+
agent = ranger.Ranger(skills=[
|
|
193
|
+
"skills/haiku/SKILL.md", # file -> --file attachment
|
|
194
|
+
"skills/pack", # dir -> all its *.md attached
|
|
195
|
+
'Always answer in British spelling', # prose -> prompt grant
|
|
196
|
+
])
|
|
197
|
+
agent.do("write the changelog", skills=["docs/changelog_style.md"]) # per call
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## AGI loop, the point of the whole thing
|
|
201
|
+
|
|
202
|
+
```python
|
|
203
|
+
agent = ranger.Ranger(model="openrouter/anthropic/claude-sonnet-4.5")
|
|
204
|
+
|
|
205
|
+
for i in range(10):
|
|
206
|
+
hits = agent.search(f"TODO and unimplemented spots, pass {i}")
|
|
207
|
+
plan = agent.ask(f"Pick ONE thing to fix from:\n{hits}\nReply with a one-line fix plan.")
|
|
208
|
+
report = agent.do(plan)
|
|
209
|
+
print(f"[pass {i}] {report}")
|
|
210
|
+
```
|
rangers-0.6.1/SKILL.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ranger
|
|
3
|
+
description: Use the ranger Python library to drive headless coding agents from ordinary Python. Load BEFORE writing a Ranger loop, agent-backed repair or review workflow, multi-agent composition, custom backend, or tests around ranger. Triggers - ranger, rangers, Ranger(), agent-as-a-library, headless coding agent in Python, ask/do/check/until/refine_with, coding-agent loop, агент как библиотека, цикл агента на Python, ранжер. Do NOT use for a hosted agent runtime, background task queue, or streaming chat server - ranger intentionally has none; Python owns the loop.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# ranger — agent-as-a-library
|
|
7
|
+
|
|
8
|
+
`rangers` is the PyPI distribution; the import is `ranger`:
|
|
9
|
+
|
|
10
|
+
```python
|
|
11
|
+
# shell: pip install rangers
|
|
12
|
+
import ranger
|
|
13
|
+
|
|
14
|
+
agent = ranger.Ranger(cwd="/path/to/project", timeout=180)
|
|
15
|
+
answer = agent.ask("Find the smallest safe fix for the failing parser test.")
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Every live Ranger call starts one headless harness CLI process and blocks until
|
|
19
|
+
it returns. Python, not an agent runtime, owns the control flow.
|
|
20
|
+
|
|
21
|
+
## Non-negotiable rules
|
|
22
|
+
|
|
23
|
+
| Need | Use | Do not substitute |
|
|
24
|
+
|---|---|---|
|
|
25
|
+
| Open-ended answer or one small plan | `ask(prompt)` | A custom chat loop |
|
|
26
|
+
| Make a filesystem change | `do(goal)` | A claim that a change happened |
|
|
27
|
+
| Produce one document | `write(task, path=...)` | Parsing prose for a filename |
|
|
28
|
+
| Read-only codebase findings | `search(goal)` / `summarize(file)` | `do()` |
|
|
29
|
+
| Agent-verified fact | `check(condition)` | Truthy prose; it must parse YES/NO |
|
|
30
|
+
| Deterministic acceptance | `gate(shell_command)` | An agent's opinion |
|
|
31
|
+
| Bounded repair loop | `until(..., gate_cmd=..., max_iter=N)` | An unbounded `while` loop |
|
|
32
|
+
| Independent review | `critic.review(subject, author=claims)` | Trusting the author report |
|
|
33
|
+
|
|
34
|
+
**Use a mechanical gate whenever one exists.** For a repair, the shell test
|
|
35
|
+
command decides success:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
result = agent.until(
|
|
39
|
+
"Make the parser tests pass; reproduce first and make the smallest fix.",
|
|
40
|
+
gate_cmd="python -m pytest -q tests/test_parser.py",
|
|
41
|
+
max_iter=2,
|
|
42
|
+
)
|
|
43
|
+
if not result["achieved"]:
|
|
44
|
+
raise RuntimeError(result["report"])
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
`until` never invents success after its budget runs out. `gate()` returns only
|
|
48
|
+
an exit-code boolean and does not call a model.
|
|
49
|
+
|
|
50
|
+
## Costs, cancellation, and state
|
|
51
|
+
|
|
52
|
+
- Set an explicit `timeout=` for real work and a small `max_iter`/`rounds`
|
|
53
|
+
budget for every loop. A loop costs one or more full CLI calls per iteration.
|
|
54
|
+
- Ctrl+C / notebook interrupt raises `KeyboardInterrupt`, stops the CLI client,
|
|
55
|
+
and retires the progress spinner. Long loops put honest partial state in the
|
|
56
|
+
interrupt message; nothing is claimed complete.
|
|
57
|
+
- `ask`, `do`, and `write` record and recall bounded `agent.context`. Treat it
|
|
58
|
+
as conversational color, never as a fact store.
|
|
59
|
+
- `check`, `search`, `summarize`, `review`, challenge judgments, and debate
|
|
60
|
+
judges are memory- and session-free by contract. Do not try to override that
|
|
61
|
+
purity with `session=`.
|
|
62
|
+
- A model answer is not a success signal. `check()` rejects ambiguous,
|
|
63
|
+
contradictory, or uncertain replies with `RangerError`.
|
|
64
|
+
|
|
65
|
+
## Multi-agent work
|
|
66
|
+
|
|
67
|
+
Interactions are normal Python compositions, not a scheduler or swarm.
|
|
68
|
+
Pass another agent's report as **unverified claims** and let the receiver verify
|
|
69
|
+
the repository itself:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
builder = ranger.Ranger(cwd=".", timeout=180)
|
|
73
|
+
critic = ranger.Ranger(cwd=".", timeout=180)
|
|
74
|
+
|
|
75
|
+
outcome = builder.refine_with(
|
|
76
|
+
critic,
|
|
77
|
+
"Add a regression test for empty parser input and make it pass.",
|
|
78
|
+
max_iter=2,
|
|
79
|
+
)
|
|
80
|
+
if not outcome["approved"]:
|
|
81
|
+
print(outcome["reviews"][-1]["changes"])
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use the smallest fitting pattern:
|
|
85
|
+
|
|
86
|
+
- `second_opinion(other, prompt)` — compare two answers; disagreement is the
|
|
87
|
+
signal, not a vote.
|
|
88
|
+
- `review(subject, author=...)` — strict `VERDICT`, `FINDINGS`, `CHANGES`.
|
|
89
|
+
- `challenge(other, claim=..., rounds=1)` — adversarial evidence check.
|
|
90
|
+
- `refine_with(critic, goal, max_iter=2)` — do → review → revise.
|
|
91
|
+
- `ranger.debate(a, b, topic, judge=...)` — surface factual disagreements;
|
|
92
|
+
the judge digests evidence and never crowns a winner.
|
|
93
|
+
|
|
94
|
+
Do not parse model prose yourself. The interaction methods validate their
|
|
95
|
+
frozen grammars and raise `RangerError` on malformed or conflicting replies.
|
|
96
|
+
|
|
97
|
+
## Backends and models
|
|
98
|
+
|
|
99
|
+
- Use `Ranger(backend="opencode")` (default) or `Ranger(backend="codex")`.
|
|
100
|
+
The public API stays the same; CLI flags and output parsing do not.
|
|
101
|
+
- Use OpenRouter-style public model IDs in repository files. Do **not** add
|
|
102
|
+
internal provider/model names to code, docs, examples, tests, or commits.
|
|
103
|
+
- For a new harness, register a small adapter with
|
|
104
|
+
`ranger.register_backend(name, adapter_cls)`; do not fork command logic.
|
|
105
|
+
- Resolve a model only when needed: explicit per-call model beats constructor,
|
|
106
|
+
then `RANGER_MODEL`, then the effective backend's default.
|
|
107
|
+
|
|
108
|
+
## Contributing to this repository
|
|
109
|
+
|
|
110
|
+
- Read [docs/PARADIGM.md](docs/PARADIGM.md) before changing public behavior.
|
|
111
|
+
The core laws are grammar over vibes, explicit Python state, and a
|
|
112
|
+
replaceable harness data plane.
|
|
113
|
+
- Keep normal tests fully mocked. Agent calls use the
|
|
114
|
+
`ranger.subprocess.run` seam; `gate()` uses `ranger.subprocess.Popen`.
|
|
115
|
+
Do not put live opencode/codex calls in the test suite.
|
|
116
|
+
- Add truth-table tests for parsers, verdicts, option precedence, and loop
|
|
117
|
+
outcomes. The suite has a strict one-minute budget.
|
|
118
|
+
- Update `docs/API.md`, README, examples, and docs gates whenever public API
|
|
119
|
+
changes. Examples must be main-guarded and import-safe.
|
|
120
|
+
- Run `python -m pytest -q`; for releases also run `python -m build` and
|
|
121
|
+
`python -m twine check --strict dist/*`. See [docs/PUBLISHING.md](docs/PUBLISHING.md).
|
|
122
|
+
|
|
123
|
+
## Execution-bug feedback for maintainers
|
|
124
|
+
|
|
125
|
+
If a user asks you to use ranger and you encounter a reproducible library or
|
|
126
|
+
harness-execution bug, help the maintainers learn from it: create an issue at
|
|
127
|
+
[`AlexKay28/ranger`](https://github.com/AlexKay28/ranger/issues) when GitHub
|
|
128
|
+
authentication and issue-creation permission are available. If they are not,
|
|
129
|
+
give the user the complete ready-to-paste issue instead. Do this after a
|
|
130
|
+
minimal reproduction attempt — not for a malformed prompt, a missing CLI, an
|
|
131
|
+
expired model quota, or an expected `RangerError` caused by invalid input.
|
|
132
|
+
|
|
133
|
+
**Never include secrets.** Redact API tokens, credentials, private prompts,
|
|
134
|
+
absolute private paths, and proprietary source. Link to public output only.
|
|
135
|
+
|
|
136
|
+
Use this issue format:
|
|
137
|
+
|
|
138
|
+
````markdown
|
|
139
|
+
## ranger execution bug
|
|
140
|
+
|
|
141
|
+
**ranger version:** `ranger.__version__`
|
|
142
|
+
**Python / OS:** `python --version`; operating system
|
|
143
|
+
**Backend / model:** `opencode|codex`; public model ID or `redacted`
|
|
144
|
+
**Command or minimal code:**
|
|
145
|
+
```python
|
|
146
|
+
# smallest self-contained reproduction
|
|
147
|
+
```
|
|
148
|
+
**Expected behavior:** what should have happened
|
|
149
|
+
**Actual behavior:** exact exception, exit code, or unexpected result
|
|
150
|
+
**Reproduction:** always / intermittent; smallest known steps
|
|
151
|
+
**Relevant non-secret context:** timeout, session/memory setting, and whether
|
|
152
|
+
the problem remains with `memory=False` and a fresh session
|
|
153
|
+
````
|
|
154
|
+
|
|
155
|
+
Title issues as: `bug: <short observable failure>`. Before filing, search
|
|
156
|
+
existing open issues for the same error and add reproduction details there
|
|
157
|
+
instead of creating a duplicate. The report is feedback, not a substitute for
|
|
158
|
+
the user's immediate workaround: state the workaround or honest blocker too.
|
|
159
|
+
|
|
160
|
+
## Choose an example before inventing a workflow
|
|
161
|
+
|
|
162
|
+
See [examples/README.md](examples/README.md) for runnable recipes:
|
|
163
|
+
|
|
164
|
+
- `examples/code-work/fix_failing_tests.py` — bounded repair with a real test
|
|
165
|
+
command as the gate.
|
|
166
|
+
- `examples/code-work/simple_code_review.py` — one file, one strict verdict.
|
|
167
|
+
- `examples/monitoring/project_health.py` — read-only health snapshot.
|
|
168
|
+
- `examples/multiagent/multi_agent.py` — all collaboration patterns.
|
|
169
|
+
- `examples/dummy/mechanical_gates.py` — no model or login required.
|