v0.4.0
Substrate, observability, planning, approval, memory, and connector primitives. The largest single release since 0.1.0; lays down building blocks the next two quarters of roadmap items will compose.
Added
Runner and observability
lib/agent_runner.pydecomposed from a single monolith into a 10-filelib/agent_runner/package: preflight, lock, spend, engines, gh, slack, event-log, commit-trailer, transcripts, dedup. Public import surface preserved. 50 new unit tests undertests/unit/agent_runner/cover the split modules; full suite grew from 689 to 749.alfred metrics(bin/alfred-metrics.py): per-agent rollup of firings, cost, turns, tool-use, and Codex tokens.--since 7d,--codename,--by-day,--json. Reads$ALFRED_STATE_DIRonly.alfred logs(bin/alfred-logs.py): tail and filter per-firing stream-JSON transcripts.--last N,--firing-id ID,--show-tool-calls,--json. Seedocs/CLI.md.lib/transcripts.pyandlib/metrics.py:TranscriptReaderandMetricsAggregatorprotocols + filesystem-backed implementations, used by the two new CLIs and exposed for downstream code.
State machine and multi-repo
lib/labels.py:LabelClientprotocol +GhCliLabelClientimplementation. Atomic transitions across the issue-claim state machine (agent:queuedtoagent:implementtoagent:in-flighttoagent:pr-opentoagent:done), with race resolution and conflict detection.lib/cross_repo_pr.py: cross-repo PR coordinator. Opens stacked PRs across multiple repos with a shared spec id, links them via PR-body cross-references, marks the spec done only when all PRs merge.lib/multi_worktree.py: managed pool of git worktrees under$ALFRED_HOME/wt. Per-firing reservation, completion cleanup, crash recovery.bin/alfred-label-state: operator-facing CLI for the issue-claim state machine.claim,release,dedup-check,status-issue,repo pause/resume/list,sweep-claims. Pre-push hook recipe indocs/STATE_MACHINE.md.
Planning and execution
- Damian spec-bundle planner (
lib/damian_planner.py+bin/damian.py): walks a spec directory, identifies multi-repo features, filesagent:bundle:<slug>siblings across the affected repos. All-or-nothing per bundle. Caps at 3 bundles per firing. Single-repo work is left to drake. - Batman now executes approved plans (
lib/batman.pyfrom 505 to 1383 lines;bin/batman.pyfrom 261 to 472 lines). Once a Damian-style plan is approved (Slack reaction, label transition, orBATMAN_AUTO_EXECUTE=1), Batman drives the fan-out implementation across the listed repos. Previously Batman halted at plan-only. TheBATMAN_AUTO_EXECUTEenv contract:0= always ask,approval-gate= read approval signals,1= always execute. Seedocs/BATMAN.md.
Approvals
lib/slack_approval.py+docs/SLACK_APPROVAL.md: reaction-based approval gate. An agent posts a proposal, the operator reacts with the configured emoji, the agent proceeds.ApprovalGateis atyping.Protocolso the same call site can swap Slack for any other channel. New env vars:ALFRED_OPERATOR_SLACK_USER_ID,ALFRED_APPROVAL_EMOJI(defaults to:white_check_mark:).
Quality gates
lib/slop_detector.py+bin/slop-detector.py+bin/curator.py: PR-time linter for AI-authored prose patterns. 21 default rules covering banned vocabulary (seamless, unlock, leverage, transform), em-dashes, hedged numbers, marketing fluff. Rules are JSON-configurable; seeexamples/slop-rules.jsonanddocs/SLOP_DETECTOR.md.
Memory
lib/fleet_brain/: v1 SQLite-backed memory store. Per-codename and per-reporecall/reflect, atomic writes, ULID ids via the standard library, zero external dependencies. 948 lines of package code, 33 tests. Architecture and the v2 path (PGLite + Apache AGE + pgvector) indocs/FLEET_BRAIN.md. CLIs:bin/alfred-brain.py,bin/fleet-ingest.py.lib/memory/:MemoryProviderProtocol +FleetBrainProvider,ChainedMemoryProvider, andNullMemoryProviderimplementations. Optional read-onlygbrainsubprocess shim for operators with a personal knowledge base. Chain order is env-driven:ALFRED_MEMORY_PROVIDERS=fleet,gbrain; default is fleet-brain only;nulldisables memory. Seedocs/MEMORY_PROVIDERS.md.
Connectors
lib/connectors/:ConnectorProtocol + reference Linear and Sentry implementations. Pull-mode adapters from non-GitHub sources into the engineering fleet'sagent:implementqueue. Linear uses a stdlib GraphQL POST; Sentry uses a stdlib REST GET; both rely on env-only credentials (LINEAR_API_KEY,SENTRY_AUTH_TOKEN). One bad connector cannot break the sync. Seedocs/CONNECTORS.md,bin/connector-sync.py,examples/connectors.yaml.
Dashboards and proof
alfred servev1 (bin/alfred-serve.py+lib/server/): localhost-only, read-only FastAPI dashboard over$ALFRED_HOME/state. Three views: fleet status with HTMX auto-refresh, recent firings, single-firing detail. Reader injected astyping.Protocol. New[serve]optional dependency group forfastapi,uvicorn,jinja2. Seedocs/SERVE.md.bin/alfred-shipped-public.py: self-host emitter that reads$ALFRED_HOME/state, applies a public field allowlist + partner-name redaction table, and writes aweekly.jsonoperators can publish on their own site. Seedocs/SHIPPED_EMITTER.md.
Infrastructure for unattended operation
lib/claude_proxy/andbin/claude-proxy.py: localhost unix-socket daemon that brokersclaude -pinvocations on behalf of launchd-spawned agent processes. Solves the macOS Keychain ACL issue that returns 401 on everyclaudecall from a non-Aqua launchd session. NDJSON wire protocol withinvoke,health, andproberequests; stdlib-only; opt-in viaALFRED_CLAUDE_PROXY_SOCKETwith transparent fallback to direct subprocess. Seedocs/CLAUDE_PROXY.mdanddocs/MACOS_KEYCHAIN.md.examples/launchd/luminik.claude-proxy.plist.example: sample launchd unit withLimitLoadToSessionType=Aquaand inline install / verify recipe. Operators must edit the placeholder paths before bootstrapping. (Brand-neutral filename rename tracked for the v0.4.1 docs PR.)lib/agent_runner.process.claude_invoke_streamingroutes through the proxy when the env var is set, falls back to direct subprocess otherwise.
Fleet diagnostic + cleanup hardening
- Pause-marker honoring under launchd via
$ALFRED_HOME/state/_paused/<codename>(paused agents stay paused across firings, not just at boot). - Fail-streak / pause-marker sync at every self-pause site (lucius, drake, batman, rasalghul, nightwing).
ALFRED_CLEANUP_EXTRA_PATHSenv var: sweep operator-managed worktree pools outside$ALFRED_HOME/worktrees.- Status-cache TTL stops stale reads when
alfred statusis invoked in quick succession. ALFRED_PREFLIGHT_SLACK_MIN_MINUTESthrottles repeated preflight Slack alerts.fleet-doctordistinct alert for concurrent engine-auth failures (separates "claude not logged in" from generic firing errors).
Documentation
- Three new concept pages: state and memory, engine routing, operating the fleet. Mirrored across
docs/(GitHub-rendered) andsite/src/content/docs/(Starlight). Linked into the sidebar under Concepts and Getting Started. - ROADMAP rewritten into a four-tier model: Shipped, In flight, Next, Horizon. Mirrored in
site/src/content/docs/about/roadmap.md.
Changed
- Core dependencies:
slack-sdk>=3.27andboto3>=1.34moved from optional[slack]and[aws]extras into the basedependencieslist. Slack and AWS are integral enough that the optional-extras split was adding install friction for new operators with no payoff. pyproject.tomladds the new[serve]optional-dependency group (FastAPI + uvicorn + Jinja2)..gitignoreadds.claude/andscreenshots/so per-agent worktrees, launch configs, and local verification screenshots stay out of the public repo..gitallowedadded sogit secretspre-commit hooks understand thatbin/scrub-check.shand CI workflows reference secret-pattern regexes by design.
Fixed
lib/labels.py: addedPLAN_PENDING_APPROVALconstant (agent:plan-pending-approval) plus a backward-compatLABEL_AGENT_PLAN_PENDING_APPROVALalias for code that imports the long-form name. Required bylib/slack_approval.pyandlib/batman.py.tests/unit/__init__.pyandtests/unit/agent_runner/__init__.py: promote the agent-runner unit test directory to a package so pytest can disambiguatetests/test_transcripts.pyfromtests/unit/agent_runner/test_transcripts.py.docs/BATMAN.md: replaced operator-specific channel literal with#your-fleet-channelplaceholder per the private-to-public boundary policy.
Verification
- 689 tests pass on Python 3.11.
bash bin/scrub-check.shreturnsscrub-check: clean.cd site && npm run buildbuilds 45 pages with 0 errors and 0 content warnings.