Lifeloop
Lifeloop is a provider-neutral lifecycle abstraction and normalizer for AI harnesses.
It exists because AI harness lifecycle is a reusable substrate. Claude Code, Codex, Gemini, Hermes, OpenClaw, OpenCode, and future harnesses expose session, prompt, context-pressure, turn, closeout, and recovery moments through different hooks and telemetry conventions. Lifeloop normalizes those lifecycle moments so clients can attach through a stable contract instead of importing CCD or rebuilding harness adapters.
Role
harnesses
Claude / Codex / Gemini / Hermes / OpenClaw / OpenCode
|
v
Lifeloop
lifecycle events, receipts, capabilities, payload delivery
|
+------------+-------------+-------------+
| | | |
CCD RLM Reforge Fixity
continuity recursion memory family constraints
Boundary
Lifeloop owns lifecycle normalization:
- harness identity and adapter manifests;
- lifecycle event vocabulary;
- hook timing normalization;
- capability negotiation;
- lifecycle receipts;
- payload placement and delivery metadata;
- lifecycle-relevant telemetry;
- failure classes and retry posture.
Lifeloop does not own continuity, memory, recursive inference policy, model selection, prompt semantics above placement metadata, tool abstraction, skills, or a universal IDE.
Why Rust
Lifeloop starts as an extraction from CCD, and CCD is Rust. Keeping Lifeloop in Rust minimizes translation risk during extraction, preserves behavior around the existing lifecycle normalizer, and gives the public event/capability/receipt contracts strong local types. The callback protocol remains language-neutral, so Go, Python, shell, or research clients can consume Lifeloop through JSON envelopes without importing Rust.
Current Shape
The crate implements the lifeloop.v0.2 slice of the contract:
- lifecycle event vocabulary (14 events, including the
frame.*family,context.compacted, andreceipt.gap_detected); - callback request and response envelopes (
CallbackRequest/CallbackResponse) plus aDispatchEnvelopetransport-boundary shape carrying request + payload envelopes through one stdio document (issue #22); - adapter manifest registry with built-in manifests for Codex and
Claude as v1 conformance targets and pre-conformance manifests for
Hermes, OpenClaw, Gemini, and OpenCode (issue #6); shared
conformance fixture suite under
tests/conformance/(issue #10); - payload envelope with
placement/requirement/outcomeenums, opaque-by-construction renderer (bodies are transported verbatim so overlapping JSON keys across payloads stay distinguishable, per issue #21); - lifecycle receipt with required-but-nullable correlation fields and
per-payload
payload_receiptscarrying payload kind and optional digest provenance; - 13-class
FailureClass, 5-classRetryClass, and the spec's failure-to-retry default mapping; - 5-state
SupportState(native,synthesized,manual,partial,unavailable) for adapter capability claims; - optional renewal/reset capability claims that distinguish native, wrapper-mediated, manual, and unavailable reset paths from observation-only versus payload-delivering continuation support;
- lifecycle router stack: pre-dispatch validation + adapter resolution
→ capability/placement negotiation → callback invocation
(in-process or subprocess over JSON stdio via
DispatchEnvelope) → receipt synthesis with idempotency (issues #7 / #13 / #14 / #15); - subprocess callback transport with deadline-bounded round trip (issues #8 / #22);
- host integration assets (
.claude/settings.json,.codex/config.toml, etc.) rendered throughsrc/host_assets.rswith a CCD-flavored compat profile (issues #4 / #9; profile abstraction is in flight as issue #26); - thread-sync publisher (
crates/thread-sync-publisher/) as the first non-CCD lifecycle client, consuming Lifeloop receipts over the same callback contract (issue #11); - Fixity pilot (
crates/fixity-pilot/) as the #28 non-CCD product pilot, consumingDispatchEnvelopepayloads through reallifeloop event invokedispatch and keeping Reforge-inspired repeated-signal policy outside Lifeloop core.
The lifeloop CLI is intentionally thin — every subcommand is a
shim over the library:
# accepts a DispatchEnvelope on stdin
Run lifeloop --help for argument detail, exit-code semantics, and
the spec pointer.
Docs
- Product thesis
- Release gates and v0.2/v1 roadmap
- Lifecycle contract spec (normative)
- Harness concept boundary note
- Renewal reset capability boundary
- Source-file ownership decision
- RLM development-contract declaration
- Fixity pilot client
- Wire-contract review playbook
- Schema-bump playbook
Verification
Focused mutation sweeps are available through make mutants-all, which writes
slice evidence under mutants.out/all. The mutation gate excludes only the
documented behavior-equivalent survivors in Makefile: subprocess deadline
polling cadence and host-asset no-op rendering branches. Treat any new missed
mutant as a test gap unless it has an explicit equivalence rationale.