Skip to content

Releases: alexnodeland/hoist

Release list

Hoist v0.2.0

Choose a tag to compare

@github-actions github-actions released this 15 Oct 18:41
7699919

A file in the way of hoist init --force

  • hoist init named the "pass --force" advice whenever writing a configuration file failed because the path already existed, even with --force given. With --force that error means a directory is in the way, which --force does not fix, so it now says it could not write the path.

The project is now Hoist

stretto is renamed Hoist. Nothing had been published under the old name and it had no users, so the rename is complete and nothing migrates.

  • The crates are hoist-trace, hoist-model, hoist-oracle, hoist-report and hoist-mcp (the proxy, formerly stretto-proxy), and hoist-console. The binaries are hoist, hoist-mcp, hoist-procedure, hoist-mcp-demo and hoist-console. No stretto binary or alias remains.
  • The data directory is ~/.hoist, and HOIST_HOME overrides it. The environment variables are HOIST_*, in place of STRETTO_*. Neither the old directory nor the old variables are read.
  • The tool the proxy adds for the agent is hoist_commit. A call to a tool named stretto_commit in a session log is shown as an ordinary call of the agent, under the name written; it is not read as a commit.
  • The file formats are named hoist_mcp_log, hoist_servers, hoist_arbiter, hoist_flow, hoist_procedure and hoist_stage, and a flow's provenance names the writer as hoist. Files written before the rename do not load. The flow and procedure files under docs/results/, and the flows and session logs inside its tarballs, were rewritten in those keys, and the proxy's call ids stretto-N became hoist-N in the logs. Nothing else in them changed, and the ledger's values are unchanged.
  • The console's header is X-Hoist-Console, and the header that names a host session over the proxy's HTTP transport is Hoist-Session. The images are ghcr.io/alexnodeland/hoist and ghcr.io/alexnodeland/hoist-console, the release archives are hoist-<target>, and the site is hoist.alexnodeland.com. The repository is github.com/alexnodeland/hoist, and GitHub redirects the old address.
  • The six hoist-* crates are published on crates.io as empty 0.0.0 placeholders, to hold their names; no release is published there. The crate named hoist is an unrelated tool, so cargo install hoist installs something else.
  • Results pages, their rows and archives, the research notebook, RFC-001's body and the entries below Unreleased keep the name they were written under. The replay cache keys carry no product name, so cached answers still replay.

Two deep-dive films, and the explainer on the home page

  • The site's home page opens on the explainer video, full width under the hero's words, with a play button and a "Watch the explainer" action. The two deep dives sit under it, each playing in place. Every player on the site starts with its captions track off, since the films set their captions in the picture; the player's captions control still turns it on.
  • A film on the math and the probabilistic programs inside Hoist (brand/media/math.mp4), on the research page beside the paper. It covers the event a lookup is decided on, Proposition 1, the rule and its live costs, the back-off counts, alpha's posterior as a fugue program, the bindings, and how the estimate held up: calibration, the threshold sweep, the share of the ceiling, the live tasks and learning from few sessions. Its formulas are typeset, each symbol in one color throughout, each term named where it sits, and its derivations are worked in place. Where a value moves (q, alpha, the bindings tried, the threshold), the numbers in the formula beside it follow. Its charts draw the published rows of the reach round, and alpha's posterior is fugue's own run on the console's test fixtures (brand/video/math/data/). Every number has its scope on screen.
  • A tour of the console (brand/media/console.mp4), on the console's guide page. It is made from the real console over its test fixtures: brand/video/console/capture.sh serves them, and capture.mjs drives the console as a user does and saves each shot.
  • The films open on their titles: the explainer's and the console film's wordless openings are gone. The explainer's stays as the README's teaser.
  • The films share one stage (brand/video/stage/) and one renderer, node brand/video/film.mjs FILM. narrate.py voices any film on it, compares numbers digit by digit, and pins "Dirichlet" and "nats" in its lexicon.

The explainer video, remade

  • The explainer video (brand/media/explainer.mp4) is a new film: ten chapters, one diagram each, on a still stage, from the proxy's own output to the live results and how to start. It adds a chapter on the console, shown from its own screens. It shows the real thing: the reads a result carries as the proxy writes them, τ²-bench retail's tools, the counts of the flow in docs/examples/, and the commands of the docs. The line being spoken is set at the foot of the frame, each word lit as it is said. The poster and the README's teaser come from it.
  • The voice-over of both videos and of the interactive explainer is Kokoro-82M's af_heart, run locally (brand/video/narrate.py), in place of Chatterbox. Each line is checked by speech recognition as before. The videos have no sound effects now: the voice, the music bed under it, and its motif in and out.
  • brand/video/PACING.md records the pacing the film follows, measured from Auracle's films: one breath a sentence, one idea a line, and silence written into the script.

The paper in two columns, with more figures

  • The paper's PDF (paper/latex/) is set in two columns, with the abstract boxed, the propositions boxed, run-in heads in the accent color and running heads. A table or figure spans both columns only when it is too wide for one, and the note under a table travels with it.
  • Six new figures: how a lookup spares an LLM turn and the event the speculator estimates (Figure 1), a read's expected value against its probability of use at the counted costs of retail, airline and telecom (Figure 2), what decides each turn across the benchmarks (Figure 4), the share of the ceiling each speculator takes in replay (Figure 8), the live comparisons of the speculator and of a prompt for parallel calls, with their intervals (Figure 10), and the cascade on solo telecom (Figure 11). scripts/paper_diagrams.py draws them, from numbers written as the paper writes them, and fails if the paper's text (its figures' captions aside) does not hold each one in its sentence or table row. The earlier figures are renumbered.
  • scripts/paper_figures.py sets the ceilings in two panels side by side and the reliability diagrams narrower, for the two-column page.

The cold start on more agents

  • scripts/cold_draws.py run learns three flows from random draws of an agent's first sessions (the habit alone, the draw's own arbiter, a shipped arbiter) and replays each on the agent's test episodes; report gives each flow's spread across draws, how many draws save under half of what every training task gives, and the shipped arbiter's paired difference (#9).
  • Measured (results): on Qwen3.5-397B, Claude Sonnet 4.5 and Claude Opus 4.5, twenty draws of 5 and 10 sessions each. From five sessions the habit alone saved under half in 16 of 120 draws; a shipped arbiter lifted 13 of the 17 narrow draws above half, at no more than 3.3 points of the median. Jev's 39,541 new answers are published.

Flows and guards together

  • pilot/run_episode.py --arm reach-guards serves a flow on the reach decider with the guards in the proxy, the design's arm E (#8). pilot/run_paired.py --model runs another agent model, and --flow-oracle mock spares Jev's key for flows that ask no model.
  • Fixed: the guards, and the confirmation judge's check of the records a write names, read the lookups a flow appended to a result as reads the agent was shown (hoist_trace::mcp::appended). When the server behind the proxy runs the flow, as the pilots' tau2_mcp.py does, its lookups reach the proxy inside the agent's own result. The guards read that result whole, so a user id with lookups after it authenticated nobody, and they refused writes the policy allows.
  • Measured (results): glm-5.3-flash, served a flow learned from Claude Opus 4.5's, Claude Sonnet 4.5's and Gemini 3 Pro's training episodes with the guards, took 20.8% fewer LLM turns on the pilots' twenty tasks, 33.3% in retail and 10.1% in airline. Passes held at 18 of 20, and the guards refused one write, which the tool refuses too.

Tickets no trace showed

  • scripts/telecom_workflow.py --unseen N runs the compiled procedure on tickets of τ²-bench's full telecom set whose faults no base task combines, N of them drawn with --seed, or all 2,171 (#38). pilot/run_procedure.py --unseen N --seed S runs the same draw through hoist-procedure. pilot/tau2_mcp.py and run_episode.py find a task in the domain's full split when its default tasks lack it, so a solo agent and the cascade's hand-backs run on those tickets too.
  • Measured (results): the procedure passed 84.3% of the 2,171 tickets with no model, the same tickets for a customer renamed throughout, and handed back 334, all failures. hoist-procedure matched the script on 100 of them. Claude Haiku 4.5 resolved 19 of 20 hand-backs, and passed 8 of 20 tickets alone.

τ²-bench's own reward

  • pilot/run_episode.py records τ²-bench's own reward beside the database check: reward_basis in result.json, the product of...
Read more