Releases: Jason-Vaughan/TangleBrain
v0.15.0
Added
- Per-parent-task delegation tree (cross-process linkage, scatter-gather roadmap #39 stretch /
closes #52). Each delegated sub-call is now linked back to the specific top-level task that
spawned it, across the process boundary. The CLI mints a task id per routed task; the
orchestrator-CLI adapter injects it asTANGLEBRAIN_TASK_IDinto the orchestrator's environment
(only when the delegate tool is injected), the orchestrator forwards it to the MCP delegate child
it spawns, andrun_delegatereads it back to stamp each delegate record'sparent_task_id. Task
records gain atask_id, delegate records gain aparent_task_id(both written only when present,
so existing records and readers are unaffected).tanglebrain --statsand the rollup gain a
by_parentgrouping — "Linked to: N parent task(s)" — with sub-calls run outside a propagated task
grouped asunlinked. The linkage was manually verified live through the real claude→MCP-delegate
boundary (the env survives the orchestrator's subprocess hop; the parent and delegate records
shared the same id) — the orchestrator-forwards-env hop is a load-bearing assumption, not a
TangleBrain-enforced guarantee, so a delegate that loses the env degrades safely tounlinked(never
an error). This was the deferred half of the scatter-gather epic whose entry criterion was a
live-verification spike — now done. - Knob panel surfaces the delegation tree. The panel's "Delegated sub-tasks" card now shows a
Linked to stat (N parent task(s), with anyunlinkedsub-calls noted) — GUI parity with the
tanglebrain --statsrollup, so the per-parent-task linkage is visible in the panel, not just the
CLI. Read-only; no new endpoint (the data already ridesview_stats's rollup payload).
Fixed
pyproject.tomlpackage metadata carried the purged "cost-tiered / flat-rate subscriptions"
framing that the public-rollout neutralization scrubbed everywhere else (#42). Both thedescription
and thecost-tieredentry inkeywords(→local-llm) — the metadata rendered on the repo and any
package index — now match the neutral positioning used in the README andARCHITECTURE.md:
"A local-first, config-driven LLM router across OpenAI-compatible backends you own."
Internal
- Gated live smoke check for delegate parent-task linkage (closes #55). A
TANGLEBRAIN_LIVE-gated
test routes a delegation-inducing prompt through the real router → orchestrator →delegate_local
and asserts each delegate record'sparent_task_idmatches the parent task'stask_id— a standing
guard for the load-bearing "orchestrator forwards env to the MCP child" assumption (it skips, never
fails, if the orchestrator doesn't delegate that run, since delegation is emergent). Test-only; gated
off in CI.
v0.14.0 — delegate observability + metering
Delegate observability + metering — slice 6 of the scatter-gather roadmap (#39).
Added
- Delegate observability + metering. Delegated sub-calls are now metered: every
run_delegateexecution (including eachdelegate_manyitem — metered at one seam) is logged as akind: delegateusage record with its served backend + estimated tokens.tanglebrain --statsand the knob panel gain a "Delegated sub-tasks" breakdown by backend (count, est tokens, informational cloud-equiv).- Delegate records are kept out of the "spend avoided" headline so a sub-call's saving is never double-counted against its parent task.
- Concurrent fan-out appends are serialized by a process-level lock.
- Records carry a new
kindfield (task/delegate; older records read astask). - The per-parent-task tree (cross-process linkage) is deferred.
This closes the deferred metering noted since the measurement layer landed, and builds on parallel fan-out (#39 slice 3, v0.13.0).
Internal
- Documented the synthesis/reduce pattern (#39 slice 4): TangleBrain doesn't own the reduce step; the orchestrator synthesises
delegate_manyresults itself, offloading a mechanical stitch viadelegate(task=…). No reducer tool ships.
Full changelog: https://github.com/Jason-Vaughan/TangleBrain/blob/main/CHANGELOG.md
v0.13.0 — parallel fan-out
Parallel fan-out — slice 3 of the scatter-gather roadmap (#39).
Added
- Parallel fan-out (
delegate_many). A new MCP tool lets an orchestrator fan several sub-tasks out concurrently in one call and collect them, instead of delegating one at a time. Each item ({prompt, target?, task?, max_tokens?}) routes independently — a batch can mix backends — and runs on a thread pool over the existing syncrun_delegate(plain Python, no new deps).- Results come back in input order with a per-item
status:ok(+text),no_fit(+message), orerror(+error). A failing sub-task never sinks the batch. - Concurrency is bounded by a system-derived default (
os.cpu_count()), an operator override (newdelegate_max_concurrencyinsettings.yaml— pin it to your backend's real parallelism, e.g.OLLAMA_NUM_PARALLEL), and an optional per-callmax_concurrencythat may lower it. - Dispatch + collect only — synthesis stays the orchestrator's job.
- Results come back in input order with a per-item
Builds on capability-routed delegation (#39 slice 2, v0.12.0). Still ahead on #39: synthesis/reduce, orchestration-tree observability.
Full changelog: https://github.com/Jason-Vaughan/TangleBrain/blob/main/CHANGELOG.md
v0.12.0 — capability-routed delegation
Capability-routed per-sub-task delegation — slice 2 of the scatter-gather roadmap (#39).
Added
- Capability-routed delegation. The
delegateMCP tool gains ataskparameter: an orchestrator can delegate a sub-task by the capability it needs (agood_attag, e.g.code) instead of naming a backend id, and TangleBrain selects the cheapestcan_delegatebackend good_at it (localbeforesub, ties by declared order) — sub-task-level task-fit mirroring the request-level router.- Precedence: explicit
targetid >taskcapability > free local default. - Paid
apibackends are never auto-selected bytask(the paid-is-last-resort invariant) — reach one only via an explicittarget. - No fit → hand back to the orchestrator. When no backend fits the capability, the tool returns an instruction for the frontier model to handle the sub-task itself (a
NoDelegateFitsignal caught at the MCP boundary), rather than surfacing a tool error or routing to a poor-fit backend.
- Precedence: explicit
Builds on the generalized delegate (#38, v0.11.0). Still ahead on #39: parallel fan-out, synthesis/reduce, orchestration-tree observability.
Full changelog: https://github.com/Jason-Vaughan/TangleBrain/blob/main/CHANGELOG.md
v0.11.0 — generalized/tiered delegate
First feature release after going public (v0.10.0).
Added
- Generalized / tiered delegate (#38). An orchestrator can now offload a sub-task to a configured backend, not just the free local model. The
tanglebrain-delegateMCP server gains two tools alongside the unchangeddelegate_local:delegate(prompt, target?, max_tokens?)— route a sub-task to any roster entry flagged the newcan_delegate: true(mirrorscan_orchestrate); omittargetfor the free local model.delegate_targets()— list the configured menu (id,tier,good_at,cost,kind) so the orchestrator picks by fit; thedelegatetool's description also enumerates the menu, built at server startup.- Targets are invoked as leaves (no recursive delegation);
apitargets stay behind the billing gate; the menu is secret-safe (never emits akey_ref). Non-local delegate spend is not metered in this version — orchestration-tree observability is tracked on the scatter-gather roadmap (#39), of which this is the first slice.
- Project logo brands the README and the knob panel.
Changed
- README restructured around Problem → Solution; surfaces the OAuth-/local-first credential model and prompt-aware routing. Knob-panel header copy refreshed.
Full changelog: https://github.com/Jason-Vaughan/TangleBrain/blob/main/CHANGELOG.md
v0.10.0 — first public release
A local-first, config-driven router across OpenAI-compatible backends you own. TangleBrain
routes each task to a backend you've configured — a local model by default, with optional
authenticated CLIs and your own paid API keys as overflow — and keeps the whole roster in one
plain, editable YAML file. Adding or removing a backend is a config edit, not a code change.
Highlights
- Local-first routing — ships pointing at a free local model server; nothing leaves your
machine unless you configure a backend that does. - Config-driven roster — every routable backend is one entry in a plain YAML list,
auto-discovered from$TANGLEBRAIN_ROSTER→~/.config/tanglebrain/roster.yaml→ the packaged
example, so agit pullnever clobbers your config. - Frontier-first orchestration — drive authenticated CLI backends as orchestrators with
rotation and failover across them for resilience. - Local sub-task delegation — an orchestrator can offload bulk sub-tasks to the local backend
over an MCP tool, then review the results. - Optional classifier gate — a cheap local pre-filter can send trivial requests straight to the
local backend (off by default, fails safe). - Measurement — every routed task is logged with an estimated cloud-equivalent "spend avoided,"
rolled up bytanglebrain --stats. - Knob GUI — a localhost panel (
tanglebrain-gui) to view the roster, pricing, and rollup, edit
a focused set of config knobs, and run a prompt. - Gated paid-API tier — bring-your-own-key overflow, off by default behind two independent
switches.
Getting started
Requires Python ≥ 3.10.
make venv
.venv/bin/tanglebrain --local "Write a haiku about local inference."See the README to add orchestrator backends, ARCHITECTURE.md for
how the pieces fit, and DISCLAIMER.md for the opt-in / bring-your-own-key posture.
For contributors
CI runs the hermetic test suite on every push and PR. See CONTRIBUTING.md —
adding a backend is usually a config edit, a great first contribution.
MIT licensed.
v0.9.0 — Local classifier gate (off by default)
Added
- Local classifier gate (plan §6 evolution path), off by default. An optional cheap local classify can now run in front of the router: it rates each request's complexity on free local gpt-oss and sends trivial work straight to free local (skipping the rate-limited subs), while frontier work falls through to the normal frontier-first router — preserving sub rate-limit runway when rotation alone isn't enough.
- Off by default: new
classifier_gate_enabledsetting (defaultfalse); per-run--gate/--no-gateoverride. Built ahead of the §8 data trigger, so existing routing is unchanged until enabled. - Fail-safe by design: rates task complexity (not "can the local model do it?"), and any ambiguity/error/negation resolves to frontier — the gate can never trap a hard task on local. New
tanglebrain/classifier.py; gated work meters aspath=gate-local.
- Off by default: new
Notes
- 316 hermetic tests pass; independent Critic review found no blockers.
- The paid-API tier remains hermetically tested but live-unverified by design (anti-key stance) — see #23.
Full Changelog: v0.8.0...v0.9.0
v0.8.0 — Editable roster in the knob panel
Completes the deferred half of the C5 knob GUI: the tanglebrain-gui roster card is now editable, comment-preserving, with zero new runtime dependencies.
Added
- Editable roster in the knob panel (plan §5/§9.2). A focused set of per-entry scalar fields is editable from the panel —
enabled,can_orchestrate,budget_usd_month,good_at— each row with its own Save.- Comment-preserving, no new deps: a new
tanglebrain/roster_edit.pyedits the targeted value on the targeted line in place, so every inline comment, blank line, the nestedinvokeblock, and the commented paid-API example survive byte-for-byte — no YAML round-trip library. Adding/removing/reordering entries and editing theinvokeblock stay hand-edits. - Write-safety mirrors the pricing editor: edits are validated and the candidate is re-parsed with the real loader before any write (a surgical slip can never land a malformed roster), the prior file is backed up to
<state_dir>/backups/roster-<ts>.yaml, and the write is atomic. The panel sends only changed fields and confirms before overwriting the trackedconfig/roster.yaml. - New
views.save_roster_view()+POST /api/roster.
- Comment-preserving, no new deps: a new
Notes
- 295 hermetic tests pass; independent Critic review found no blockers.
- With this, the planned build (C0→C7 plus the deferred GUI roster-editing item) is complete.
Full Changelog: v0.7.1...v0.8.0
v0.7.1 — __version__ no longer drifts
Fixed
tanglebrain.__version__now derives from the installed package metadata (importlib.metadata.version) instead of a hardcoded literal, so it always trackspyproject.tomland can no longer drift from the released version — it had been frozen at0.1.0since C1 while releases moved on. Falls back to0.0.0+unknownwhen imported from an uninstalled source checkout. Closes #17.
Full Changelog: v0.7.0...v0.7.1
v0.7.0 — Paid-API tier complete (off by default)
Completes the paid-API tier (closes #2): an off-by-default, LiteLLM-fronted last-resort tier with full operator visibility. Builds on v0.6.0's gate + adapter (C6a) with last-resort routing (C6b) and panel visibility + a runbook (C6c).
Added
- C6b — last-resort paid-API routing. The frontier-first router now falls through to a paid
tier: apientry as a genuine last resort (plan §6): only after everycan_orchestratesub has failed/exhausted, and only when theapi_billing_enabledgate is on. Gate off (the default) → the router never reaches a paid tier. Enabledapientries are tried in roster order; a paid success is meteredtier=api/spend_avoided=0but does not advance the rotation cursor; paid failures fail over with the same[rate-limit]annotation. Requires ≥1 orchestrator (never paid-routes a subless roster). - C6c — paid-API visibility + runbook. The
tanglebrain-guiknob panel surfaces each entry'senabledkill-switch andbudget_usd_month(display-only), plus a Paid-API billing: ON/OFF banner from the global gate. Newview_settings()+GET /api/settings(reads onlyconfig/settings.yaml; no key file touched). README gains a step-by-step runbook for minting a budget-scoped LiteLLM virtual key on Monad and wiring it viakey_ref.
Notes
- Off by default and safe: paid billing requires the explicit
api_billing_enabledgate and a per-entryenabledflag. Custody is LiteLLM-fronted (a scoped virtual key viakey_ref); the hard budget cap is enforced LiteLLM-side, not by TangleBrain (v1 decision). - 265 hermetic tests pass; each chunk passed an independent Critic review.
Full Changelog: v0.6.0...v0.7.0