bareloop 0.9.0 → 0.10.0

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.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,210 @@ All notable changes to bareloop are documented here. Format:
5
5
  [SemVer](https://semver.org/spec/v2.0.0.html). Pre-1.0: **minor** = a ladder rung or
6
6
  feature lands, **patch** = docs, fixes, scaffolding.
7
7
 
8
+ ## [0.10.0] — 2026-08-13
9
+
10
+ ### Added
11
+
12
+ - **The close-AUTHORING pipeline gets a money ceiling** (`--budget`, `ceilingUsd`) — the lever
13
+ parked at v0.9.0 as arbiter territory, approved by hamr. Until now the flow **metered** spend
14
+ and nothing **bounded** it: the runner printed a total and no number anywhere could stop a
15
+ call. It has **NO DEFAULT** — omitting it runs UNBOUNDED and the runner **prints that** before
16
+ the provider is built, because a defaulted cap is a silent second ceiling (the `maxWallMs`
17
+ precedent) and an unbounded run must be a visible operator choice. A malformed value is an
18
+ error, never a silent fall back to unbounded. The ceiling **binds BETWEEN metered calls** —
19
+ the survey's attempts and its F59 recovery round, and the declaration loop's author call,
20
+ each revise, and each malformed-emission retry — because a cap that binds mid-call kills the
21
+ row before it can be graded (F45). ONE number reaches BOTH paid seams, and spend already
22
+ incurred folds in, so re-entering cannot silently widen it. **F6 keeps its own axis**: a
23
+ null/unknown cost never counts as $0, so spend that cannot be *known* stops as `pricing-red`
24
+ rather than passing silently — while known spend at or over the cap is `cap-halt` even when
25
+ the total is unknown, since that breach is certain on the priced half alone. The stop is a
26
+ governance stop, not an error: it names the cap and the spend, nothing retries, partial
27
+ artifacts stay on disk, and it is DISTINCT from `artifact-red` and `provider-red`. A survey
28
+ the ceiling stopped is named a money stop (`budgetStop`, typed cause `not-funded`, outside
29
+ `SCOUT_RETRY_CAUSES`) instead of blaming a model that never spoke. One predicate, one
30
+ spelling (`capStop`/`tallyCalls` in `src/text.js`, beside `priceOf` and for the same reason).
31
+
32
+ - **A resume may DERIVE `wall-halt` from a recorded `step-red`.** Only when that run's OWN
33
+ spine shows the wall crossed BEFORE the terminal was minted — a derivation from the primary
34
+ record, which never rewrites the recorded outcome and announces itself with a banner. The
35
+ terminal's NAME is what gates resume (`readResume`'s `resumableOutcomes`, which the operator
36
+ runner supplies as `cap-halt` / `wall-halt`), so a run mislabelled `step-red` past its own
37
+ wall silently lost its resumability. **It is a PERMANENT read-side safety net, not a
38
+ migration shim** (ruled 2026-08-13; the expiry question that was parked here is closed). The
39
+ defect that minted the shape is fixed at source, but spines are append-only forever, so the
40
+ population it protects can never shrink; it fires only on the run's own un-forgeable
41
+ `wall-bounded` record, cannot rescue a `step-red` that has no wall record in front of it, and
42
+ is a never-taken branch on a healthy spine.
43
+
44
+ ### Changed
45
+
46
+ - **The two revise-loop tighten-only clamps get a detector.** `maxRevisions` and
47
+ `structureRetries` have been clamped since `40672ae`, but nothing could *fail* if they
48
+ stopped clamping: MEASURED, three mutations survived the whole suite — including deleting
49
+ the `structureRetries` clamp outright, a straight revert of the fix that added it. The two
50
+ existing tests pinned only the ceiling and the floor, and neither can fail when the clamp
51
+ stops honouring values *between* them; the direction the rule exists to permit — the
52
+ operator **lowering** a bound — was the untested one. Seven tests now cover the middle of
53
+ both ranges, the non-numeric floor, and `Infinity` (a widening, which clamps to the ceiling,
54
+ matching `runAuthorScout`'s own reading). The three floors are pinned as *deliberately
55
+ different* (`SCOUT_ATTEMPTS` at 1, both revise axes at 0) so a later "harmonisation" has to
56
+ argue with a test. No production behaviour changed — this is the detector the rule was
57
+ missing (F45's class: a frozen rule without a wired detector is prose, not protection).
58
+
59
+ - **A stop past the wall never funds a replan draft, on ANY trigger.** W-2's *"no new step
60
+ starts"* now covers the drafting call itself (hamr: *"it's a replan that is doomed to
61
+ die"*), and the guard is trigger-agnostic rather than wired to one path. A declined grant is
62
+ not consumed. With time left on the clock every one of these paths is byte-identical to
63
+ before — pinned as a control.
64
+ - **The drafter is told its worker has no shell.** A replan wrote an action opening *"Run
65
+ `npx tsc --strict --noEmit`…"*; `run` is locked out of `TOOL_MENU` permanently, so the
66
+ worker obeyed as far as its verbs allowed — 25 reads and greps, zero edits, a whole step
67
+ spent hunting six errors by hand, on a plan that validated clean. The no-shell law now sits
68
+ in the DRAFTER prompt unconditionally, beside the exit-freedom law, with `read`/`grep`
69
+ glossed as the worker's only eyes; the scout and worker prompts already carried it, and the
70
+ one component that WRITES instructions did not. **A regex over action prose was explicitly
71
+ refused** (F86's anti-precedent): the same sentence is legitimate in an operator's signed
72
+ goal, so the instrument is a prompt register, never a matcher. F95.
73
+ - **The worker persona REGISTERS the arbiter's books instead of leaving them to be
74
+ discovered.** `PERSONA_TOOLS` now names `gate-audit.jsonl`, `.smoke`, `.litectx` and the
75
+ run's spine as always-denied — records of how the worker is judged, holding nothing about
76
+ its task — beside the absolute-path law it is the twin of, so it renders for every worker on
77
+ every grant (a `write`-only grant gets no component strategy paragraph at all and must still
78
+ be told). **The fence is unchanged**: nothing widened, no book became readable. The only way
79
+ to learn the rule was previously to spend rounds of a bounded attempt on it. F98.
80
+ - **Both signing surfaces show the GOAL and the judged stages as ONE reading.** F87's law is
81
+ that the goal must state everything the close judges while NOTHING derives one from the
82
+ other or checks them against each other — so the sole defence is the signer reading both
83
+ halves at once, and neither surface offered it: `run-author` printed the declaration and
84
+ never the goal, `run-u --approve` printed the goal and never the declaration. `run-u`'s gate
85
+ now names every close stage (name + kind) under the goal, **for BOTH spec forms** — the
86
+ pairing was first gated on `closeDecl`, so 10 of the 11 shipped specs (the command `close[]`
87
+ form) still met the signer with a goal and none of the stages that judge it, the exact
88
+ half-reading this entry claimed to end; `closeStagesOf(spec)` now renders either form, and a
89
+ command stage prints `[command]` rather than the catalogue kind name `command-exit` it does
90
+ not carry (spec hashes and exit codes byte-identical, proven live). `run-author`'s block moves to
91
+ **`scripts/author-readout.mjs`** (`declarationLines(spec)`) and gains the goal above it,
92
+ rendered from the RESOLVED spec — the bytes that get hashed. It moved because the block was
93
+ otherwise reachable only after a paid scout and a paid model call, and a readout no test can
94
+ reach is a readout nothing checks. An absent goal renders as ABSENT, never as a bare label.
95
+ Still a READING and not a validator — comparing the two is the move F87 forbids.
96
+ - **README rewritten value-first** (hamr's framing, straight to `main`). The pitch now leads
97
+ with the trust-but-verify lineage (the ralph loop, code machine MCP, and RLMs converged on
98
+ the same principle), the three kinds of done (green / softgreen / hitl, one everyday
99
+ example each), why the agent authors the workflow (forty-plus primitives — counted 51+
100
+ across the suite's real surfaces — and no one recipe picked), and "build it once, keep it"
101
+ (localhost UI, whole-workflow export with its self-healing harness). One `[WIP]` badge is
102
+ the only status marker; all mechanics, layer tables, findings numbers and rung history
103
+ moved out of the pitch — `bareloop.context.md` stays the contract, the README the pitch.
104
+ - **`step-stalled` joins the RESUMABLE halts** (hamr's go, 2026-08-13). A stall that trips with
105
+ time left and only reaches the replan gate after the wall has expired kept its NAME — `run.js`
106
+ keys the F44 spend floor on that exact outcome, and renaming it would report unknown spend as
107
+ an exact total — but the name is also what `readResume` gates on, so keeping it cost the run
108
+ its checkpoint. A `step-stalled` spine now previews as **RESUME**, folds the spend floor in as
109
+ `>=$x`, and re-enters at the recorded branch and step. A pure widening of the resumable set:
110
+ nothing else about the terminal moved, and `reuse.js`'s D4a path was checked unaffected.
111
+ - **The arbiter-book names get ONE home.** `gate-audit.jsonl`, `.smoke` and `.litectx` were
112
+ spelled independently in `isArbiterBook`, in BOTH fence deny lists, in the `PERSONA_TOOLS`
113
+ prose and in `run.js`'s smoke root — five sites, the exact drift class F98 had just paid for,
114
+ with the prose copy unguardable by any test. `kinds.js` now exports
115
+ `SMOKE_STORE`/`LITECTX_STORE`/`GATE_AUDIT_FILE`/`ARBITER_BOOK_STORES` and all five consume it.
116
+ Purely mechanical and verified as such: the deny-list joins and the persona prose are
117
+ **byte-identical** to the strings they replace, so no fence decision and no worker prompt
118
+ changed, and there is no import cycle (`kinds.js` sits below `tools.js`/`run.js`).
119
+ `tools.test.js`'s literal-spelling guard now asserts the fence consumes the constant — the
120
+ drift it guarded is impossible by construction.
121
+
122
+ ### Fixed
123
+
124
+ - **A time-stop is NAMED a time-stop — W-2 closes over the sibling terminals.** The ruling
125
+ (*"when time is up, keep the grade we already have and stop"*) was implemented on the
126
+ cap-halt path and not on the variance path: one run minted `step-red` **9.9 seconds past its
127
+ own wall**, having recorded the crossing in its own spine 5.6 seconds earlier. Now **every
128
+ variance and cap-halt terminal re-reads the clock before minting**, through ONE shared
129
+ `wallHaltTerminal` emission site — one site, one spelling —
130
+ and the ladder's cap-halt past the wall is a `wall-halt`. **`step-stalled` is pinned OUT of
131
+ the class by test:** `run.js` keys `spendComplete:false` on that exact outcome name because
132
+ an abandoned-and-reissued call may already be billed, and relabelling it would report a
133
+ floor as an exact total (F6 in a self-heal coat). **With both allowances exhausted the MONEY
134
+ cut is reported** (`cap-halt` wins over `wall-halt`) — hamr: *"understood"*; recorded so the
135
+ choice stays visible. F96 / PRD v1.59.
136
+ - **A declared `count-not-worse` red gap carries the LINES it counted, not just how many.**
137
+ `"8 match(es)"` with no file, no line and no error code is a number with nowhere to open —
138
+ F28's rule (*the close's output format is part of the contract*) recurring one rung later
139
+ inside the authored-close executor, with the `gapKeep` machinery it needed sitting in the
140
+ same file. `parseValue` now returns `matched`: the **KEPT** lines only — those that survived
141
+ the scope filter and reached aggregation, so a scope-DROPPED line is never named and the
142
+ worker is never aimed outside its own population (F84). The harvest is **per-term**, not
143
+ global: each term's kept lines nest under that term's own breakdown row — the one place its
144
+ `+n`/`-n` already prints — a `first` aggregate echoes only the one line it read, and dedup is
145
+ WITHIN a term, so a line feeding two terms plays both roles and appears under each. Harvested
146
+ globally, a negative-sign term's lines and a `first` term's never-read lines were echoed flat
147
+ as *the lines the count is made of*, handing the worker a line to go fix when that term
148
+ SUBTRACTED; labelling per term rather than dropping negatives keeps the subtracted term
149
+ visible, because under higher-is-better that is where the news is. The value is
150
+ still computed from the parsed values and never from the list. The lines ride the EXISTING
151
+ channel and invent none: the stage's `gapKeep` prefix on every line (Layer R's `redKeep` is
152
+ DERIVED from it), the existing `GAP_LINE_CAP`, and the announced trim on overflow.
153
+ **Nothing here can flip a signed spec hash** — verdict logic, baselines, counting,
154
+ `closeDecl` schema and `detail` untouched. Measured, not asserted: the identical job, same
155
+ patient, same hash, went from stalling at 8 and dying to **67 → 8 → 1 → 0** in three
156
+ iterations. F98.
157
+ - **A fence deny streak ends the ATTEMPT, never the RUN — `gate-red` is extinct as a mintable
158
+ terminal.** A converging run (close reading 46 → 10 → 8, no strikes) probed three of the
159
+ arbiter's own books, the fence denied all three CORRECTLY, bare-agent's BA-11 deny-spin
160
+ guard ended the loop, and the plan flow mapped that to a terminal `gate-red` — escalate,
161
+ never retry. The run died with **$1.77 and 21.6 wall-minutes unspent, on a fence that had
162
+ worked perfectly.** BA-11's stop now joins `max_turns` in the **bounded-attempt lane on BOTH
163
+ worker surfaces**: `attempt-bounded` carries the `reason`, the close judges the partial
164
+ work, the gap feeds forward, caps unchanged, the loop continues. **And the next attempt is
165
+ told which bound actually fired.** All three attempt bounds wrote the same bare iteration
166
+ number, so the following prompt rendered *"CUT OFF after N tool rounds"* for a denial streak —
167
+ false on cause and count, aiming the worker at its read budget instead of at the fence, while
168
+ `r.error` reached only the spine. The bound now carries `{iteration, cause, reason}`, and the
169
+ denial branch quotes the recorded `denied:<tool>` terminal verbatim — bare-agent returns the
170
+ tool name only, so no path and no streak count is invented — trimmed under `GAP_TRIM_MARKER`
171
+ and scrubbed once at capture, one scrub shared by prompt and spine (an append-only spine that
172
+ captures a key captures it forever). The round-bound sentence stays **byte-identical**, pinned
173
+ by block-equality after an `includes` guard survived a sabotage prefix. This is F32's routing rule
174
+ applied to a new stop cause, not a new one — a stop arriving AFTER gate-audited worker
175
+ writes is non-terminal by construction, and a denial is its most benign member. **Nothing is
176
+ widened**: the same actions are denied and the same audit rows written; a genuine scope
177
+ escape now costs one bounded attempt instead of the whole run. The category stays in
178
+ `EXCLUDED_ESCALATIONS` and in `ralph`'s passthrough decision table — that set is EXECUTABLE,
179
+ so dropping the name would re-file any future emission as a counted capability gap rather
180
+ than delete it. F98.
181
+ - **A malformed money ceiling is an ERROR at the library seam, never a silent UNBOUNDED.**
182
+ `capStop` read `'2.50'`, `NaN`, `Infinity`, `true` and `{}` as *no ceiling* while
183
+ `makeCostBook` advertised the same value straight back — the advertised and the enforced
184
+ budget were different numbers, the one thing a budget may never be — and the only guard
185
+ (`parseCeiling`) was CLI-side, so every library caller ran unprotected. A non-finite non-null
186
+ now throws **before the first paid call**: it costs $0 and propagates uncaught, so no catch
187
+ can launder it into an ABSENT survey. `null`/`undefined` stay the stated operator choice for
188
+ unbounded; `0` and negatives stay finite and cap-halt immediately, pinned as they were.
189
+ - **`budgetStop` latches only when the ceiling actually ended the ladder.** The recovery-seam
190
+ latch fired for EVERY final cause: a 1-turn transport death and even a healthy PRESENT survey
191
+ that spent past the ceiling both came back `budgetStop:'cap-halt'`, on a field whose own
192
+ docstring says *"the ceiling, when it is what ended the ladder"* (the second instance was not
193
+ in the finding). The recovery predicate is settled first now, and `capStop` consulted only
194
+ when a recovery call was actually PENDING. The genuine cap-plus-transport-death case keeps its
195
+ `cap-halt`, but the refusal detail **concedes the concurrent cause instead of contradicting
196
+ the `ENETUNREACH` it quotes** — and concedes it for every INCOMPLETE cause, not only transport
197
+ death: a SHORT/EMPTY/UNPARSEABLE survey whose repair round the ceiling refused was still
198
+ emitting *"the survey stopped on the authoring ceiling, not on anything it read"* directly
199
+ above the reply it was quoting. `CALL_FAILED` keeps the transport wording; `NOT_FUNDED` — no
200
+ call ever made — keeps the ceiling-only wording, the one case where it is true. No budget
201
+ semantics moved: the PRD already said only the former is why the loop ended, and the code now
202
+ honours its own sentence.
203
+ - **The authoring spine event rides its own stop.** `scripts/run-author.mjs` hardcoded
204
+ `type:'cap-halt'` on the governance readout even when the stop was `pricing-red` — the only
205
+ site in the repo where a spine event's type contradicted its own category, and a `pricing-red`
206
+ event carrying *"not under cap"* sends the operator off to raise a number when the repair is a
207
+ priced provider. The old spelling could also arm `ledger.js`'s capability-gap fuse on a run
208
+ whose wallet was never empty (latent — no script feeds author spines to `updateLedger` today,
209
+ but type-keyed slicing is exactly how F45's misread happened). The emit now spends
210
+ `authored.stop` for both fields, so meaning derives from the stop once.
211
+
8
212
  ## [0.9.0] — 2026-08-09
9
213
 
10
214
  The **close-authoring rung**. The close stops being a hand-written script and becomes a
package/README.md CHANGED
@@ -13,144 +13,126 @@
13
13
  <p align="center">
14
14
  <img src="https://img.shields.io/github/package-json/v/hamr0/bareloop?label=version&color=2a4f8c" alt="version (auto from package.json)">
15
15
  <img src="https://img.shields.io/badge/license-Apache%202.0-2a4f8c" alt="license: Apache 2.0">
16
- <img src="https://img.shields.io/badge/status-Layer%202%20%C2%B7%20accepted-2a6d3a" alt="status: Layer 2, accepted">
16
+ <img src="https://img.shields.io/badge/status-WIP-orange" alt="status: WIP">
17
17
  </p>
18
18
 
19
- **"Automate this job — I don't know the best workflow."** For tasks that are **repeated,
20
- long, and verifiable**: an agent authors the workflow scaffolding (a constrained,
21
- validated config — never freeform code); runs execute under an un-gameable outer gate;
22
- and the scaffolding *improves across runs* through verdict-gated, run-as-executed
23
- inheritance with ledger-counted attribution.
24
-
25
- The pitch in one line: **workflows that earn their own design, with receipts** — every
26
- inherited rule carries the green that minted it and the contrast that attributed it.
27
-
28
- **What you keep is the workflow, not the session.** An agent figures your recurring,
29
- verifiable job out once; what survives is a verified, self-healing workflow you can run
30
- again — with bounded spend under an envelope *you* sign, deterministic verification you
31
- don't author, and cost and time reported honestly (an unknown is reported unknown, never
32
- rounded to zero). *Direction, not yet shipped:* a local workbench where you experiment with
33
- a job, graduate a workflow once it greens, and **export** it — signed spec, workflow, close
34
- scripts and a thin runner that depends on bareloop, so the whole self-healing library
35
- (bare-agent · bareguard · litectx) comes along as npm dependencies. That bundle runs
36
- headless as an enclosed CLI and asks you the same signing questions at the prompt that the
37
- workbench would. It is a dependency, never generated standalone code: the gate travels with
38
- it and never disappears.
39
-
40
- > **Status: Layer 2 — accepted.** The agent now authors its own workflow: `runJob()`
41
- > takes a signed job spec, surveys the repo, **drafts a validated plan of bounded steps**
42
- > (each with an operator-signed self-check it may reference but never author), and runs it
43
- > under an un-gameable outer close and one budget it can only tighten. On the real-model
44
- > acceptance battery (F47) the emergent flow converted a job the same worker failed 4/4
45
- > before — 3/3 runs, clearing the owned bar every time, composing its own check exits. The
46
- > within-run ratchet (Layer R) ships armed-and-inert by measurement (F41). **Then N3 —
47
- > executed inheritance**, where a workflow that greened is kept, offered to the next
48
- > similar job, and improved as executed instead of drafted from scratch (the ladder's
49
- > kill-switch question). As of 0.7.0 N3's machinery **ships** — the bridge registry, the
50
- > operator-signed reuse envelope, the selection call and step-level resume are all in the
51
- > public API — but shipping is not acceptance: one execution green proves reuse safe and
52
- > legal, never *beneficial*. The contrast that was to prove the lift is now retired (F88): a
53
- > validation rule hands every cold run the plan shape a bridge was carrying, so the gap it
54
- > would have measured is gone. Treat reuse as available and unproven — what a bridge should
55
- > carry instead is open. **The rung in flight is close authoring** — the last layer where a
56
- > human still wrote code. You answer a short interview about what *done* means; an LLM then
57
- > composes a close **declaration** over a catalogue of stage kinds bareloop implements — never
58
- > code, never prose parsed back — which is validated, run once against your untouched repo so
59
- > every ruler is seen measuring something real, and gated before you sign its hash. It is
60
- > proven live on both a JavaScript and a Python patient, and its designed failure mode is an
61
- > honest refusal: a close that would grade nothing, or a stage whose population does not exist
62
- > in your tree, comes back decision-ready instead of green.
63
-
64
- ## Quick start
19
+ **"Automate this job — I don't know the best workflow."**
65
20
 
66
- ```bash
67
- npm install bareloop
68
- ```
21
+ For work that is repeated, long, and verifiable: an agent authors the workflow scaffolding
22
+ itself, as a constrained and validated config rather than freeform code. Every run executes
23
+ under an outer gate the agent cannot reach or argue with. And the workflow gets better across
24
+ runs, because what actually worked is kept with receipts and carried into the next run.
69
25
 
70
- **Give your AI assistant the integration guide**
26
+ Agents got good at doing the work. The open problem is knowing when the work is actually
27
+ done. Three of the strongest results in long-running agent work landed on the same answer
28
+ independently: the ralph loop, code machine MCP, and recursive language models all trust the
29
+ agent to do the work and verify it with something the agent cannot reach. Trust, but verify.
71
30
 
72
- ```
73
- Read bareloop.context.md from node_modules/bareloop/bareloop.context.md
74
- ```
31
+ bareloop takes that principle and makes it the product. You describe a repeated, verifiable
32
+ job and what *done* means for it. The agent handles the rest, under verification it never
33
+ gets to touch.
34
+
35
+ ## Three kinds of done
36
+
37
+ Jobs differ by who or what decides the result is good. That difference is the product's
38
+ spine, so you choose it when you create the job.
75
39
 
76
- That single file is the complete adopter contract — the boundary, the architecture, the
77
- refusals, the constraints — and it grows API sections as rungs land. (Suite-wide pattern:
78
- every bare package ships its `*.context.md`.)
40
+ **green** — a predicate decides. Tests pass, the build exits clean, the type checker is
41
+ quiet.
42
+ > *"Fix the failing suite."* · *"Migrate this package to strict types."*
79
43
 
80
- ---
44
+ **softgreen** — an assessment decides against a rubric.
45
+ > *"Reserve a ticket from SF to LA under $400."*
81
46
 
82
- ## How it works
47
+ **hitl** — a human makes the final call.
48
+ > *"Improve my resume."*
83
49
 
84
- Three layers; nothing inside negotiates with the layer above it.
50
+ ## Why the agent authors the workflow
85
51
 
86
- | Layer | What it is | Emergent? |
87
- |---|---|---|
88
- | **Outer shell** | Per-run budget cap (bareguard), retry cap, verdict collection, escalation routing. Stateless across runs | never — permanent, dumb, un-gameable |
89
- | **Emergent middle** | The authored plan: bounded steps, each with its granted verbs, its own round cap, its write scope and its form-checkable exits — schema-validated, red before tokens burn. A step keeps iterating while it is making progress; when it stops, the shell ends it and the planner re-allocates | yes — authored and improved by the agent |
90
- | **Floor** | Append-only JSONL spine (single source for every UI), litectx store per job, per-run ledger | never — the record |
52
+ The bare suite gave us forty-plus primitives, and there are at least as many opinions about
53
+ how context engineering should be broken into steps. Instead of picking one opinion and
54
+ shipping it as the recipe, bareloop makes the agent the author. It chooses its own path
55
+ through the primitives and then has to survive verification it cannot edit, widen, or
56
+ disable.
91
57
 
92
- Every job declares a **verdict class**, and the class decides what the run's learning is
93
- worth. Today exactly one is built:
58
+ The lessons from ralph, RLMs, and code machine MCP are in here, applied to the small parts
59
+ rather than adopted whole. None of them is the workflow; each one is available to the agent
60
+ building it.
94
61
 
95
- | Verdict | Truth source | Mints inheritance? | Status |
96
- |---|---|---|---|
97
- | **Hard green** | predicate / exit-code (tests, build, lint) | automatically | **built** |
98
- | **Soft green** | rubric / assessment | only with HITL confirm or N consistent repeats | declared, not built (rung N4) |
99
- | **HITL green** | a human is the close (PR merge, "publish") | yes — and merge stays human, forever | declared, not built (rung N4) |
62
+ ## Install
100
63
 
101
- The full bare-suite surface is *disclosed* to the authoring agent; only *admitted* verbs
102
- are callable per job. A request against a locked primitive is a structured red — real
103
- diagnostic signal, and the admission path when it's justified.
64
+ ```bash
65
+ npm install bareloop
66
+ ```
104
67
 
105
- ## Security posture — honest about the boundary
68
+ ## Usage
69
+
70
+ A signed job spec goes in. A verdict comes out.
71
+
72
+ ```js
73
+ import { runJob, jobSpecHash, makeSpine } from 'bareloop';
74
+ import { AnthropicProvider } from 'bare-agent';
75
+
76
+ const spec = {
77
+ schema: 'job-v1',
78
+ job: 'my-maintainer',
79
+ description: 'fix src until the suite greens',
80
+ goal: 'Fix any failure in src/ so the suite passes.',
81
+ verdictType: 'green',
82
+ close: [{ name: 'suite-green', cmd: 'npm test', expect: 0 }],
83
+ provider: 'anthropic-api',
84
+ cadence: { unit: 'day', every: 1 },
85
+ budgetUsd: 1.5,
86
+ writeScope: ['src/**'],
87
+ tools: ['read', 'grep', 'write', 'edit'],
88
+ escalation: { mode: 'decision-ready' },
89
+ };
90
+
91
+ // you sign the spec; an edited spec is unsigned by construction
92
+ const approvals = [
93
+ { specHash: jobSpecHash(spec), signer: 'you', ts: new Date().toISOString() },
94
+ ];
95
+
96
+ const outcome = await runJob(spec, {
97
+ approvals,
98
+ workdir: '/path/to/checkout',
99
+ provider: new AnthropicProvider({ model: 'claude-sonnet-5' }), // key from env
100
+ emit: makeSpine('/path/to/checkout/run.jsonl'),
101
+ });
102
+ // 'green' means your close passed. Anything else is a named, decision-ready stop.
103
+ ```
106
104
 
107
- bareloop runs **locally**, as you. Secrets load from the environment and never enter the
108
- tree, the spine, the configs or the ledger — and the close child, which executes the code
109
- the worker just wrote, gets its environment **stripped of credential-shaped variables**
110
- (provider keys, `AWS_*`, anything named `*_TOKEN`/`*_SECRET`/`*_PASSWORD`/`*_API_KEY`):
111
- nothing that judges a tree needs them. That is exposure reduction, **not a sandbox** — the
112
- worker's code still runs with your OS permissions and network access, so treat a bareloop
113
- run as inside your trust boundary and give it a repo you'd let an agent touch.
105
+ You do not have to hand-write that `close` yourself. bareloop can author it with you from a
106
+ short interview about what done means for the job, then hand you the result to sign.
114
107
 
115
- ## The science behind it
108
+ **Integrating an agent?** Point it at the contract, not this file:
116
109
 
117
- bareloop is the productization of **[adaptlearn](https://github.com/hamr0/adaptlearn)**
118
- (archived at v0.11.1) — a closed experimental record, findings F1–F23. What it settled,
119
- bareloop consumes without re-proving:
110
+ ```
111
+ Read bareloop.context.md from node_modules/bareloop/bareloop.context.md
112
+ ```
120
113
 
121
- | Mechanism | Evidence |
122
- |---|---|
123
- | Agents author valid harness configs at hand-written parity | M4 (F10) |
124
- | Mid-run revision recovers stuck runs | M5 (F11: 3/3 vs 1/3) |
125
- | Verdict-gated inheritance beats ungated on pass/fail | F19: gated late 1.00 vs ungated 0.13 |
126
- | Run-as-executed inheritance transmits in-run learning | F20: 6/6 lineages, ~½ cost |
127
- | Which-knob attribution is countable from the ledger | V2: contrast bit 16/16 gens |
128
- | Where memory pays: regularities outside the worker's prior | F17/F18: ~8× under acquisition cost |
114
+ That single file is the complete adopter contract: the API, the boundary, the refusals, the
115
+ constraints. The README is the pitch. (Suite-wide pattern: every bare package ships its
116
+ `*.context.md`.)
129
117
 
130
- Full PRD with design laws and open questions: [`docs/01-product/PRD.md`](docs/01-product/PRD.md).
118
+ ## Build it once, keep it
131
119
 
132
- ## Roadmap — the build ladder
120
+ A simple localhost UI lets you build a job by talking about it and watch it run. When it
121
+ works, **export the whole workflow** — with its self-healing harness — and run it again
122
+ anywhere. The point is to stop trial-and-erroring your way to the workflow that fits a job.
123
+ Find it once, keep it, reuse it. It is a seed of something bigger over time.
133
124
 
134
- Each rung POCs its riskiest assumption; a rung that cannot meet its exit stops the
135
- ladder, and the stop is a result.
125
+ ## Running it
136
126
 
137
- | Rung | What lands |
138
- |---|---|
139
- | **N0** ✅ | Port + outer shell + spine (token-free) — v0.1.0 |
140
- | **N1** ✅ | Job/close schema + validator — v0.2.0 |
141
- | **N2** ✅ | Single-job headless loop — job #1 minimal (review→fix→PR, hard greens only) — v0.3.0 |
142
- | **Layer R** ✅ | Within-run ratchet: shell-side fixation detector (intent) + rejected-edit feedback (outcome), **shipped OFF by default** (F41: fixation in remission, so ON has never won its A/B; F43 split the two axes; field read + default decision defer to Layer 2) — v0.4.0 |
143
- | **Layer 2** ✅ | plan-v1 micro-wheels — the road: bounded steps with in-run verifiable exits (the F39-measured semantic converter), accepted on the real-model battery (F47) — v0.5.0, then finished by T·A·P·U (a wall clock, variance-triggered replan, the 14-verb palette, user-mode e2e) |
144
- | **N3** | Executed inheritance + contrast-bit extractor — **kill-switch: rules must transmit across non-identical runs** |
145
- | **N4** | Verdict classes complete (soft/HITL minting) |
146
- | **N5** | Scheduler + budget ops |
147
- | **N6** | The panel ([spec](docs/01-product/PRD.md#appendix-a--panel-spec-provisional): left chat + command bar, right progress over results, context-graph reserved) |
127
+ bareloop runs locally, as you. Secrets load from the environment and never enter the tree or
128
+ the run's records. It reduces exposure but it is not a sandbox: the code your job writes runs
129
+ with your permissions, so give bareloop a repo you would let an agent touch.
148
130
 
149
131
  ## The bare ecosystem
150
132
 
151
- Local-first, composable agent infrastructure. Same API patterns throughout —
152
- mix and match, each module works standalone. bareloop is the suite's flagship consumer:
153
- it exercises every package and gaps get fixed upstream, never shimmed.
133
+ Local-first, composable agent infrastructure. Same API patterns throughout. Mix and match,
134
+ each module works standalone. bareloop is the suite's flagship consumer: it exercises every
135
+ package, and gaps get fixed upstream rather than shimmed.
154
136
 
155
137
  **Core** — the brain, the gate, the memory.
156
138
 
@@ -164,10 +146,12 @@ it exercises every package and gaps get fixed upstream, never shimmed.
164
146
  - **[baremobile](https://npmjs.com/package/baremobile)** — Android + iOS device control. *Screen in → pruned snapshot out.* Replaces Appium, Espresso, XCUITest.
165
147
  - **[beeperbox](https://github.com/hamr0/beeperbox)** — 50+ messaging networks via one MCP server. *Chat in → unified message stream out.* Replaces Twilio, per-platform bot APIs.
166
148
 
167
- **Why this exists:** most automation stacks make you design the workflow before you know
168
- what works. bareloop's bet — proven in adaptlearn — is that for repeated, verifiable
169
- jobs, selection under an honest gate designs a better workflow than you would, and shows
170
- its receipts.
149
+ ## Background
150
+
151
+ bareloop is the productization of **[adaptlearn](https://github.com/hamr0/adaptlearn)**, a
152
+ closed experimental record on whether agent-authored workflows improve under an honest gate.
153
+ The design laws it inherited, and the open questions it has not answered yet, are in
154
+ [`docs/01-product/PRD.md`](docs/01-product/PRD.md).
171
155
 
172
156
  ## License
173
157