Repository navigation
The config is grouped, the commands are grouped, and the engine that runs both
is split into crates that can be tested apart. A 0.3 config still loads and a
0.3 command still works, so the upgrade is a cargo install — but both now
print where the thing they named has moved to, and loopsmith loop migrate
rewrites a file in place.
Read Migration 0.3 → 1.0 before upgrading a
loop you cannot afford to re-run.
Changed
-
Breaking: the config has four bundles instead of twenty-two top-level
keys.intentis what the loop is for,executionis how it runs,safety
is what must not happen, andevolutionis what it is allowed to change about
itself.name,version,description,environmentandfeaturesstay at
the top, because they describe the file rather than the loop.Every old key has exactly one new home, and there is exactly one description
of where — the table inconfig/legacy.rs. The loader applies it, so a 0.3
file parses and reports each key it moved;loopsmith loop migrateapplies the
same table to rewrite the file, and--writeis required before it touches
anything. A migrator that disagreed with the parser would produce a file
meaning something other than what it replaced, which is why there is one table
and not two pieces of code.The sections also lost their letters. A validation was "section D" in 0.3 and
issafety.checksin 1.0, in every error message, every document and every
card in the browser. -
Breaking: the commands are grouped under four nouns.
loopmakes and
checks config files,runconcerns an actual run of one, andmemoryand
skillscover what outlives a run.doctor,providers,webandmcp
stay where they are, because each is one thing.Every 0.3 verb still works. The rewrite happens in one table before the
argument parser sees anything, prints a notice naming the new spelling, and
only ever looks at the first argument — so a config file namedvalidateis
in no danger. At 2.0 that file is deleted whole rather than unpicked from the
grammar. -
The workspace is twelve crates.
loopsmith-coreholds the model and the
validator,-runthe engine,-graphthe wave planner,-memorythe store,
-providerthe model cascade,-gatethe regression gate,-skillsthe
marketplace,-wizardthe guided walk-through,-webthe browser,-mcpthe
server,-utilthe shared parts, and-clithe binary that wires them
together. What used to be one crate's private modules can now be tested
without building the CLI. -
An unknown key inside a config is refused rather than dropped. Every
struct and every internally tagged enum in the model rejects a field it does
not know, including variants that carry no fields of their own. A misspelled
idempotency_kyeused to parse and leave a trigger with no deduplication and
no warning. -
The minimum supported Rust version is 1.85, up from a documented 1.75 that
had already stopped being true — the dependency graph needed 1.85 and nothing
checked. CI checks it now.
Added
-
A run has a lifecycle. Every run moves through named states, writes a
ledger entry at each, and can be resumed from its last checkpoint. An
unreadable checkpoint is answered by thecorrupted_staterecovery policy
rather than by a panic. -
Typed recovery per failure class.
transient_error,invalid_output,
tool_unavailable,repeated_failure,safety_violation,
resource_exhaustionandcorrupted_stateeach name an action — retry with backoff, revise, fall back
to the next provider, escalate, pause, restore a checkpoint, or stop. -
Join strategies and derived concurrency. A wave finishes when every node
does, when a quorum does, or when the first one succeeds. Width is
sequential, a fixed number, or derived from the graph itself and trimmed to
the point where another worker stops paying for itself. -
Container isolation that degrades instead of failing. A node can run in a
container over its own worktree; where Docker is absent it runs in the
worktree and the run records a warning, because the same loop directory gets
checked out on laptops, CI runners and servers. -
Memory namespaces that outlive a run, with promotion as the bar. A record
moves from observed to reusable never, automatically, after this many
independent corroborations, or only once a human says so. -
Metrics, alerts, trigger idempotency and the evolution gates. A trigger
that can be fired by the loop's own output is capped by depth; a proposal the
loop makes about itself goes through a gate before it applies. -
The browser has three doors. An experienced smith goes straight to the
six-step editor, a new one gets the explanation and a working example to start
from, and either can switch. The form reaches every section the config has,
the questions are a declarative mirror of the terminal's, and a run can be
watched rather than read.--webbinds to127.0.0.1and has no
public-bind mode. -
A landing page at the project's own address, and fifteen worked examples
in the 1.0 shape — each generated from one source, with the 0.3 originals kept
beside them as a corpus the migration is tested against. -
One architecture diagram, rendered rather than copied.
assets/
holds the source; the PNG and the text form are generated from it and checked
byte for byte, as are the three package READMEs, the markdown twin of every
example, and the grade level of the plain-English README.
Fixed
Two end-of-phase reviews, run as separate standards and spec passes, found
these implemented but wrong. Each is fixed with a test at the seam it failed at.
- A retry sleeping out its backoff called its provider even after the iteration
had stopped dispatching — after a halt, or after a sibling crossed a budget
ceiling. Workers now share a stop flag and a waking retry checks it. - A worker that panicked never reported, and the dispatcher waited for it
forever. - A rollback left the discarded iteration's rulings in the store, where
status
and agoal_satisfiedtrigger would act on them. - The watcher counted every
file_changeas the loop's own doing, so a human's
sixth file into a watched inbox was refused forever. A firing now extends the
chain only if it plausibly came from the last run. - Alerts fired again on every resume, and the retry and failure counters reset.
Both are in the checkpoint now. - A judge whose output stayed unusable through every revision was logged as
having succeeded. - The first exponential retry waited twice the base delay.
- A failed checkpoint save was ignored.
- Resuming never let an escalated node run again, because its spent revisions
came back with the checkpoint. Answering is now an explicit act: a plain
resume leaves escalations open and their nodes held, and says so, while
loopsmith run resume --answerclears them and refunds each node's revisions.
Refunding on every resume would have handed a stuck node a fresh budget
unattended, which is the guarantee the stress suite holds. install.batfailed on every stock Windows machine. It runs
install.ps1under Windows PowerShell 5.1, which reads a file with no
byte-order mark in the ANSI code page, where the last byte of an em dash is a
curly double quote — and PowerShell takes curly quotes as string delimiters.
One dash in a log message ended its string early and the script failed to
parse on first use. Behind that was a second failure: 5.1 treats a native
command's stderr as an error once it is redirected, so even a successful
build died on cargo's own progress lines. Nothing ran the installer on
Windows until 1.0's CI did. The Windows scripts are plain ASCII now, with a
test that keeps them so, and every native step is judged by its exit code.- The PyPI package's first run could sit silent for minutes. It downloads
the binary with Python'surllib, which spends its whole timeout on each
address that does not answer before trying the next; on a network that could
not reach one of GitHub's four CDN addresses, that was two minutes per
download and nothing printed. It now says what it is fetching before it
starts, and gives each step twenty seconds. - The expert editor edited a config the server did not serve.
- The Homebrew formula's test invoked a command spelling that 1.0 had moved,
which would have failed on the first 1.0 build. Nothing checked Ruby lists of
strings; something does now.
Removed
installers/install.ps1moved to the repository root besideinstall.sh, so
both installers are where somebody cloning the repository will look. Every
fact the two share now comes frominstallers/manifest.json.