Releases: HackStrix/herd
Adding process security using cgroups and namespaces
What's Changed
- Linux sandbox with cgroup support [ignoring sandbox in MacOS] by @HackStrix in #5
- namespace isolation and new integration tests for CI by @HackStrix in #6
- Feature/observer and polish by @HackStrix in #8
- feat: extract SessionRegistry interface and technical debt cleanup by @HackStrix in #9
Full Changelog: v0.2.0...v0.3.1
v0.2.0
Release Notes:
- Adding support for websockets with passive tracking and minimal overhead
- Allow tracking multiplexing connection to the same worker session
- Worker Reuse is now a configurable option.
What's Changed
- fix(ttl): correctly track active connections for sweeper by @HackStrix in #3
- ci: add GitHub Actions workflow for tests and linting by @HackStrix in #4
Full Changelog: v0.1.4...v0.2.0
v0.1.4
What's Changed
- updating module api, fixing naming convention, and removing race cond… by @HackStrix in #2
New Contributors
- @HackStrix made their first contribution in #2
Full Changelog: v0.1.2...v0.1.4
v0.1.2: The Session-Affine Process Pool
Release Notes: v0.1.2
Release Date: March 07, 2026
This release focuses on critical concurrency bug fixes, API improvements for worker health checks, and comprehensively expanding documentation and examples.
🐛 Bug Fixes
- Pool Scaling Race Condition: Fixed a critical bug in
Pool.maybeScaleUp()where highly concurrent Acquire calls could circumvent themaxworker limit, causing the pool to spawn excessive workers and crash when attempting to release them back into a full channel. We introduced apendingAddsconcurrency counter to strictly bound scaling.
✨ New Features & API Improvements
- ProcessFactory Enhancements: Added flexible configuration options for
ProcessFactory:WithEnv(kv string): Inject custom environment variables (supports{{.Port}}templating).WithHealthPath(path string): Customize the HTTP path polled for liveness (defaults to"/health").WithStartTimeout(duration): Configure the maximum time allowed for the process to successfully start and report healthy.
- Robust Health Polling: Migrated health check polling from a static 30-retry limit to a clean, context-aware timeout mechanism.
📚 Documentation & Examples
- Comprehensive README: Added a complete README.md covering Herd's core invariants, architecture, and feature set.
- Ollama Multi-Agent Gateway: Introduced a fully fleshed-out example in
examples/ollamademonstrating how to use Herd as a session-affine LLM proxy.- The README was heavily updated to showcase this runnable code, along with
curlusage queries. - Added a concurrency stress-test suite (
TestConcurrentChat) for the Ollama integration.
- The README was heavily updated to showcase this runnable code, along with
⚙️ Chores
- Go Version Compatibility: Updated go.mod files to ensure backward compatibility with Go
1.21/1.22.
v0.1.0: The Session-Affine Process Pool
v0.1.0: The Session-Affine Process Pool
The Pain
Running stateful binaries — Ollama, headless Chromium, Python REPLs — behind a shared gateway usually means one of two terrible options: build complex container orchestration to isolate users, or share a single process and leak state across sessions. Neither is acceptable.
The Fix
Herd gives you a strict 1:1 session-to-worker mapping, automatic crash recovery, and a built-in reverse proxy — in 10 lines of Go.
factory := herd.NewProcessFactory("./my-binary", "--port", "{{.Port}}")
pool, _ := herd.New(factory,
herd.WithAutoScale(2, 10),
herd.WithTTL(5 * time.Minute),
herd.WithCrashHandler(func(sid string) { log.Printf("session %s lost", sid) }),
)
http.ListenAndServe(":8080", proxy.NewReverseProxy(pool, func(r *http.Request) string {
return r.Header.Get("X-Session-ID")
}))Every request with X-Session-ID: abc123 always routes to the same OS process — no external coordination, no sticky sessions, no Redis. When a process crashes, only that one session is affected; the pool spawns a replacement automatically.
What's in the Box
WorkerFactory[C] |
Spawn any OS binary with OS-allocated ports and /health polling |
Pool[C].Acquire |
Singleflight-safe session affinity with zero race conditions |
Session.Release |
Explicit lifetime management — workers are never leaked |
WithAutoScale(min, max) |
Elastic pool sizing; blocks Acquire at ceiling |
WithTTL(d) |
Idle session eviction — reclaim workers from abandoned sessions |
WithCrashHandler(fn) |
Hook into crash recovery — clean up DB state, alert users |
NewReverseProxy |
Full HTTP gateway in one call; session acquire + proxy + release |
The NewReverseProxy 5-liner
pool, _ := herd.New(herd.NewProcessFactory("./ollama", "serve", "--port", "{{.Port}}"))
http.ListenAndServe(":8080", proxy.NewReverseProxy(pool, func(r *http.Request) string {
return r.Header.Get("X-Session-ID") // route by any header, cookie, or path param
}))NewReverseProxy returns a standard http.Handler. Wire it into any existing net/http multiplexer — no framework lock-in.
Architecture
See docs/ARCHITECTURE.md for the Mermaid request-lifecycle diagrams, component breakdown, and full design rationale.
Installation
go get github.com/hackstrix/herd@v0.1.0Requires Go 1.21+.
Herd is intentionally small. The surface area is three types —
WorkerFactory,Pool, andReverseProxy— and one rule: a session always talks to the same process. That's it.