This roadmap covers the Alfred monorepo and its packages. Alfred is a policy engine for async resilience: composable, observable, testable — and eventually operable (live-tunable by ID without redeploy).
"Need to adjust that bulkhead? No redeploy needed."
Alfred becomes a runtime-controlled resilience layer:
- Policies are pure + composable
- Config is live + addressable by ID
- Telemetry is first-class
- Testing is deterministic (no time-based flakiness)
- Core stays dependency-free. Heavy integrations live in satellites.
- Deterministic under TestClock. No "sleep in tests" nonsense.
- No global state. Control plane is an object you pass in.
- Validated updates only. Parse/validate before apply; reject bad writes.
- Audit first. Every config change attempt is recordable (even denied).
- Single-version ecosystem. All packages bump together.
- Live stays out of core. Control plane lives in
@git-stunts/alfred-live, not core.
@git-stunts/alfred— Core policies + composition + telemetry + TestClock.@git-stunts/alfred-live— Control plane primitives + live policy plans +alfredctlCLI.@git-stunts/alfred-transport-jsonl— Telemetry sink adapter (JSONL logger, planned).
- v0.5 — Correctness & Coherence (
@git-stunts/alfred) - v0.6 — Typed Knobs & Stable Semantics (
@git-stunts/alfred) - v0.7 — Rate Limiting (Throughput) Policy (
@git-stunts/alfred) - v0.8 — Control Plane Core (In-Memory) (
@git-stunts/alfred-live) - v0.9 — Live Policies by ID (No Redeploy) (
@git-stunts/alfred-live) - v0.10 — Control Plane Command Channel + Audit Ordering (
@git-stunts/alfred-live) - v1.0 — Production Contract Release (all packages)
The control plane is intentionally layered. Interfaces appear in this order:
- In-process API (v0.8):
ConfigRegistry+CommandRouterused directly in code. - Live policy plans (v0.9):
LivePolicyPlan+ControlPlane.registerLivePolicy, still in-process. - Command channel + CLI (v0.10): JSONL envelope +
alfredctlfor external control.
Telemetry transport packages (e.g. @git-stunts/alfred-transport-*) are a separate track and do not carry control plane commands.
Goal: eliminate credibility leaks (docs inconsistencies, missing imports), and make the "algebra" obvious and documented.
Package(s)
@git-stunts/alfred
User story As a developer evaluating Alfred, I want the first example to run without edits so I can trust the library.
Requirements
- Quick Start imports match usage (bulkhead included).
- Quote uses valid, copy-safe JS (double quotes inside code).
- Add a minimal "What you get" line: retry/circuit/bulkhead/timeout/hedge + TestClock + telemetry.
Acceptance criteria
- README Quick Start runs as-is in Node 20.
- No missing import in any snippet.
- Hedge is mentioned at least once as a feature (even if not fully documented yet).
Scope
- README edits only.
Out of scope
- New API features.
- Major README restructure (save that for 0.5+).
Test spec
- Golden: copy/paste snippets into examples/readme-smoke.test.js and execute.
- Known failures: none acceptable.
- Fuzz/stress: N/A.
Definition of done
- CI includes a "README smoke" test that runs at least the Quick Start snippet.
Package(s)
@git-stunts/alfred
User story As a user, I want to understand composition quickly so I can build real stacks without reading source.
Requirements
- Document equivalences:
- wrap ≈ sequential composition ("A wraps B")
- or ≈ fallback
- race/hedge ≈ concurrent first-success patterns
- Document precedence (or lack thereof) for fluent API vs functional compose.
Acceptance criteria
- README has an "Algebra" section with 3 examples:
- timeout + retry + bulkhead stack
- fast timeout fallback to slower stack
- hedge/race pattern
Scope
- README + small examples folder if needed
Out of scope
- Adding new operators or parser for expressions (like A + B | C text)
Test spec
- Golden: examples run in Node 20 and Deno/Bun if you've got CI matrix.
- Known failures: none.
- Fuzz/stress: N/A.
Definition of done
- Docs merged + examples pass CI.
Package(s)
@git-stunts/alfred
User story As a maintainer, I want deterministic timeout tests using TestClock so the test suite is fast and stable.
Requirements
- timeout(ms, fn, options) accepts options.clock (or options.timer) consistent with the rest of the library.
- Uses clock for scheduling and elapsed calculation (not Date.now()).
- Preserves current runtime behavior if no clock provided.
Acceptance criteria
- New tests prove timeout works without real delays.
- Existing timeout behavior remains unchanged in Node.
Scope
- timeout implementation + tests
- update testing exports if needed
Out of scope
- Deadline propagation across nested policies (that's later).
Test spec
- Golden:
- timeout triggers after virtual time advance
- timeout does not trigger if operation finishes before deadline
- Known failures:
- ensure AbortError / cancellation doesn't report as timeout
- Fuzz/stress:
- random operation durations under TestClock (100–500 iterations)
- ensure no leaked timers / pending promises
Definition of done
- Timeout tests run in <1s total, no sleeps.
- No flakiness across 20 CI runs.
Goal: normalize option resolution/snapshot timing so future "live edit" doesn't create chaos.
Package(s)
@git-stunts/alfred
User story As a user, I want predictable semantics when passing functions/handles for options (e.g. limit, retries).
Requirements
- Document and implement: which options resolve "per execute" vs "per attempt" vs "per admission".
- Standardize:
- Retry: resolve most options once per execute (except maybe shouldRetry)
- Bulkhead: resolve limit/queueLimit per admission
- Circuit breaker: resolve thresholds per event
- Hedge: resolve delay/maxHedges per execute
Acceptance criteria
- Behavior is explicit in docs.
- Tests assert resolution timing for each policy.
Scope
- Policy implementations + tests + docs
Out of scope
- Full control plane integration
Test spec
- Golden: "resolution timing" tests with counters (no real delays)
- Known failures: inconsistent resolution across policy constructors
- Fuzz/stress: randomized options functions; ensure no repeated unexpected calls
Definition of done
- A single doc section "Resolution timing" exists + tests cover it.
Package(s)
@git-stunts/alfred
User story As a user, I want to use hedged requests safely without accidentally DDOSing myself.
Requirements
- Docs include:
- "Only hedge idempotent operations"
- "Prefer hedge with bulkhead + circuit breaker"
- "Use AbortSignal to cancel losing hedges"
- Provide 1–2 recipes:
- hedgeRead (read-only)
- happyEyeballsFetch (two endpoints)
Acceptance criteria
- README includes one hedge example that composes with bulkhead + timeout
- Mention Promise.any requirement for older runtimes.
Scope
- Docs + examples
Out of scope
- Implementing automatic idempotency detection (lol)
Test spec
- Golden: hedge cancels losing branch; no unhandled rejections
- Known failures: losing branch continues running after winner resolves
- Fuzz/stress: 1000 races under TestClock/simulated clock
Definition of done
- Docs land + one "hedge example" test runs in CI.
Goal: add throughput control (token bucket / GCRA). Bulkhead limits concurrency; rate limit limits requests per time.
Package(s)
@git-stunts/alfred
User story As a user, I need to limit request rate (RPS) without external infrastructure.
Requirements
- Token bucket or GCRA implementation
- Options:
- rate (tokens/sec)
- burst (max tokens)
- optional clock (TestClock support)
- Failure mode: reject immediately with RateLimitExceededError (or optionally queue—default reject)
Acceptance criteria
- Deterministic tests for:
- steady-state throughput
- burst handling
- refill over time
- Works in Node/Bun/Deno (no Node-only APIs)
Scope
- New policy + error type + d.ts + tests
Out of scope
- Distributed rate limiting
- Adaptive/autotuning
Test spec
- Golden:
- allow N ops per second under TestClock
- burst allows immediate spikes then throttles
- Known failures:
- floating point drift (use integer math if possible)
- Fuzz/stress:
- random request schedules (10k events) under TestClock
- ensure no negative tokens / overflow
Definition of done
- New policy documented + covered + exports stable.
Goal: the minimum viable control plane, Nine Lives style: ReadConfig / WriteConfig against a registry.
Package(s)
@git-stunts/alfred-live
User story As an operator/dev, I want to change policy parameters at runtime in-process, safely.
Requirements
- Adaptive:
- get(): T
- set(next: T): void
- update(fn): void
- metadata: version, updatedAt
- ConfigRegistry:
- register(path, adaptive, { parse, format })
- keys(), read(path), write(path, valueString)
- paths are relative and slash-delimited (e.g.
bulkhead/api) - prefix semantics:
bulkheadmatchesbulkhead+bulkhead/*;bulkhead/*matches children only;bulkhead*uses wildcard matching - Validate before apply: parsing failure rejects, old value preserved.
Acceptance criteria
- Registry supports:
- list keys
- read current values
- write new values
- write rejects invalid value and does not mutate config
Scope
- In-memory only
Out of scope
- Persistence
- Networking
- Auth
Test spec
- Golden:
- write valid value updates version and updatedAt
- write invalid value returns structured error and preserves old
- Known failures:
- partial update leaving config in invalid state
- Fuzz/stress:
- 10k random writes including invalid; assert invariants hold
Definition of done
- Registry is stable, documented, and unit tested heavily.
Package(s)
@git-stunts/alfred-live
User story As a tool author, I want a stable command API that can be transported over any protocol.
Requirements
- Command types:
- read_config { path }
- write_config { path, value }
- list_config { prefix? }
- Result model:
- ok: true, data
- ok: false, error { code, message, details }
Acceptance criteria
- Router executes commands against registry and returns canonical results.
Scope
- Internal router API only
Out of scope
- Wire format
- Auth/audit (next milestones)
Test spec
- Golden: read/write/list flows
- Known failures: unknown key, invalid key path, invalid value
- Fuzz/stress: random paths/prefixes
Definition of done
- Commands are stable + used by at least one example script.
Goal: Policies become operable: "liveBulkhead('bulkhead.api')" etc.
Package(s)
@git-stunts/alfred-live (wraps @git-stunts/alfred policies)
User story As an operator, I want to tune a live system without redeploying, using stable IDs.
Requirements
- Introduce
LivePolicyPlanbuilders:LivePolicyPlan.retry(binding, defaults)LivePolicyPlan.bulkhead(binding, defaults)LivePolicyPlan.circuitBreaker(binding, defaults)LivePolicyPlan.timeout(binding, ms, options)LivePolicyPlan.static(policy)for core-only policies inside a live stack
- Bind plans with
ControlPlane.registerLivePolicy(plan, basePath)- Creates registry entries under
<basePath>/<binding>/<field> - Returns
{ policy, bindings, paths }in a Result envelope
- Creates registry entries under
- Resolution semantics:
- Retry/Timeout: per execute
- Bulkhead: per admission
- Circuit: per event
Acceptance criteria
- Demo: adjust bulkhead limit live and observe admission behavior change without restart.
Scope
- In-process control plane only
Out of scope
- Remote control protocols
- Auth/audit
Test spec
- Golden:
- update bulkhead limit from 10→1 blocks new admissions
- update retry retries from 3→6 changes future operations
- Known failures:
- changing retry mid-operation causes inconsistent attempt schedule (avoid by per-execute snapshot)
- Fuzz/stress:
- concurrent executions while config changes (1k iterations)
Definition of done
- Live policies are documented + tested + examples exist.
Package(s)
@git-stunts/alfred
User story As an operator, I want to reduce concurrency safely without killing in-flight operations.
Requirements
- Implement safe shrink:
- decreasing limit prevents new admissions until active <= limit
- never cancels running tasks
- Queue limit updates only affect new enqueues
Acceptance criteria
- A test proves:
- start 10 ops, shrink to 2: no cancellations, but new admissions wait/reject correctly.
Scope
- Bulkhead internals + tests
Out of scope
- Preemptive cancellation
- Fairness guarantees beyond "reasonable FIFO" if queue exists
Test spec
- Golden:
- grow behaves immediately
- shrink is soft
- Known failures:
- deadlocks under shrink pressure
- Fuzz/stress:
- random limit changes under load for 5k ops
Definition of done
- No deadlocks, no leaked queued items, no incorrect stats.
Goal: make the control plane operable outside the process: command channel + canonical envelope + audit-first ordering.
Package(s)
@git-stunts/alfred-live
User story As a CLI/tooling user, I want to send commands to Alfred over stdin/stdout safely and predictably.
Requirements
- Envelope:
- id, cmd, args, optional auth
- JSONL codec (for commands, not telemetry):
- decode per line
- encode per result
- Strict validation: reject unknown fields and malformed payloads
alfredctlCLI shipped from@git-stunts/alfred-live
Acceptance criteria
alfredctlcan:- list keys
- read config
- write config
Scope
- JSONL only (command channel)
Out of scope
- HTTP/gRPC (future satellites)
- Telemetry transport packages (separate track)
Test spec
- Golden:
- round-trip encode/decode
- command execution via JSONL harness
- Known failures:
- partial lines, invalid JSON, huge payload lines
- Fuzz/stress:
- randomized JSONL lines and junk input (1k–5k lines)
Definition of done
- Transport is stable and exercised by CI integration tests.
Package(s)
@git-stunts/alfred-live
User story As an operator, I need a complete audit trail of config change attempts (even denied or invalid).
Requirements
- Pipeline order:
- Audit (attempt)
- Auth (optional)
- Validate + Execute
- Audit (result)
- Auth provider interface (pluggable):
- start with allowAll / opaqueToken provider
Acceptance criteria
- Every command produces 2 audit events (attempt + result) OR one combined event with status.
- Invalid commands are audited too.
Scope
- Local audit sink(s): console + in-memory
- auth as hooks
Out of scope
- Real security claims (that's v1+ with threat model + external review)
Test spec
- Golden:
- audit sees denied write
- audit sees invalid JSON
- audit sees successful write
- Known failures:
- audit not firing on exceptions
- Fuzz/stress:
- throw errors in handlers; ensure audit still records "failed"
Definition of done
- Audit is impossible to bypass accidentally (tests enforce it).
Goal: stop moving cheese. API stability, deterministic tests, docs complete, and "operable" story is real.
Telemetry transports are not the same thing as the control plane command channel. Packages with transport in the name are telemetry sink adapters that plug into Alfred’s telemetry system.
Planned examples:
@git-stunts/alfred-transport-jsonl— JSONL telemetry sink@git-stunts/alfred-transport-datadog— Datadog telemetry sink@git-stunts/alfred-transport-otlp— OTLP/OpenTelemetry telemetry sink
Package(s)
All packages (@git-stunts/alfred, @git-stunts/alfred-live, @git-stunts/alfred-transport-*)
User story As an adopter, I want confidence that upgrades won't silently break my system.
Requirements
- Declare public API surface:
- exports and subpath exports
- error types and event types
- control plane command schema
- Deprecation policy in README/CONTRIBUTING:
- how long deprecations live
- what constitutes breaking change
Acceptance criteria
- A "Public API" section exists and matches actual exports.
Scope
- Docs + minor code guards
Out of scope
- Big refactors
Test spec
- Golden: export snapshot test (assert export keys stable)
- Known failures: none
- Fuzz/stress: N/A
Definition of done
- Export snapshot is enforced by CI.
Package(s)
@git-stunts/alfred
User story As a maintainer, I want tests that are fast and don't fail randomly in CI.
Requirements
- All time-based policies support TestClock (retry/backoff/jitter/timeout/rateLimit/hedge delays).
- No setTimeout-based tests except maybe one smoke test.
Acceptance criteria
- Full suite runs in <10s
- 50 consecutive CI runs show no flake
Scope
- tests + small refactors
Out of scope
- Benchmarking
Test spec
- Golden: deterministic virtual time assertions
- Known failures: none acceptable
- Fuzz/stress: stress suite that runs 5k randomized scenarios under TestClock
Definition of done
- "No sleeps" rule documented and enforced (lint/grep in CI).
Package(s)
@git-stunts/alfred, @git-stunts/alfred-live, @git-stunts/alfred-transport-jsonl
User story As a user, I want an end-to-end example proving live editing works.
Requirements
- Provide examples/control-plane/:
- starts a service with live policies
- changes bulkhead/retry via JSONL control
- prints telemetry events
Acceptance criteria
- One command changes live behavior demonstrably (throughput/latency/rejections).
Scope
- examples + docs
Out of scope
- hosted service, cloud infra
Test spec
- Golden: run example in CI and assert output contains "config version changed" and behavior changed
- Known failures: non-determinism (use scripted sequence)
- Fuzz/stress: N/A
Definition of done
- Example is runnable in <2 minutes by a new user.