lifeloop-cli 0.2.0

Provider-neutral lifecycle abstraction and normalizer for AI harnesses
Documentation

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, and receipt.gap_detected);
  • callback request and response envelopes (CallbackRequest / CallbackResponse) plus a DispatchEnvelope transport-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 / outcome enums, 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_receipts carrying payload kind and optional digest provenance;
  • 13-class FailureClass, 5-class RetryClass, 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 through src/host_assets.rs with 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, consuming DispatchEnvelope payloads through real lifeloop event invoke dispatch and keeping Reforge-inspired repeated-signal policy outside Lifeloop core.

The lifeloop CLI is intentionally thin — every subcommand is a shim over the library:

lifeloop events                         # print the event vocabulary
lifeloop envelope validate request      # validate JSON read from stdin
lifeloop envelope validate response
lifeloop envelope echo request
lifeloop event invoke                   # validate -> negotiate -> callback -> receipt
                                        # accepts a DispatchEnvelope on stdin
lifeloop manifest list                  # registry-backed adapter listing
lifeloop manifest show <id>
lifeloop manifest inspect <id>@<ver>
lifeloop asset preview --host <h> --mode <m>   # render host assets
lifeloop telemetry snapshot --host <id>
lifeloop receipt emit                   # synthesize a receipt from a wire envelope
lifeloop receipt show
lifeloop conformance run                # walk tests/conformance/ fixtures
lifeloop version

Run lifeloop --help for argument detail, exit-code semantics, and the spec pointer.

Docs

Verification

make verify

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.