sutra-agent 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sutra_agent-0.3.0/LICENSE +21 -0
- sutra_agent-0.3.0/MANIFEST.in +9 -0
- sutra_agent-0.3.0/PKG-INFO +267 -0
- sutra_agent-0.3.0/README.md +243 -0
- sutra_agent-0.3.0/__init__.py +157 -0
- sutra_agent-0.3.0/claude_code.py +611 -0
- sutra_agent-0.3.0/cli.py +350 -0
- sutra_agent-0.3.0/codex.py +242 -0
- sutra_agent-0.3.0/config.py +155 -0
- sutra_agent-0.3.0/core.py +204 -0
- sutra_agent-0.3.0/discovery.py +212 -0
- sutra_agent-0.3.0/engine.py +657 -0
- sutra_agent-0.3.0/hermes.py +275 -0
- sutra_agent-0.3.0/hook.py +24 -0
- sutra_agent-0.3.0/installer.py +143 -0
- sutra_agent-0.3.0/jsonc.py +248 -0
- sutra_agent-0.3.0/mcp.py +22 -0
- sutra_agent-0.3.0/metrics.py +233 -0
- sutra_agent-0.3.0/opencode.py +406 -0
- sutra_agent-0.3.0/opencode_plugin.js +161 -0
- sutra_agent-0.3.0/plugin.yaml +8 -0
- sutra_agent-0.3.0/pyproject.toml +61 -0
- sutra_agent-0.3.0/recovery.py +508 -0
- sutra_agent-0.3.0/runner.py +34 -0
- sutra_agent-0.3.0/scripts/_sutra.py +27 -0
- sutra_agent-0.3.0/scripts/check_version.py +44 -0
- sutra_agent-0.3.0/scripts/sutra-claude-code-hook.py +157 -0
- sutra_agent-0.3.0/scripts/sutra-cli.py +165 -0
- sutra_agent-0.3.0/scripts/sutra-mcp-server.py +177 -0
- sutra_agent-0.3.0/setup.cfg +4 -0
- sutra_agent-0.3.0/store.py +543 -0
- sutra_agent-0.3.0/sutra_agent.egg-info/PKG-INFO +267 -0
- sutra_agent-0.3.0/sutra_agent.egg-info/SOURCES.txt +60 -0
- sutra_agent-0.3.0/sutra_agent.egg-info/dependency_links.txt +1 -0
- sutra_agent-0.3.0/sutra_agent.egg-info/entry_points.txt +4 -0
- sutra_agent-0.3.0/sutra_agent.egg-info/top_level.txt +1 -0
- sutra_agent-0.3.0/utf8.py +41 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2019 aler9
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The wheel carries the runtime package; the sdist carries the same files plus
|
|
2
|
+
# packaging metadata. The development test suite is not installed with the
|
|
3
|
+
# package (its conftest is what makes the checkout layout importable), so
|
|
4
|
+
# shipping half of it in the sdist is worse than shipping none.
|
|
5
|
+
prune tests
|
|
6
|
+
|
|
7
|
+
# Release tooling is useful to anyone rebuilding from the sdist, but it is not
|
|
8
|
+
# runtime code: the wheel excludes it through the explicit package-data list.
|
|
9
|
+
include scripts/check_version.py
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sutra-agent
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Deterministic tool-output reduction for AI agents, preserving the evidence that matters.
|
|
5
|
+
Author: Vishal Gurung
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://sutra-alive.vercel.app/
|
|
8
|
+
Project-URL: Repository, https://github.com/g0GobliN/sutra
|
|
9
|
+
Project-URL: Documentation, https://github.com/g0GobliN/sutra/blob/main/docs/README.md
|
|
10
|
+
Project-URL: Changelog, https://github.com/g0GobliN/sutra/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Issues, https://github.com/g0GobliN/sutra/issues
|
|
12
|
+
Keywords: ai-agents,context-compression,tool-output,mcp
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Dynamic: license-file
|
|
24
|
+
|
|
25
|
+
<p align="center">
|
|
26
|
+
<img src="https://raw.githubusercontent.com/g0GobliN/sutra/main/public/logo/sutraThumb.png" alt="SUTRA" width="520">
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+
# SUTRA
|
|
30
|
+
|
|
31
|
+
**Less output. More signal.**
|
|
32
|
+
|
|
33
|
+
SUTRA is a deterministic tool-output optimization and recovery layer for AI coding agents. It processes eligible tool results after a command runs and before the model reads them, so a large log costs less context on every following turn — without a model paraphrasing it.
|
|
34
|
+
|
|
35
|
+
One core. Multiple agents. Recoverable output. No compression model calls.
|
|
36
|
+
|
|
37
|
+
> **Eight-fixture benchmark:** payload size reduced by **54.3%**, o200k tokenizer counts by **55.2%**; **8/8** planted clues recovered; **0** diffs touched. The fixtures are generated tool-output shapes and the token figure is not a provider bill — [method](#evidence-and-benchmarks).
|
|
38
|
+
|
|
39
|
+
[Why](#the-problem-tool-output-is-re-read-all-session) · [How it works](#how-sutra-handles-a-tool-result) · [Architecture](#architecture) · [Comparison](#how-sutra-compares-with-caveman-and-ponytail) · [Evidence](#evidence-and-benchmarks) · [Install](#install) · [Integrations](#supported-integrations) · [Limitations](#limitations)
|
|
40
|
+
|
|
41
|
+
## The problem: tool output is re-read all session
|
|
42
|
+
|
|
43
|
+
An agent runs `pytest -q`, receives 12,000 lines, and needs one failure. The useful part may be twenty lines, but the tool result stays in context and is re-sent on every subsequent turn. Prompt compression can shave an instruction once; tool output grows with every command an agent runs.
|
|
44
|
+
|
|
45
|
+
```text
|
|
46
|
+
turn 1 ── tool output 60.9 kB ──► model
|
|
47
|
+
turn 2 ── tool output 60.9 kB ──► model (re-sent)
|
|
48
|
+
turn 3 ── tool output 60.9 kB ──► model (re-sent)
|
|
49
|
+
... context grows with the session
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
The agent rarely needs the whole result: it needs the failing line, the stack frame, the row that matters — and a route back to everything else.
|
|
53
|
+
|
|
54
|
+
## How SUTRA handles a tool result
|
|
55
|
+
|
|
56
|
+
1. **The tool runs normally.** SUTRA does not wrap, delay or re-execute it.
|
|
57
|
+
2. **The host adapter hands the result to the shared core.** The core decides whether the result is eligible: size, payload shape, evidence tools, diffs.
|
|
58
|
+
3. **The core rewrites only what is safe to remove.** ANSI escapes, repeated lines and oversized middles are elided; diffs stay byte-identical, JSON keeps its shape, a traceback keeps its error end.
|
|
59
|
+
4. **The original is retained locally** when storage is enabled, with a bounded lifetime.
|
|
60
|
+
5. **The model sees a smaller result with a marker** naming what was removed, how much, and the exact `sutra_restore` call that returns it.
|
|
61
|
+
6. **Nothing is generated.** No summariser, no model call, no interpretation, no invented content.
|
|
62
|
+
|
|
63
|
+
If anything is unexpected — a malformed payload, a failed store write, an internal exception — SUTRA fails open and the host receives the original result unchanged.
|
|
64
|
+
|
|
65
|
+
## What makes SUTRA different
|
|
66
|
+
|
|
67
|
+
- **Deterministic, not probabilistic.** The same bytes produce the same rewrite and the same marker. No compression model decides what matters.
|
|
68
|
+
- **Recoverable by construction.** An id is written only after the original is on disk. A marker never cites bytes that were not kept.
|
|
69
|
+
- **Agent-agnostic core.** Hermes, Claude Code, OpenCode, Codex, MCP and the CLI all call the same eligibility, compression, storage and recovery code.
|
|
70
|
+
- **Host-appropriate integration.** Automatic replacement only where the host documents a result-replacing hook; explicit tools or MCP registration where it does not.
|
|
71
|
+
- **Safety boundaries that hold.** Diffs and patches are never rewritten, JSON is never byte-sliced, traceback tails are never dropped.
|
|
72
|
+
- **Fail-open at every adapter.** A broken host payload or a missing interpreter leaves normal agent execution alone.
|
|
73
|
+
|
|
74
|
+
| Capability | What it means in practice |
|
|
75
|
+
|---|---|
|
|
76
|
+
| Deterministic rules, no compression model | Logs are never interpreted or paraphrased by another model |
|
|
77
|
+
| Local original retention | Anything SUTRA omitted can be retrieved later, by id |
|
|
78
|
+
| Native host adapters | No manual compression step on hosts with a result hook |
|
|
79
|
+
| Diff and shape protection | Code changes are never silently rewritten; JSON stays JSON |
|
|
80
|
+
| Fail-open design | A malformed result leaves the agent running normally |
|
|
81
|
+
| Shared core | The same rules, markers and recovery across every integration |
|
|
82
|
+
|
|
83
|
+
## Architecture
|
|
84
|
+
|
|
85
|
+
```text
|
|
86
|
+
AI coding agent
|
|
87
|
+
│ runs a tool
|
|
88
|
+
▼
|
|
89
|
+
tool execution
|
|
90
|
+
│ raw result
|
|
91
|
+
▼
|
|
92
|
+
host adapter
|
|
93
|
+
├─ Hermes: tool_execution middleware automatic
|
|
94
|
+
├─ Claude Code: PostToolUse hook automatic
|
|
95
|
+
├─ OpenCode: tool.execute.after plugin automatic
|
|
96
|
+
├─ Codex: MCP registration only explicit calls
|
|
97
|
+
└─ other clients: CLI or MCP server explicit calls
|
|
98
|
+
│
|
|
99
|
+
▼
|
|
100
|
+
shared SUTRA core
|
|
101
|
+
├─ eligibility: size, payload shape, evidence tools, diffs
|
|
102
|
+
├─ deterministic rewrite + a marker naming what was removed
|
|
103
|
+
└─ local retention (TTL, quota, bounded reads)
|
|
104
|
+
│
|
|
105
|
+
▼
|
|
106
|
+
model reads the smaller result
|
|
107
|
+
│ marker quotes: sutra_restore(id="…", mode="…")
|
|
108
|
+
▼
|
|
109
|
+
original retrieved from the local store when needed
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
The recovery path is separate from the compression path: compression can run with storage disabled, but then the marker says the original was not retained and the model can only re-run the command narrower. Recovery reads the local store by validated id and bounded mode.
|
|
113
|
+
|
|
114
|
+
## How SUTRA compares with Caveman and Ponytail
|
|
115
|
+
|
|
116
|
+
SUTRA and [Caveman](https://github.com/JuliusBrussee/caveman) approach context efficiency from different architectural directions. Both address unnecessary context consumption, but SUTRA specialises in deterministic, recoverable tool-output processing at the integration layer. [Ponytail](https://github.com/DietrichGebert/ponytail) pulls a third lever: how much code the agent writes at all.
|
|
117
|
+
|
|
118
|
+
| Dimension | SUTRA | Caveman | Ponytail |
|
|
119
|
+
|---|---|---|---|
|
|
120
|
+
| Primary focus | Deterministic tool-output processing | Agent brevity plus the inputs it reads | How much code the agent writes |
|
|
121
|
+
| Where it acts | Between a tool result and the model, through host adapters | Skill plus CLI/proxy around the agent | Skill/rules before code is generated |
|
|
122
|
+
| What it transforms | Logs, JSON documents, tracebacks; diffs untouched | Replies, tool-readable files, web pages; routing and blocks in 4.0 | The agent's plan and implementation choices |
|
|
123
|
+
| Original recovery | Local bounded store, id marker, `sutra_restore` | Docs state originals stay on disk and can be pulled back | Not a compression layer; no recovery surface claimed |
|
|
124
|
+
| Model calls for compression | None — deterministic rules | No separate compression model for the voice; file compressors are tooling | None; the effect depends on the host model following its rules |
|
|
125
|
+
| Prompt handling | Does not touch prompts or replies | Docs state prompts are never rewritten | A prompt/rules layer by design |
|
|
126
|
+
| Agent support | Four first-class adapters plus MCP/CLI; automatic only where a result hook exists | 30+ agents via skill/installer | Many agents via skill/plugin |
|
|
127
|
+
|
|
128
|
+
The closest overlap is Caveman's "read less" path, which also shrinks what the model reads and keeps originals retrievable. SUTRA's difference is scope and guarantee: one deterministic, byte-level transform on the tool-result path, one local recovery protocol, and no automatic claim on a host that lacks a result hook.
|
|
129
|
+
|
|
130
|
+
Caveman's README reports 33.2% fewer input tokens across whole sessions (older engine), 8.5% fewer output tokens in a JetBrains paired test, and one HTML case 9.9% worse; Ponytail reports 45% fewer tokens and 53% less code on its 39-task benchmark. Those are their own measurements on their own workloads. Sources: [Caveman README](https://github.com/JuliusBrussee/caveman), [Caveman product page](https://caveman.so/products/caveman), [Ponytail README](https://github.com/DietrichGebert/ponytail). Details may change.
|
|
131
|
+
|
|
132
|
+
## Evidence and benchmarks
|
|
133
|
+
|
|
134
|
+

|
|
135
|
+
|
|
136
|
+
| Payload | Rule | Bytes before → after | o200k tokens before → after | Saved |
|
|
137
|
+
|---|---|---:|---:|---:|
|
|
138
|
+
| 12,000-line command output | `head-tail` | 60.9 kB → 18.6 kB | 35,000 → 10,149 | 71.0% |
|
|
139
|
+
| JSON tool envelope | `json-fields` | 85.9 kB → 19.2 kB | 26,012 → 5,670 | 78.2% |
|
|
140
|
+
| Test run, 2,000 cases | `head-tail` | 99.8 kB → 18.6 kB | 29,998 → 5,529 | 81.6% |
|
|
141
|
+
| 3,000-frame traceback | `traceback` | 359.4 kB → 10.3 kB | 126,015 → 3,680 | 97.1% |
|
|
142
|
+
| 432 kB patch | `diff-kept` | 432.1 kB → 432.1 kB | 120,039 → 120,039 | 0.0% |
|
|
143
|
+
| 900-row SQL result | `head-tail` | 46.6 kB → 18.5 kB | 18,906 → 7,543 | 60.1% |
|
|
144
|
+
| 8,000-line build log | `head-tail` | 334.9 kB → 18.6 kB | 127,005 → 6,905 | 94.6% |
|
|
145
|
+
| 8,000-item JSON array | `json-kept` | 206.9 kB → 206.9 kB | 103,002 → 103,002 | 0.0% |
|
|
146
|
+
| **Total** | | **1.63 MB → 742.7 kB (54.3%)** | **585,977 → 262,517 (55.2%)** | |
|
|
147
|
+
|
|
148
|
+
The patch row saves nothing on purpose: a compressor that shrinks diffs can hide a code change. The JSON-array row saves nothing because keeping the array an array leaves nothing safe to remove. Five buried clues needed one `sutra_restore` call (about 700 B each; the single-line JSON envelope cost 8.9 kB); three were already visible.
|
|
149
|
+
|
|
150
|
+
What the numbers are — and are not:
|
|
151
|
+
|
|
152
|
+
- Payload bytes and `tiktoken o200k_base` tokenizer counts on the payload text.
|
|
153
|
+
- Not provider input tokens, not prompt-cache effects, not an invoice, and not a live-agent task-success score. No model was called for any number here.
|
|
154
|
+
- 8/8 proves the clue is retained and retrievable; it does not prove an agent will ask for it.
|
|
155
|
+
|
|
156
|
+
Method, fixtures, per-phase timings, memory, recovery costs and reproduction: [docs/benchmark.md](https://github.com/g0GobliN/sutra/blob/main/docs/benchmark.md). The frozen live-model A/B protocol is in [docs/ab-benchmark.md](https://github.com/g0GobliN/sutra/blob/main/docs/ab-benchmark.md); it has not been run.
|
|
157
|
+
|
|
158
|
+
## Safety, recovery and trust
|
|
159
|
+
|
|
160
|
+
Every rewrite leaves a marker in place of the omitted bytes:
|
|
161
|
+
|
|
162
|
+
```text
|
|
163
|
+
… [sutra: partial · 133,522 bytes elided (large output) · id=su_3e72c41e… ·
|
|
164
|
+
original 151,920 B retained 168h ·
|
|
165
|
+
retrieve: sutra_restore(id="su_3e72c41e…", mode="bytes", start=12259, end=145781)] …
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
The marker answers four questions: is this complete, what is missing and why, is the original still available, and exactly how to get it. `sutra_restore` supports exact byte ranges, line ranges, literal search and `full` when it fits, with paging that reproduces the original slice byte for byte.
|
|
169
|
+
|
|
170
|
+
Safety properties you can rely on:
|
|
171
|
+
|
|
172
|
+
- **Diffs and patches are byte-identical.** Always.
|
|
173
|
+
- **JSON keeps its shape.** Documents are decoded and re-encoded, never byte-sliced; an array stays an array.
|
|
174
|
+
- **Tracebacks keep their error end.** Only the middle is elided.
|
|
175
|
+
- **An id means the bytes exist.** If storage is off, full or the write failed, the marker says "not retained" and quotes no id.
|
|
176
|
+
- **Fail-open.** Any unexpected shape, parse error or internal exception leaves the original result untouched.
|
|
177
|
+
- **Bounded storage.** Defaults: 32 MiB per entry, 128 MiB total, 2,000 entries, 7-day TTL, 8 KiB recovery response (64 KiB hard cap). The store is local and **not encrypted**; it is protected by filesystem permissions, and tool output can contain secrets. Set `SUTRA_STORE=0` to opt out.
|
|
178
|
+
|
|
179
|
+
Read the full threat model in [SECURITY.md](https://github.com/g0GobliN/sutra/blob/main/SECURITY.md), the guarantees in [docs/contract.md](https://github.com/g0GobliN/sutra/blob/main/docs/contract.md), and the recovery protocol in [docs/recovery.md](https://github.com/g0GobliN/sutra/blob/main/docs/recovery.md).
|
|
180
|
+
|
|
181
|
+
## Install
|
|
182
|
+
|
|
183
|
+
The distribution is `sutra-agent`; the `sutra` name on PyPI belongs to an unrelated package.
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
python3 -m venv ~/.sutra-venv
|
|
187
|
+
~/.sutra-venv/bin/pip install sutra-agent
|
|
188
|
+
~/.sutra-venv/bin/sutra --version # sutra 0.3.0
|
|
189
|
+
|
|
190
|
+
~/.sutra-venv/bin/sutra detect # read-only: what is installed
|
|
191
|
+
~/.sutra-venv/bin/sutra install --dry-run
|
|
192
|
+
~/.sutra-venv/bin/sutra install # configure every detected client
|
|
193
|
+
~/.sutra-venv/bin/sutra doctor # prove the installed paths
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
If the index you use does not serve 0.3.0 yet, install the checkout instead:
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
git clone https://github.com/g0GobliN/sutra
|
|
200
|
+
~/.sutra-venv/bin/pip install ./sutra
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
`sutra install` auto-detects Hermes, Claude Code, OpenCode and Codex. Each change is backed up first and can be removed with `sutra uninstall`; `--dry-run` prints the change and writes nothing. Restart the host after installing a plugin or hook.
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
~/.sutra-venv/bin/sutra uninstall # remove only SUTRA-owned entries
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If you only want one client, use `--client hermes|claude|opencode|codex`. The installer's behaviour and evidence are recorded in [docs/automatic-install.md](https://github.com/g0GobliN/sutra/blob/main/docs/automatic-install.md).
|
|
210
|
+
|
|
211
|
+
## Supported integrations
|
|
212
|
+
|
|
213
|
+
| Host | Mode | Verified against | What to expect |
|
|
214
|
+
|---|---|---|---|
|
|
215
|
+
| **Hermes Agent** | Automatic — native `tool_execution` middleware | 0.22.5 | Plugin validated and enabled by the installer; restart the gateway; enable the `sutra` toolset for recovery |
|
|
216
|
+
| **Claude Code** | Automatic — `PostToolUse` hook + MCP recovery | 2.1.268 | Result replaced before the model reads it; start a new session; hook and MCP must share a store |
|
|
217
|
+
| **OpenCode** | Automatic — generated `tool.execute.after` plugin + MCP recovery | 1.19.5 | Oversized string results replaced in place; restart OpenCode |
|
|
218
|
+
| **Codex CLI** | **Explicit MCP only** | 0.166.0 | `sutra_compress`/`sutra_restore` are callable; Codex has no supported post-tool result replacement, so nothing is automatic |
|
|
219
|
+
| **Any MCP client** | Explicit | protocol `2024-11-05` | Register `python -m sutra.mcp`; MCP registration is not interception |
|
|
220
|
+
| **Any subprocess-capable agent** | Explicit CLI | Python 3.11–3.13 | `sutra compress` / `sutra restore` as JSON; one process per call |
|
|
221
|
+
| **Cursor, Windsurf/Cascade** | No adapter | — | No generic built-in-tool result hook; MCP registration only, by hand |
|
|
222
|
+
|
|
223
|
+
The authoritative, per-client matrix — mechanisms, install paths, evidence and known limits — is [docs/integrations.md](https://github.com/g0GobliN/sutra/blob/main/docs/integrations.md). The host-API audit is [docs/universal-integration.md](https://github.com/g0GobliN/sutra/blob/main/docs/universal-integration.md).
|
|
224
|
+
|
|
225
|
+
## Configuration
|
|
226
|
+
|
|
227
|
+
Common settings, read on every call:
|
|
228
|
+
|
|
229
|
+
| Variable | Default | Meaning |
|
|
230
|
+
|---|---|---|
|
|
231
|
+
| `SUTRA_ENABLED` | `1` | `0` disables compression and retention |
|
|
232
|
+
| `SUTRA_MAX_BYTES` | `24576` | results at or below this are untouched |
|
|
233
|
+
| `SUTRA_HEAD_BYTES` / `SUTRA_TAIL_BYTES` | `12288` / `6144` | bytes kept from the start and end |
|
|
234
|
+
| `SUTRA_STORE` | `1` | `0` keeps compression but stops retaining originals |
|
|
235
|
+
| `SUTRA_STORE_DIR` | `$HERMES_HOME/cache/sutra-store` | where originals live |
|
|
236
|
+
| `SUTRA_STORE_TTL_HOURS` | `168` | retention window |
|
|
237
|
+
| `SUTRA_RECOVERY_MAX_BYTES` | `8192` | default response cap (64 KiB hard max) |
|
|
238
|
+
|
|
239
|
+
The complete table, including store quotas, stats-log rotation and retrieval bounds, is in [docs/configuration.md](https://github.com/g0GobliN/sutra/blob/main/docs/configuration.md).
|
|
240
|
+
|
|
241
|
+
## Limitations
|
|
242
|
+
|
|
243
|
+
- **Automatic replacement depends on the host.** Codex, Cursor and Windsurf have no supported generic result-replacement hook; they get explicit tools only.
|
|
244
|
+
- **JSON re-encoding normalises formatting.** Indentation and whitespace inside a re-encoded document are not preserved, and duplicate keys collapse to the last value. The original bytes remain recoverable, so nothing is lost, but the visible copy is not byte-identical.
|
|
245
|
+
- **Large JSON arrays with no large string fields are not compressed at all** — the price of keeping their shape.
|
|
246
|
+
- **Retrieval is bounded.** One entry ≤32 MiB, one response ≤8 KiB by default, at most 20 literal matches; a single line longer than the response cap is returned clipped.
|
|
247
|
+
- **The store is not encrypted.** It is local, permission-protected and expiring, but any process running as you can read it.
|
|
248
|
+
- **The recovery tool may need enabling.** In Hermes, `sutra_restore` is gated by the plugin toolset; without it the marker degrades to "re-run narrower".
|
|
249
|
+
- **No live-model A/B has been run.** No task-success, invoice or provider-token claim is made.
|
|
250
|
+
- **Windows is untested.** CI covers Linux and macOS.
|
|
251
|
+
|
|
252
|
+
## Development and contributing
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
python3 -m venv .venv && .venv/bin/pip install pytest ruff
|
|
256
|
+
.venv/bin/python -m pytest tests -q
|
|
257
|
+
.venv/bin/python -m pytest spikes -q
|
|
258
|
+
.venv/bin/ruff check .
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Read [CONTRIBUTING.md](https://github.com/g0GobliN/sutra/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/g0GobliN/sutra/blob/main/CODE_OF_CONDUCT.md) before opening a pull request: one rule per change, a failing test first, and proof that the elided bytes are still recoverable. Bug reports are most useful with the smallest fixture, the result shape, the byte size and the `SUTRA_*` settings in force. Security issues go through a private advisory, not a public issue — see [SECURITY.md](https://github.com/g0GobliN/sutra/blob/main/SECURITY.md).
|
|
262
|
+
|
|
263
|
+
Browse the documentation index at [docs/README.md](https://github.com/g0GobliN/sutra/blob/main/docs/README.md). Releases are prepared and published only by authorized maintainers, following [docs/release.md](https://github.com/g0GobliN/sutra/blob/main/docs/release.md).
|
|
264
|
+
|
|
265
|
+
## Licence
|
|
266
|
+
|
|
267
|
+
MIT.
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://raw.githubusercontent.com/g0GobliN/sutra/main/public/logo/sutraThumb.png" alt="SUTRA" width="520">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# SUTRA
|
|
6
|
+
|
|
7
|
+
**Less output. More signal.**
|
|
8
|
+
|
|
9
|
+
SUTRA is a deterministic tool-output optimization and recovery layer for AI coding agents. It processes eligible tool results after a command runs and before the model reads them, so a large log costs less context on every following turn — without a model paraphrasing it.
|
|
10
|
+
|
|
11
|
+
One core. Multiple agents. Recoverable output. No compression model calls.
|
|
12
|
+
|
|
13
|
+
> **Eight-fixture benchmark:** payload size reduced by **54.3%**, o200k tokenizer counts by **55.2%**; **8/8** planted clues recovered; **0** diffs touched. The fixtures are generated tool-output shapes and the token figure is not a provider bill — [method](#evidence-and-benchmarks).
|
|
14
|
+
|
|
15
|
+
[Why](#the-problem-tool-output-is-re-read-all-session) · [How it works](#how-sutra-handles-a-tool-result) · [Architecture](#architecture) · [Comparison](#how-sutra-compares-with-caveman-and-ponytail) · [Evidence](#evidence-and-benchmarks) · [Install](#install) · [Integrations](#supported-integrations) · [Limitations](#limitations)
|
|
16
|
+
|
|
17
|
+
## The problem: tool output is re-read all session
|
|
18
|
+
|
|
19
|
+
An agent runs `pytest -q`, receives 12,000 lines, and needs one failure. The useful part may be twenty lines, but the tool result stays in context and is re-sent on every subsequent turn. Prompt compression can shave an instruction once; tool output grows with every command an agent runs.
|
|
20
|
+
|
|
21
|
+
```text
|
|
22
|
+
turn 1 ── tool output 60.9 kB ──► model
|
|
23
|
+
turn 2 ── tool output 60.9 kB ──► model (re-sent)
|
|
24
|
+
turn 3 ── tool output 60.9 kB ──► model (re-sent)
|
|
25
|
+
... context grows with the session
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The agent rarely needs the whole result: it needs the failing line, the stack frame, the row that matters — and a route back to everything else.
|
|
29
|
+
|
|
30
|
+
## How SUTRA handles a tool result
|
|
31
|
+
|
|
32
|
+
1. **The tool runs normally.** SUTRA does not wrap, delay or re-execute it.
|
|
33
|
+
2. **The host adapter hands the result to the shared core.** The core decides whether the result is eligible: size, payload shape, evidence tools, diffs.
|
|
34
|
+
3. **The core rewrites only what is safe to remove.** ANSI escapes, repeated lines and oversized middles are elided; diffs stay byte-identical, JSON keeps its shape, a traceback keeps its error end.
|
|
35
|
+
4. **The original is retained locally** when storage is enabled, with a bounded lifetime.
|
|
36
|
+
5. **The model sees a smaller result with a marker** naming what was removed, how much, and the exact `sutra_restore` call that returns it.
|
|
37
|
+
6. **Nothing is generated.** No summariser, no model call, no interpretation, no invented content.
|
|
38
|
+
|
|
39
|
+
If anything is unexpected — a malformed payload, a failed store write, an internal exception — SUTRA fails open and the host receives the original result unchanged.
|
|
40
|
+
|
|
41
|
+
## What makes SUTRA different
|
|
42
|
+
|
|
43
|
+
- **Deterministic, not probabilistic.** The same bytes produce the same rewrite and the same marker. No compression model decides what matters.
|
|
44
|
+
- **Recoverable by construction.** An id is written only after the original is on disk. A marker never cites bytes that were not kept.
|
|
45
|
+
- **Agent-agnostic core.** Hermes, Claude Code, OpenCode, Codex, MCP and the CLI all call the same eligibility, compression, storage and recovery code.
|
|
46
|
+
- **Host-appropriate integration.** Automatic replacement only where the host documents a result-replacing hook; explicit tools or MCP registration where it does not.
|
|
47
|
+
- **Safety boundaries that hold.** Diffs and patches are never rewritten, JSON is never byte-sliced, traceback tails are never dropped.
|
|
48
|
+
- **Fail-open at every adapter.** A broken host payload or a missing interpreter leaves normal agent execution alone.
|
|
49
|
+
|
|
50
|
+
| Capability | What it means in practice |
|
|
51
|
+
|---|---|
|
|
52
|
+
| Deterministic rules, no compression model | Logs are never interpreted or paraphrased by another model |
|
|
53
|
+
| Local original retention | Anything SUTRA omitted can be retrieved later, by id |
|
|
54
|
+
| Native host adapters | No manual compression step on hosts with a result hook |
|
|
55
|
+
| Diff and shape protection | Code changes are never silently rewritten; JSON stays JSON |
|
|
56
|
+
| Fail-open design | A malformed result leaves the agent running normally |
|
|
57
|
+
| Shared core | The same rules, markers and recovery across every integration |
|
|
58
|
+
|
|
59
|
+
## Architecture
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
AI coding agent
|
|
63
|
+
│ runs a tool
|
|
64
|
+
▼
|
|
65
|
+
tool execution
|
|
66
|
+
│ raw result
|
|
67
|
+
▼
|
|
68
|
+
host adapter
|
|
69
|
+
├─ Hermes: tool_execution middleware automatic
|
|
70
|
+
├─ Claude Code: PostToolUse hook automatic
|
|
71
|
+
├─ OpenCode: tool.execute.after plugin automatic
|
|
72
|
+
├─ Codex: MCP registration only explicit calls
|
|
73
|
+
└─ other clients: CLI or MCP server explicit calls
|
|
74
|
+
│
|
|
75
|
+
▼
|
|
76
|
+
shared SUTRA core
|
|
77
|
+
├─ eligibility: size, payload shape, evidence tools, diffs
|
|
78
|
+
├─ deterministic rewrite + a marker naming what was removed
|
|
79
|
+
└─ local retention (TTL, quota, bounded reads)
|
|
80
|
+
│
|
|
81
|
+
▼
|
|
82
|
+
model reads the smaller result
|
|
83
|
+
│ marker quotes: sutra_restore(id="…", mode="…")
|
|
84
|
+
▼
|
|
85
|
+
original retrieved from the local store when needed
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The recovery path is separate from the compression path: compression can run with storage disabled, but then the marker says the original was not retained and the model can only re-run the command narrower. Recovery reads the local store by validated id and bounded mode.
|
|
89
|
+
|
|
90
|
+
## How SUTRA compares with Caveman and Ponytail
|
|
91
|
+
|
|
92
|
+
SUTRA and [Caveman](https://github.com/JuliusBrussee/caveman) approach context efficiency from different architectural directions. Both address unnecessary context consumption, but SUTRA specialises in deterministic, recoverable tool-output processing at the integration layer. [Ponytail](https://github.com/DietrichGebert/ponytail) pulls a third lever: how much code the agent writes at all.
|
|
93
|
+
|
|
94
|
+
| Dimension | SUTRA | Caveman | Ponytail |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| Primary focus | Deterministic tool-output processing | Agent brevity plus the inputs it reads | How much code the agent writes |
|
|
97
|
+
| Where it acts | Between a tool result and the model, through host adapters | Skill plus CLI/proxy around the agent | Skill/rules before code is generated |
|
|
98
|
+
| What it transforms | Logs, JSON documents, tracebacks; diffs untouched | Replies, tool-readable files, web pages; routing and blocks in 4.0 | The agent's plan and implementation choices |
|
|
99
|
+
| Original recovery | Local bounded store, id marker, `sutra_restore` | Docs state originals stay on disk and can be pulled back | Not a compression layer; no recovery surface claimed |
|
|
100
|
+
| Model calls for compression | None — deterministic rules | No separate compression model for the voice; file compressors are tooling | None; the effect depends on the host model following its rules |
|
|
101
|
+
| Prompt handling | Does not touch prompts or replies | Docs state prompts are never rewritten | A prompt/rules layer by design |
|
|
102
|
+
| Agent support | Four first-class adapters plus MCP/CLI; automatic only where a result hook exists | 30+ agents via skill/installer | Many agents via skill/plugin |
|
|
103
|
+
|
|
104
|
+
The closest overlap is Caveman's "read less" path, which also shrinks what the model reads and keeps originals retrievable. SUTRA's difference is scope and guarantee: one deterministic, byte-level transform on the tool-result path, one local recovery protocol, and no automatic claim on a host that lacks a result hook.
|
|
105
|
+
|
|
106
|
+
Caveman's README reports 33.2% fewer input tokens across whole sessions (older engine), 8.5% fewer output tokens in a JetBrains paired test, and one HTML case 9.9% worse; Ponytail reports 45% fewer tokens and 53% less code on its 39-task benchmark. Those are their own measurements on their own workloads. Sources: [Caveman README](https://github.com/JuliusBrussee/caveman), [Caveman product page](https://caveman.so/products/caveman), [Ponytail README](https://github.com/DietrichGebert/ponytail). Details may change.
|
|
107
|
+
|
|
108
|
+
## Evidence and benchmarks
|
|
109
|
+
|
|
110
|
+

|
|
111
|
+
|
|
112
|
+
| Payload | Rule | Bytes before → after | o200k tokens before → after | Saved |
|
|
113
|
+
|---|---|---:|---:|---:|
|
|
114
|
+
| 12,000-line command output | `head-tail` | 60.9 kB → 18.6 kB | 35,000 → 10,149 | 71.0% |
|
|
115
|
+
| JSON tool envelope | `json-fields` | 85.9 kB → 19.2 kB | 26,012 → 5,670 | 78.2% |
|
|
116
|
+
| Test run, 2,000 cases | `head-tail` | 99.8 kB → 18.6 kB | 29,998 → 5,529 | 81.6% |
|
|
117
|
+
| 3,000-frame traceback | `traceback` | 359.4 kB → 10.3 kB | 126,015 → 3,680 | 97.1% |
|
|
118
|
+
| 432 kB patch | `diff-kept` | 432.1 kB → 432.1 kB | 120,039 → 120,039 | 0.0% |
|
|
119
|
+
| 900-row SQL result | `head-tail` | 46.6 kB → 18.5 kB | 18,906 → 7,543 | 60.1% |
|
|
120
|
+
| 8,000-line build log | `head-tail` | 334.9 kB → 18.6 kB | 127,005 → 6,905 | 94.6% |
|
|
121
|
+
| 8,000-item JSON array | `json-kept` | 206.9 kB → 206.9 kB | 103,002 → 103,002 | 0.0% |
|
|
122
|
+
| **Total** | | **1.63 MB → 742.7 kB (54.3%)** | **585,977 → 262,517 (55.2%)** | |
|
|
123
|
+
|
|
124
|
+
The patch row saves nothing on purpose: a compressor that shrinks diffs can hide a code change. The JSON-array row saves nothing because keeping the array an array leaves nothing safe to remove. Five buried clues needed one `sutra_restore` call (about 700 B each; the single-line JSON envelope cost 8.9 kB); three were already visible.
|
|
125
|
+
|
|
126
|
+
What the numbers are — and are not:
|
|
127
|
+
|
|
128
|
+
- Payload bytes and `tiktoken o200k_base` tokenizer counts on the payload text.
|
|
129
|
+
- Not provider input tokens, not prompt-cache effects, not an invoice, and not a live-agent task-success score. No model was called for any number here.
|
|
130
|
+
- 8/8 proves the clue is retained and retrievable; it does not prove an agent will ask for it.
|
|
131
|
+
|
|
132
|
+
Method, fixtures, per-phase timings, memory, recovery costs and reproduction: [docs/benchmark.md](https://github.com/g0GobliN/sutra/blob/main/docs/benchmark.md). The frozen live-model A/B protocol is in [docs/ab-benchmark.md](https://github.com/g0GobliN/sutra/blob/main/docs/ab-benchmark.md); it has not been run.
|
|
133
|
+
|
|
134
|
+
## Safety, recovery and trust
|
|
135
|
+
|
|
136
|
+
Every rewrite leaves a marker in place of the omitted bytes:
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
… [sutra: partial · 133,522 bytes elided (large output) · id=su_3e72c41e… ·
|
|
140
|
+
original 151,920 B retained 168h ·
|
|
141
|
+
retrieve: sutra_restore(id="su_3e72c41e…", mode="bytes", start=12259, end=145781)] …
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
The marker answers four questions: is this complete, what is missing and why, is the original still available, and exactly how to get it. `sutra_restore` supports exact byte ranges, line ranges, literal search and `full` when it fits, with paging that reproduces the original slice byte for byte.
|
|
145
|
+
|
|
146
|
+
Safety properties you can rely on:
|
|
147
|
+
|
|
148
|
+
- **Diffs and patches are byte-identical.** Always.
|
|
149
|
+
- **JSON keeps its shape.** Documents are decoded and re-encoded, never byte-sliced; an array stays an array.
|
|
150
|
+
- **Tracebacks keep their error end.** Only the middle is elided.
|
|
151
|
+
- **An id means the bytes exist.** If storage is off, full or the write failed, the marker says "not retained" and quotes no id.
|
|
152
|
+
- **Fail-open.** Any unexpected shape, parse error or internal exception leaves the original result untouched.
|
|
153
|
+
- **Bounded storage.** Defaults: 32 MiB per entry, 128 MiB total, 2,000 entries, 7-day TTL, 8 KiB recovery response (64 KiB hard cap). The store is local and **not encrypted**; it is protected by filesystem permissions, and tool output can contain secrets. Set `SUTRA_STORE=0` to opt out.
|
|
154
|
+
|
|
155
|
+
Read the full threat model in [SECURITY.md](https://github.com/g0GobliN/sutra/blob/main/SECURITY.md), the guarantees in [docs/contract.md](https://github.com/g0GobliN/sutra/blob/main/docs/contract.md), and the recovery protocol in [docs/recovery.md](https://github.com/g0GobliN/sutra/blob/main/docs/recovery.md).
|
|
156
|
+
|
|
157
|
+
## Install
|
|
158
|
+
|
|
159
|
+
The distribution is `sutra-agent`; the `sutra` name on PyPI belongs to an unrelated package.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
python3 -m venv ~/.sutra-venv
|
|
163
|
+
~/.sutra-venv/bin/pip install sutra-agent
|
|
164
|
+
~/.sutra-venv/bin/sutra --version # sutra 0.3.0
|
|
165
|
+
|
|
166
|
+
~/.sutra-venv/bin/sutra detect # read-only: what is installed
|
|
167
|
+
~/.sutra-venv/bin/sutra install --dry-run
|
|
168
|
+
~/.sutra-venv/bin/sutra install # configure every detected client
|
|
169
|
+
~/.sutra-venv/bin/sutra doctor # prove the installed paths
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
If the index you use does not serve 0.3.0 yet, install the checkout instead:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
git clone https://github.com/g0GobliN/sutra
|
|
176
|
+
~/.sutra-venv/bin/pip install ./sutra
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
`sutra install` auto-detects Hermes, Claude Code, OpenCode and Codex. Each change is backed up first and can be removed with `sutra uninstall`; `--dry-run` prints the change and writes nothing. Restart the host after installing a plugin or hook.
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
~/.sutra-venv/bin/sutra uninstall # remove only SUTRA-owned entries
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
If you only want one client, use `--client hermes|claude|opencode|codex`. The installer's behaviour and evidence are recorded in [docs/automatic-install.md](https://github.com/g0GobliN/sutra/blob/main/docs/automatic-install.md).
|
|
186
|
+
|
|
187
|
+
## Supported integrations
|
|
188
|
+
|
|
189
|
+
| Host | Mode | Verified against | What to expect |
|
|
190
|
+
|---|---|---|---|
|
|
191
|
+
| **Hermes Agent** | Automatic — native `tool_execution` middleware | 0.22.5 | Plugin validated and enabled by the installer; restart the gateway; enable the `sutra` toolset for recovery |
|
|
192
|
+
| **Claude Code** | Automatic — `PostToolUse` hook + MCP recovery | 2.1.268 | Result replaced before the model reads it; start a new session; hook and MCP must share a store |
|
|
193
|
+
| **OpenCode** | Automatic — generated `tool.execute.after` plugin + MCP recovery | 1.19.5 | Oversized string results replaced in place; restart OpenCode |
|
|
194
|
+
| **Codex CLI** | **Explicit MCP only** | 0.166.0 | `sutra_compress`/`sutra_restore` are callable; Codex has no supported post-tool result replacement, so nothing is automatic |
|
|
195
|
+
| **Any MCP client** | Explicit | protocol `2024-11-05` | Register `python -m sutra.mcp`; MCP registration is not interception |
|
|
196
|
+
| **Any subprocess-capable agent** | Explicit CLI | Python 3.11–3.13 | `sutra compress` / `sutra restore` as JSON; one process per call |
|
|
197
|
+
| **Cursor, Windsurf/Cascade** | No adapter | — | No generic built-in-tool result hook; MCP registration only, by hand |
|
|
198
|
+
|
|
199
|
+
The authoritative, per-client matrix — mechanisms, install paths, evidence and known limits — is [docs/integrations.md](https://github.com/g0GobliN/sutra/blob/main/docs/integrations.md). The host-API audit is [docs/universal-integration.md](https://github.com/g0GobliN/sutra/blob/main/docs/universal-integration.md).
|
|
200
|
+
|
|
201
|
+
## Configuration
|
|
202
|
+
|
|
203
|
+
Common settings, read on every call:
|
|
204
|
+
|
|
205
|
+
| Variable | Default | Meaning |
|
|
206
|
+
|---|---|---|
|
|
207
|
+
| `SUTRA_ENABLED` | `1` | `0` disables compression and retention |
|
|
208
|
+
| `SUTRA_MAX_BYTES` | `24576` | results at or below this are untouched |
|
|
209
|
+
| `SUTRA_HEAD_BYTES` / `SUTRA_TAIL_BYTES` | `12288` / `6144` | bytes kept from the start and end |
|
|
210
|
+
| `SUTRA_STORE` | `1` | `0` keeps compression but stops retaining originals |
|
|
211
|
+
| `SUTRA_STORE_DIR` | `$HERMES_HOME/cache/sutra-store` | where originals live |
|
|
212
|
+
| `SUTRA_STORE_TTL_HOURS` | `168` | retention window |
|
|
213
|
+
| `SUTRA_RECOVERY_MAX_BYTES` | `8192` | default response cap (64 KiB hard max) |
|
|
214
|
+
|
|
215
|
+
The complete table, including store quotas, stats-log rotation and retrieval bounds, is in [docs/configuration.md](https://github.com/g0GobliN/sutra/blob/main/docs/configuration.md).
|
|
216
|
+
|
|
217
|
+
## Limitations
|
|
218
|
+
|
|
219
|
+
- **Automatic replacement depends on the host.** Codex, Cursor and Windsurf have no supported generic result-replacement hook; they get explicit tools only.
|
|
220
|
+
- **JSON re-encoding normalises formatting.** Indentation and whitespace inside a re-encoded document are not preserved, and duplicate keys collapse to the last value. The original bytes remain recoverable, so nothing is lost, but the visible copy is not byte-identical.
|
|
221
|
+
- **Large JSON arrays with no large string fields are not compressed at all** — the price of keeping their shape.
|
|
222
|
+
- **Retrieval is bounded.** One entry ≤32 MiB, one response ≤8 KiB by default, at most 20 literal matches; a single line longer than the response cap is returned clipped.
|
|
223
|
+
- **The store is not encrypted.** It is local, permission-protected and expiring, but any process running as you can read it.
|
|
224
|
+
- **The recovery tool may need enabling.** In Hermes, `sutra_restore` is gated by the plugin toolset; without it the marker degrades to "re-run narrower".
|
|
225
|
+
- **No live-model A/B has been run.** No task-success, invoice or provider-token claim is made.
|
|
226
|
+
- **Windows is untested.** CI covers Linux and macOS.
|
|
227
|
+
|
|
228
|
+
## Development and contributing
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
python3 -m venv .venv && .venv/bin/pip install pytest ruff
|
|
232
|
+
.venv/bin/python -m pytest tests -q
|
|
233
|
+
.venv/bin/python -m pytest spikes -q
|
|
234
|
+
.venv/bin/ruff check .
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
Read [CONTRIBUTING.md](https://github.com/g0GobliN/sutra/blob/main/CONTRIBUTING.md) and [CODE_OF_CONDUCT.md](https://github.com/g0GobliN/sutra/blob/main/CODE_OF_CONDUCT.md) before opening a pull request: one rule per change, a failing test first, and proof that the elided bytes are still recoverable. Bug reports are most useful with the smallest fixture, the result shape, the byte size and the `SUTRA_*` settings in force. Security issues go through a private advisory, not a public issue — see [SECURITY.md](https://github.com/g0GobliN/sutra/blob/main/SECURITY.md).
|
|
238
|
+
|
|
239
|
+
Browse the documentation index at [docs/README.md](https://github.com/g0GobliN/sutra/blob/main/docs/README.md). Releases are prepared and published only by authorized maintainers, following [docs/release.md](https://github.com/g0GobliN/sutra/blob/main/docs/release.md).
|
|
240
|
+
|
|
241
|
+
## Licence
|
|
242
|
+
|
|
243
|
+
MIT.
|