cd /news/developer-tools/show-hn-offshoot-copy-on-write-branc… · home topics developer-tools article
[ARTICLE · art-98780] src=github.com ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Show HN: Offshoot – Copy-on-write branching for stock SQLite files

Offshoot, a new open-source tool, introduces copy-on-write branching for stock SQLite files, enabling AI agents and eval harnesses to fork databases instantly with minimal storage overhead. A shared fork of a 100 MB database adds only 377 bytes to the store, about 280,000 times less than a full copy, and every checkout is a plain .db file. The tool supports commands like create, fork, checkpoint, rollback, and promote, and includes a daemon mode and MCP support.

read21 min views3 publishedAug 16, 2026
Show HN: Offshoot – Copy-on-write branching for stock SQLite files
Image: Michielbdejong (auto-discovered)

Branch SQLite like git — fork-per-attempt databases for AI agents and eval harnesses.

Create, fork, checkpoint, rollback, promote — as stock SQLite files, on your storage, with one binary.

Quickstart · Install · Daemon · MCP · SDKs · Benchmarks · FAQ · Roadmap

377 B

per shared fork of a 100 MB database · kill -9

durable · every checkout a stock .db

file

An agent attempt or eval run needs a real database it can trash: mocks aren't real, re-seeding is slow, and container or VM snapshots version a whole machine to get at one file. offshoot branches the database itself — copy-on-write forks of stock SQLite files over a local directory or an S3-compatible bucket.

A shared fork of a 100 MB database adds 377 bytes to the store — about 280,000× less than a copy — and every checkout is a plain .db

file any SQLite tool opens. Try N migrations or N agent attempts on N forks, promote

the winner, and let the losers expire:

              fork ┌─ attempt-1 ●──✗            expires (TTL)
                   │
  main ●───────●───┼─ attempt-2 ●──●──✓   ──►   promote: main repoints here
       seed    cp  │
                   └─ attempt-3 ●──✗            expires (TTL)

No merge, no conflict resolution — the winner is promoted whole and the losers reap themselves. (That's a design position, not a gap: what offshoot deliberately doesn't do.)

go build -o offshoot ./cmd/offshoot
./offshoot init
./offshoot create app
sqlite3 "$(./offshoot checkout app)" "CREATE TABLE users (name); INSERT INTO users VALUES ('ada');"
./offshoot checkpoint app v1
./offshoot fork app attempt-1        # instant branch
sqlite3 "$(./offshoot checkout app@attempt-1)" "DELETE FROM users;"   # destructive experiment
./offshoot rollback app@attempt-1 --to fork                        # undo it
./offshoot promote app@attempt-1 --onto main --force               # or ship it
./offshoot status

That's most of the surface already. The full vocabulary, one line each (every command and flag: docs/reference.md):

Command What it does
create / checkout
new database / materialize a working copy — prints a plain .db path
checkpoint
snapshot the checkout as a named, rollback-able point
fork
branch from head or a checkpoint — instant, copy-on-write, optional --ttl
rollback / promote
repoint a branch at a checkpoint / repoint a target at a branch's head
diff / export
sqldiff two branches or checkpoints / copy state out to a plain file
destroy / gc
delete a branch / collect unreachable objects
serve / session
the daemon: leases, live capture, flush-without-pausing (

mcp

below)Runnable demo: examples/parallel-attempts/ forks a database three ways, races three migrations against the forks, promotes the one that's actually correct, and discards the other two —

./examples/parallel-attempts/run.sh

. Real recording: (play locally with

docs/demo/parallel-attempts.cast

asciinema play

).## Transcript of that demo, from a real run — nothing doctored

==> building offshoot
==> creating a database with some data
    3 orders, checkpoint 'before-migration'
==> keeping the pre-migration state on its own branch
    forked 'pre-migration' from the 'before-migration' checkpoint — promote wipes main's own checkpoint history, so this fork is what actually survives
==> forking three attempts (instant, no copy)
==> running the migrations in parallel forks
    attempt-1: FAIL
    attempt-2: FAIL
    attempt-3: PASS
==> winner: attempt-3
==> promoting the winner onto main
    promoted
==> discarding the losers
==> main now has the migrated data:
    id|total|total_cents
    1|19.99|1999
    2|8.70|870
    3|4.35|435
==> and the pre-migration state is still one command away, on its own branch:
    offshoot checkout shop@pre-migration

Building an eval harness or a test suite around this instead of a one-off script? docs/eval-harness.md is the paved road: seed once, fork per test, xdist/vitest parallelism, golden-file assertions, TTL cleanup, and a CI recipe — for Python (offshoot.pytest_plugin

) and TypeScript (testkit

) alike. offshoot export

copies a checkpoint out to a plain file for handoff, and offshoot diff

answers "what changed between these two attempts" — see docs/diff.md and docs/reference.md.

Copy-on-write forks, measured. A shared fork writes two tiny objects — 377 B for a 100 MB database, flat from 1 to 100 forks — and forking a named checkpoint takes ~9–12 ms whether the database is 12 MB or 1 GB. A diverging child pays only for the pages it changes (~776 B per single-row transaction). Numbers, method, and the honest caveats:docs/benchmarks.md.kill -9 durable. The torture harness runs a stocksqlite3

CLI writer andSIGKILL

s it mid-write on roughly half of every round, while bouncing the capture engine mid-traffic every 10th round; the replica must converge to byte-identical dump output after every round. A 300 s run is ~3,500 rounds — zero divergence — and it runs in CI on a nightly cadence:docs/testing.md.Stock everything. A checkoutisa SQLite file — no forked engine, no special VFS on the read path — andoffshoot export

materializes any branch or checkpoint to a plain.db

with zero ongoing relationship to the store. The exit hatch iscp

, and the pre-1.0stability contractguarantees any format break ships with a migration or a documented export path in the same release.Agent-native. MCP tools so the agent forks before risky work and promotes what passed (); TTL'd branches that reap themselves so a forgotten attempt doesn't leak; pytest fixtures and a vitest/jest testkit for fork-per-test isolation (offshoot mcp

docs/eval-harness.md); a LangGraph companion and framework recipes (docs/recipes/).

No row-level merge. The workload is fork-many-keep-one:promote

the winner whole, let the losers TTL away. Real merge would forfeit the single-fenced-writer invariant the safety story rests on — if you need it,Dolt is built for that.No multi-writer branches. Exactly one leased, epoch-fenced writer per lineage; two agents writing "at once" get two forks and apromote

(why).No managed service, no multi-node. Your bucket, your binary, Apache-2.0; replication, failover, and the word "cluster" are explicitly out of scope for v1 (non-goals,why not Turso/LiteFS).

More "why not X" (Litestream, Dolt, Neon, plain cp

): docs/faq.md.

Channel How
Homebrew
brew tap sricola/offshoot https://github.com/sricola/offshoot && brew trust sricola/offshoot && brew install offshoot — recent Homebrew requires the explicit trust for third-party taps; the formula lives in-repo at
Formula/offshoot.rb
Docker
docker run --rm -v offshoot-data:/data ghcr.io/sricola/offshoot:latest init — images publish to GHCR on every tagged release; the store lives in the /data volume, so reuse -v offshoot-data:/data across commands (… create app , … serve , and so on)
Prebuilt binaries
offshoot_vX_os_arch.tar.gz (+ .sha256 ) from the
go install
go install github.com/sricola/offshoot/cmd/offshoot@latest
From source
the Quickstart above (Go 1.25+, cgo)

The full guide — store setup, S3 configuration, the fail-closed probe: installation.

Requires Go 1.25+ and cgo to build, and the sqlite3

CLI for tests. Linux and macOS only. Windows: use WSL2 — the Linux binaries, Docker image, and build-from-source all work there as-is. Native Windows is unsupported: offshoot leans on POSIX file semantics (unix sockets, POSIX locks) that don't map cleanly to Windows (why).

v0.2.9. What's shipped and exercised by tests that would fail if it broke:

  • local and S3-compatible stores behind a shared conformance suite
  • copy-on-write forks; checkpoint / rollback / promote / export / diff
  • live WAL capture with incremental segments
  • leases with epoch fencing, and CAS on every ref update
  • TTL reaping and GC
  • the daemon, with metrics and events; an MCP server
  • Python and TypeScript SDKs with test fixtures

docs/status.md is the honest per-feature accounting — shipped-and-tested vs. shipped-but-unverified vs. still on the roadmap — and docs/testing.md shows the CI gates behind the "tested" column.

The caveats, stated plainly: the CLI surface and the on-disk storage format may still change before 1.0 — but never silently. Every store records a layout version, and a binary that doesn't understand a store's layout refuses the whole store rather than guessing (0.2.0's first copy-on-write fork exercised exactly that gate for real — see CHANGELOG.md). Any format break ships in the same release with a migration or a documented export

create --from

path: the stability contract is the full promise, including the proposed v1.0 criteria. 1.0 is reserved for the point the storage format freezes.

offshoot -store ./.offshoot init                 # local directory (default)
offshoot -store s3://my-bucket/offshoot init     # S3-compatible bucket

offshoot's safety rests on compare-and-swap: every branch ref update is a conditional write. At attach time it probes the store and refuses to run if conditional writes are not enforced, rather than silently degrading. That probe re-runs on every command (every CLI invocation attaches fresh) — fail-closed beats a cached "it was fine last time"; a long-lived daemon (below) amortizes it across a session instead of paying it per command.

Configuration for s3://

specs — credentials come from the AWS SDK default chain (environment, shared config, IAM role):

Variable Meaning
OFFSHOOT_S3_ENDPOINT
Custom endpoint (MinIO, or any S3-compatible endpoint)
OFFSHOOT_S3_REGION
Region; defaults to auto when an endpoint is set
OFFSHOOT_S3_PATH_STYLE
1 for path-style addressing (MinIO)
OFFSHOOT_CHECKOUTS
Where checkouts are materialized (remote stores)

A provider is listed as supported only after the conformance suite and CAS probe pass against it for real (make test-s3

) — the in-process fake used in unit tests proves nothing about a real provider.

Provider Status
MinIO verified in CI — the conformance suite runs against real MinIO[1] on every PR and push to main
AWS S3 verified — TestS3RealProvider (probe + conformance + multipart) passed against a real bucket (us-east-1, 2026-08-13)
Google Cloud Storage (S3 interop) unsupported — no conditional writes on the S3 API; the probe refuses it (

[1] minio/minio:latest

digest: sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e

Checkouts are always real local SQLite files; only the snapshots and refs live in the store.

At rest (no daemon running): checkpoints are full snapshots; checkout paths are fixed at <store>/checkouts/{db}/{branch}.db

; operations require the checkout to be quiescent (no live writers). Daemon mode (below) layers live capture, incremental segments, and continuous durability on top of the same commands.

At rest, every offshoot command opens the store, does its work, and exits — so a checkpoint has to quiesce the database. The daemon removes that constraint: it holds the branch under lease and captures every committed transaction while your agent keeps writing.

offshoot serve &                       # holds leases, captures continuously
sleep 1                                # let the listener come up
P=$(offshoot session open app)         # capture the checkout path once
sqlite3 "$P" "CREATE TABLE t (v); INSERT INTO t VALUES ('agent wrote this');"
offshoot session flush app v1          # durable in the store, writer never d
offshoot session status                # durable txid per session
offshoot session close app             # releases the lease

Everything ongoing the daemon does is bounded by a flag — each unpacked in the sections below:

serve flag | Default | What it bounds | |---|---|---| -flush-every | 30s | worst-case committed-but-unflushed work lost if the daemon dies (0 : durability advances only on explicit flush ) | -snapshot-every | 16 | read cost — materializing replays one snapshot plus at most N−1 segments | -reap-every | 1m | how often the janitor reaps TTL-expired branches and runs the GC sweep (0 disables it) | -gc-grace | 15m | how long a tombstoned lineage's storage sits before a later cycle deletes it | -http | off | a loopback, token-authenticated listener: metrics, RPC, events, pprof | -ro-cache-budget | unlimited | disk held by the read-only checkout cache (LRU eviction) | -socket | per-store path | where the unix socket (mode 0600) lives; OFFSHOOT_SOCKET works too |

Durability is explicit and reported. Between flushes, writes are committed to SQLite but not yet in the store; session status

reports the txid each session is durable through. By default the daemon also ships every open session's work on a timer:

offshoot serve -flush-every 30s        # the default; 0 disables it

-flush-every

bounds how much committed-but-unflushed work is ever at risk: worst case, a daemon that dies loses at most one interval's worth of writes. 0

returns to durability that advances only on explicit flush

. The cadence is daemon-wide, not per-session (docs/status.md). A session that loses its lease is fenced and stops — it will not write under a dead epoch — and session status

shows the error.

The daemon serves a unix socket (mode 0600) under your cache directory, one per store; override with OFFSHOOT_SOCKET

or -socket PATH

(pass the same to every offshoot session ...

command). Daemon and agent must share a kernel and a local filesystem: the checkout is a real SQLite file both processes open.

A long-running writer — the daemon — claims a branch with a lease:

offshoot lease list
offshoot lease acquire app@main --ttl 60s
offshoot lease release app@main

Acquiring or reclaiming a branch bumps its epoch, and every object is written under the epoch current at the time. A writer that s, loses its lease, and later resumes writes into a superseded prefix that no ref points at — it cannot corrupt the branch, and its garbage is collected with the lineage. Expiry is wall-clock and advisory; the guarantee against an uncooperative writer comes from the epoch fence and ref compare-and-swap, not from the clock (docs/testing.md). offshoot lease acquire

exits immediately, so its lease expires unless renewed — it exists for inspection and for breaking a stuck lease.

A branch can carry a TTL, set at fork time or any time after:

offshoot fork app attempt-1 --ttl 2h        # reap-eligible 2h after last activity
offshoot touch app@attempt-1 --ttl 30m      # resets the clock, changes the TTL
offshoot touch app@attempt-1                # resets the clock, TTL unchanged
offshoot touch app@attempt-1 --ttl none     # clears the TTL

TTL is measured from the last durable write or lease renewal, whichever is later. A branch with an active lease is never reaped — a daemon session holding a branch open keeps renewing, so the janitor can never reap a branch it's actively writing to. Protected branches (main

, by default) are never reaped regardless of TTL; branches without a TTL live until destroyed. TTLs read back re-rendered through Go's canonical duration form (--ttl 1h

reports as ttl=1h0m0s

).

offshoot serve

runs the janitor — TTL reaping plus the periodic GC sweep — on an interval:

offshoot serve -reap-every 1m -gc-grace 15m   # both are the defaults

-reap-every 0

disables the janitor entirely (GC stays available on demand via offshoot gc

); -gc-grace

is how long a tombstoned lineage's storage sits before a later cycle actually deletes it.

A daemon flush writes only the pages that changed since the previous flush. Every sixteenth flush writes a full snapshot instead, so materializing a branch never replays an unbounded chain: a read applies one snapshot plus at most fifteen segments. offshoot serve -snapshot-every N

tunes that cadence (default 16) — lower N means cheaper, more tightly bounded reads; higher N amortizes the full-snapshot upload across more flushes — see offshoot serve

's entry in docs/reference.md for the full trade-off. An idle session — nothing committed since the last successful flush — skips the tick entirely, so a quiet session pays nothing; cost scales with what the agent actually writes, not wall-clock time.

A session whose checkout had to be (re)materialized at open pays one settling full-snapshot flush, once per session; a session reopened against a clean, current checkout uploads nothing at all for it. The measurement and the exact suppression condition: docs/benchmarks.md and internal/session/session.go

's rebaseline

doc comment.

The at-rest offshoot checkpoint

still writes a full snapshot every time — it runs without a daemon, so it has no record of which pages changed. If you checkpoint large databases in a loop, run a daemon.

Forking is a different cost from flushing — usually no storage cost at all. offshoot fork

shares the parent's already-durable objects through a base pointer: the child records where it forked from and writes new objects only as it diverges, so N forks of a G-byte database cost near-zero added store bytes rather than N×G, and reads stay bounded by construction. The asymmetry to know: fork shares; promote, rollback, and compact each materialize a full independent copy (measured numbers in

docs/benchmarks.md). Destroying a parent stays instant, but its bytes are reclaimed only once no surviving shared child still reads through them —

offshoot compact

cuts that cord on demand. The first shared fork bumps the store to layout version 2, which locks pre-copy-on-write binaries out of the whole store — the refusal is the protection. Full model: docs/reference.md's

fork

/compact

/destroy

sections and docs/operations.md; the storage-cost ledger, stated plainly:

docs/faq.md.

offshoot serve -http ADDR

starts a loopback-by-default, token-authenticated HTTP listener alongside the unix socket: GET /metrics

(Prometheus text exposition, zero new dependencies), GET /healthz

, POST /rpc

(the same protocol the socket speaks), GET /events

(Server-Sent Events for flush/fork/reap/eviction/fencing), and token-gated GET /debug/pprof/*

. Six computed branch states answer "what's this branch doing right now", and -ro-cache-budget

bounds the read-only checkout cache with LRU eviction. All of it is single-node: docs/operations.md has the metrics reference, states table, event schema, budget mechanics, and the HTTP threat model in one place; docs/recipes/kubernetes.md has a real sidecar manifest.

An open session's FD footprint is small and fixed. Disk is the sharper cost: Checkout

reuses a checkout that's already clean and current at the branch's head instead of re-materializing it, so a daemon that keeps reopening the same untouched branch stays flat. A checkout that does get re-materialized (dirty, stale, or destroyed while an earlier descriptor still points at it) strands one descriptor — and the disk behind it — for the life of the daemon process; restarting the daemon reclaims everything. The tradeoff to know: a clean-and-current checkout is served straight from disk without consulting the store's chain. Full mechanics and caveats: docs/operations.md and docs/status.md's resource-behavior rows.

Read-only historical checkouts (offshoot checkout --at <checkpoint> --read-only

) live in a separate checkouts-ro/

tree — one chmod 0444

file per (db, branch, checkpoint)

, no sidecar, no lease, no stranded descriptor — and it is safe to rm -rf the entire checkouts-ro directory at any time; the next call rebuilds what it needs from the store.

offshoot export

's output has the same zero-ongoing-relationship property, written wherever you pointed it.Four ways to talk to offshoot: the CLI above needs no daemon and no SDK; everything below is a client of the daemon's lifecycle API and requires offshoot serve

already running. A fifth, operator-facing surface rides alongside without changing any of them: serve -http ADDR

exposes the same lifecycle API over HTTP (see Metrics, HTTP, and events).

Surface What it is Daemon?

MCPoffshoot mcp

Python SDKTypeScript SDKLangGraph companionHTTPserve -http

isthe daemonoffshoot mcp

speaks the Model Context Protocol on stdio, so an agent can branch on its own initiative instead of asking you to run commands:

claude mcp add offshoot -- offshoot -store ./.offshoot mcp

The agent gets seven tools — list, checkout, checkpoint, fork, rollback, promote, destroy — described so it knows when to use them: fork before a risky migration, checkpoint when tests pass, roll back when they don't, promote the attempt that worked. See it work end to end: docs/demo/mcp-walkthrough.md, a real captured session.

Destructive tools respect the same protected-branch rules as the CLI: an agent can fork and experiment freely, but promoting onto or destroying main

requires an explicit force, and the refusal tells the agent so.

Agent-created forks expire by default, so an agent that forks and forgets doesn't leak branches forever: offshoot_fork

applies offshoot mcp -default-ttl

(default 24h

) to any call that omits its own ttl

; pass ttl:"<duration>"

to override, or ttl:"none"

for a branch that never expires. The response echoes the TTL applied and the computed expiry, so both are visible in the agent's transcript. A TTL alone does not reap anything — reaping is the janitor's job (offshoot serve

), and offshoot mcp

runs no daemon of its own; a daemonless MCP setup only sweeps expired branches when offshoot gc

is run by hand.

MCP rides a running daemon when one is up. offshoot mcp

never opens a session itself — that's a harness's job (the SDKs, offshoot session open

, or your own loop). With an open session on the branch: offshoot_checkpoint

flushes live through the daemon (no quiesce) and offshoot_checkout

returns the session's live checkout path. offshoot_fork

routes through the daemon whenever one is reachable, session or not (an open source session is flushed first, so an unflushed write always lands in the child). With no reachable daemon, every tool runs exactly as it does with no daemon at all. offshoot_rollback

, offshoot_promote

(checked against its target

), and offshoot_destroy

take the opposite stance: each refuses outright — even with force — whenever the daemon has any session open on the affected branch, because all three repoint or delete a ref out from under a session the daemon still owns; close the session first and retry (

offshoot_promote

's source

is the one exception — an open session there doesn't block, but the promoted state is the last-flushed head, not unflushed writes). Details: docs/reference.md.

In short: the good path for

offshoot mcp

is a harness-opened session, opened before the agent's tool calls.sdk/python

is a stdlib-only, thin client over the daemon's lifecycle API — it never opens SQLite itself and can't do anything the CLI can't; it just lets your process drive a running daemon instead of shelling out. Not yet published to PyPI — import it from a checkout of this repo:

offshoot -store ./.offshoot init
offshoot serve -socket /tmp/o.sock &
python
import sys; sys.path.insert(0, "sdk/python")
import offshoot

with offshoot.connect("/tmp/o.sock") as c:
    c.create("app")
    s = c.open("app")              # sqlite3.connect(s.path); write; commit
    s.flush("v1")                  # durable in the store, writer never d
    c.fork("app", "main", "try", ttl="2h")
    s.close()

Client

also exposes branches()

, dbs()

, export()

, and checkout_at()

(a read-only historical checkout).

Testing with pytest? pip install "offshoot-db[pytest] @ git+https://github.com/sricola/offshoot#subdirectory=sdk/python"

(from the repo — not yet on PyPI) registers offshoot_daemon

/offshoot_db

/offshoot_fork

fixtures automatically — seed once, fork a fresh isolated branch per test, TTL-backstopped cleanup, pytest-xdist

parallelism (one daemon per worker). Full tutorial: docs/eval-harness.md; condensed reference: sdk/python/README.md

.

sdk/typescript

is the same thin client, zero runtime dependencies. Also not yet published to npm — build and import it from a checkout of this repo:

offshoot -store ./.offshoot init
offshoot serve -socket /tmp/o.sock &
(cd sdk/typescript && npm install --no-audit --no-fund && npm run build)
js
import { connect } from "./sdk/typescript/dist/client.js";

const c = await connect("/tmp/o.sock");
await c.create("app");
const s = await c.open("app");     // sqlite3 s.path; write; commit
await s.flush("v1");               // durable in the store, writer never d
await c.fork("app", "main", "try", { ttl: "2h" });
await s.close();
await c.close();

Client

also exposes branches()

, dbs()

, export()

, and checkoutAt()

— the same surface as the Python client above.

Testing with vitest/jest/ node:test?

@offshoot-db/client/testkit

(startDaemon

/seedOnce

/forkPerTest

/dump

) is the framework-agnostic counterpart of the pytest fixtures above. See docs/eval-harness.md's TypeScript section and

sdk/typescript/README.md

.Both SDKs are exercised against a real daemon by make test-sdks

(needs python3

and node

/npm

on PATH — not part of the default make test

, which stays hermetic to the Go suite).

offshoot.langgraph.ThreadForks

is a checkpointer companion, not a BaseCheckpointSaver

: it maps each LangGraph thread to its own offshoot branch, so rewinding a thread to an earlier checkpoint and retrying also forks the database from that same point — the retry never inherits what the original attempt wrote after it. See examples/langgraph-rewind/, runnable with

python3 examples/langgraph-rewind/agent.py

— no server or bucket needed (it builds offshoot

and starts its own private daemon).LangGraph is the one framework with a real companion package; everyone else gets a short recipe instead of an adapter — see docs/recipes/: Claude Code's MCP config and hooks pattern (claude-agent-sdk.md), the OpenAI Agents SDK's SQLiteSession

pointed at an offshoot checkout path (openai-agents.md), and short honest notes on LlamaIndex and CrewAI (frameworks.md).

Rendered docs site: ** https://sricola.github.io/offshoot/docs/** — the same canonical markdown as the in-repo links below, with a getting-started track:

introduction·

installation·

quickstart·

core concepts.

Understand it

Architecture— the storage model, chains, fencing, copy-on-writeFAQ— why not Litestream / LiteFS / Turso / Dolt /cp

Stability contract— pre-1.0 promises, v1.0 criteriaHow offshoot is tested— torture numbers, CI gatesBenchmarks— measured, with method

Use it

Eval-harness tutorial— seed-once-fork-many for pytest/vitest/node:test

, install to CICLI reference— every command and flagCI recipes— seed-once/fork-per-attempt Actions workflowsFramework recipes— Claude Code hooks, OpenAI Agents SDK, LlamaIndex/CrewAIBranch diffsqldiff

between branches and checkpoints

Operate it

Operations— metrics, branch states, eventing, budgets, HTTP/auth threat model (single node)Grafana dashboard— ready to import, all 18 metric familiesKubernetes sidecar recipe

Track it

Implemented/deferred status— shipped-and-tested vs unverified, honestly labeledRoadmap·CHANGELOG

CONTRIBUTING.md— dev setup and the test tiers, includingmake ci-local

(mirrors CI's job matrix locally)SECURITY.md— how to report vulnerabilitiesCHANGELOG.md— release notes- License: Apache-2.0

fork it, trash it, promote the one that worked

── more in #developer-tools 4 stories · sorted by recency
── more on @offshoot 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/show-hn-offshoot-cop…] indexed:0 read:21min 2026-08-16 ·