lifeloop-cli 0.2.0

Provider-neutral lifecycle abstraction and normalizer for AI harnesses
Documentation
# Lifeloop Release Gates

## Status

Strategic orientation note

## Date

2026-05-08

## Purpose

The extraction backlog is closed. CCD-side mechanics that needed to be lifted
into a neutral lifecycle substrate now live in this crate; the host lifecycle
surface is cut over to the `lifeloop` CLI; and the eight-issue product track
that follows extraction is open. This doc names the v0.2 hardening milestone
and the v1 freeze gates in operational terms so that future work attaches to
a release boundary instead of drifting back into local hardening tasks.

It also records which work blocks the CCD slimdown
(dusk-network/ccd#723) and which work can proceed in parallel, so the
sequencing decisions in issue #27 stay legible after the issue closes.

## Surface taxonomy

Lifeloop ships four distinguishable surfaces. Each one has a different
stability story; conflating them is how product boundaries collapse.

### Library API

The Rust crate's public types and traits: lifecycle event vocabulary, the
callback request and response envelopes, payload envelope (`placement`,
`requirement`, `outcome`), adapter manifest, lifecycle receipts, the 13-class
`FailureClass`, the 5-class `RetryClass`, and the failure-to-retry default
mapping. The `lifeloop.v0.2` slice of the lifecycle contract is implemented
and pinned by `tests/wire_contract.rs` and `tests/spec_alignment.rs`.

What v1 freezes: the wire shape of all of the above and the failure-to-retry
mapping. Additions ride a schema bump; removals require a tombstone with a
removal criterion.

### CLI / operator UX

The `lifeloop` binary subcommands: `events`, `envelope validate request|response`,
`envelope echo`, `manifest`, `asset preview` (read-only render, per the #23
boundary decision in `docs/decisions/asset-apply-boundary.md`), and
`event invoke`. The CLI is an inspection and operator surface, not a separate
contract: every subcommand is a thin shim over the library.

What v1 freezes: subcommand names, argument shapes, and exit-code semantics
for already-shipped commands. New subcommands are additive and do not
require a schema bump unless they expose new wire data.

### Fixture corpus

Committed conformance fixtures used by tests and downstream consumers:
adapter manifests for Codex and Claude, the rendered protocol fixtures, and
sanitized live-evidence fixtures captured from real Codex 0.122/0.129 (#31)
and Claude (#30) runs. The fixture corpus is the contract a non-CCD client
compares against when it asks "does Lifeloop describe this harness the way I
see it?"

What v1 freezes: the existence and shape of the v1-conformance adapter
fixtures, plus the operator procedure for regenerating live evidence. The
exact byte-for-byte contents may evolve under the schema-bump discipline.

### Client profile contract

How a non-CCD client attaches to Lifeloop without importing CCD: the
callback request and response schemas, the payload delivery plane on
`event invoke` and subprocess callbacks, and the integration asset profile
abstraction that renders host assets for something other than CCD. Today
the host asset renderer carries CCD
compatibility command prefixes directly; #26 isolates those behind a named
compat profile and proves a second profile renders.

What v1 freezes: the callback envelope schemas, the subprocess transport
contract for payload delivery (#22), and the profile abstraction shape
(#26). The CCD-flavored profile becomes one client profile, not the
shape of the renderer.

## v0.2 hardening (current milestone)

v0.2 hardens what already exists without freezing the shape. Each bullet ties
to a tracking issue.

- Payload opacity in protocol renderers (#21, landed).
  `render_additional_context` no longer parses payload bodies as JSON or
  merges keys. Each eligible payload carries through a Lifeloop transport
  envelope `{"payloads":[…]}` with `body` passed through verbatim;
  overlapping JSON keys across payloads remain distinguishable, and
  `body_ref` stays a reference. Pinned by `tests/protocol.rs` opacity
  tests.
- First-class payload delivery on event invoke and subprocess callbacks
  (#22, landed). `DispatchEnvelope` is the new transport-boundary wire
  shape carrying both the `CallbackRequest` and the opaque
  `PayloadEnvelope` bodies a dispatch is delivering with. `event invoke`
  reads it from stdin and threads payloads through negotiation and the
  subprocess invoker; subprocess clients reach payload bodies through the
  documented stdio contract. `payload_receipts` records the delivered
  placement.
- Lifecycle asset and source-file apply boundary decision (#23, landed).
  The decision is recorded in `docs/decisions/asset-apply-boundary.md`:
  Lifeloop does not own filesystem writes for lifecycle integration assets.
  The misleading `lifeloop asset apply` CLI surface is tombstoned
  (`docs/tombstones/asset-apply-cli.md`) and rejected with a redirect to
  `asset preview`; `host_assets` remains a pure renderer. The stricter
  source-file ownership decision in
  `docs/decisions/source-files-are-user-owned.md` retracts the managed-section
  renderer entirely because pure replacement-body rendering still points
  callers at user-owned instruction files.
- Docs/status refresh and kernel-purity gate (#24, landed). README,
  lifecycle-contract implementation status, RLM development-contract
  note, and the lifeloop.v0 tombstone agree with the code that landed.
  `tests/kernel_purity.rs` is wired into `cargo test` and `make verify`,
  scanning every `.rs` file under `src/` for client-owned product
  vocabulary outside a documented allowlist of compat zones.
- Profile abstraction scaffolding (#26) lands in v0.2 *only* if it stays a
  pure render refactor; otherwise it slides into v1 work because it carries
  the second-client-class evidence.

v0.2 closes when payload opacity, payload delivery, the host-asset boundary,
the source-file ownership decision, and docs parity gates are all green and
the kernel-purity gate is wired in. Those gates are landed; only #26 (profile
abstraction) remains for v0.2 hardening if it stays a pure render refactor.

## v1 freeze gates

v1 freezes the four surfaces above. Six gates govern that freeze. Each gate
has a short name, an operational definition, and the issues that close it.

1. **Adapter evidence** (#25, split into #30 and #31). Built-in adapter
   manifests for Codex and Claude are backed by captured live runs covering
   session start, frame opening, frame end, context pressure where available,
   and receipt emission. Manifest claims that disagree with observation are
   either fixed in code, corrected in the manifest, or recorded as documented
   pre-v1 degradations. A documented operator procedure recaptures the
   evidence.

2. **Two client classes** (#28, with #22 and #26 as prerequisites). At
   least two clients consume real Lifeloop event-invoke surfaces with
   payload delivery: the existing CCD client and one non-CCD client. The
   current product pilot is the Fixity client in `crates/fixity-pilot/`,
   a Reforge-inspired repeated-signal consumer that runs over
   `lifeloop event invoke`, returns valid `CallbackResponse` values,
   observes payload refs or bodies through the chosen delivery plane, and
   produces conformance fixtures usable by this gate.

3. **Payload delivery** (#22, with #21 as prerequisite). `event invoke`
   carries payload envelopes end-to-end through negotiation and subprocess
   callbacks. Negotiation receives the actual `PayloadEnvelope` values, not
   an empty slice. Subprocess clients can access payload bodies or
   `body_ref` without Lifeloop parsing payload contents. Receipt synthesis
   includes correct `payload_receipts` for delivered payloads.

4. **Asset application and profile story** (#23 and #26). Lifeloop has a
   clear, documented boundary on filesystem writes for lifecycle integration
   assets, and a stricter boundary that user-owned instruction source files
   are read/suggest-only. The profile abstraction supports at least one
   non-CCD host-asset profile rendering plausibly without editing CCD
   constants. CCD command strings live behind a named compat profile, not
   in the renderer's defaults.

5. **Docs parity** (#24). README, lifecycle contract spec, the RLM
   development-contract note, and the tombstones agree with the code. The
   kernel-purity gate is wired and CI-enforced. No stale issue-number
   TODOs reference already-landed work.

6. **CCD cutover readiness** (#28 plus dusk-network/ccd#723 on the CCD
   side). Lifeloop owns enough lifecycle reach that CCD can slim down to a
   callback consumer. The replacement contract is documented and the Fixity
   pilot confirms a non-CCD client works against real Lifeloop surfaces, not
   only fixtures.

v1 freezes when all six gates are green. Subsequent work is governed by the
schema-bump discipline (`docs/playbooks/schema-bump.md`).

## Dependency map (execution graph)

The issue bodies record a partial order. The DAG below collects it; the
recommended execution order matches issue #27.

```text
                          #27 (this doc)
                                |
              +-----------------+-----------------+
              |                 |                 |
           #21 -----+        #24 (docs/        #23 (asset
        (opacity)   |         purity gate)      boundary)
              |     |              |                 |
              v     v              v                 v
            #22 (payload delivery) <-- (parallel) -->
              |
       +------+------+
       |             |
       v             v
      #25         #26 (profiles)
   (live evidence)   |
       |             v
       |           #28 (non-CCD pilot)
       |             |
       +------+------+
              v
      dusk-network/ccd#723 (CCD slimdown)
```

Recommended execution order (from issue #27):

1. #21 payload opacity and #27 release gates in parallel.
2. #22 payload delivery after #21.
3. #24 docs/purity gate early, in parallel with #22 and #23.
4. #23 host-asset apply boundary and source-file ownership boundary after
   the #27 framing lands.
5. #26 client integration profiles after the #23 boundary is clear.
6. #25 live Codex and Claude evidence after #21 and #22, preferably after
   #23.
7. #28 non-CCD product pilot after #22 and #26.
8. dusk-network/ccd#723 CCD slimdown after Lifeloop release gates say the
   replacement is ready.

Work that blocks the CCD slimdown directly: #21, #22, #25, and #28. The
slimdown also depends on #23, #24, and #26 transitively, but the four
explicit blockers are the ones whose acceptance criteria name CCD slimdown.

Work that can proceed in parallel:

- #21 runs in parallel with #27 (this doc); both are P0 and they have no
  shared files.
- #22 runs in parallel with #24 once #21 lands; they touch different
  module boundaries.
- #23 runs in parallel with #21, #22, and #24 once the boundary decision
  is documented.
- #25 can start in read-only exploratory mode at any point after #21 and
  #22 land, even before #23 fully closes; only its v1 evidence claim is
  gated on the full prerequisites.

## CCD slimdown reference

The CCD slimdown (dusk-network/ccd#723) is gated by Lifeloop's v1 freeze
gates. Before that work opens, gates 1 through 6 must be green: adapter
evidence captured, two client classes proven, payload delivery end-to-end,
asset application and profile story documented, docs parity enforced, and
the cutover readiness confirmed by a non-CCD client running against real
Lifeloop surfaces.

No work in this repo modifies the CCD repository. The slimdown is a
downstream consequence of Lifeloop reaching v1, not a parallel track.

## Issue references

- Lifeloop #21 — Preserve payload opacity in protocol renderers
  https://code.nanto.org/nanto/lifeloop/-/work_items/21
- Lifeloop #22 — First-class payload delivery on event invoke and
  subprocess callbacks
  https://code.nanto.org/nanto/lifeloop/-/work_items/22
- Lifeloop #23 — Resolve lifecycle asset and source-file apply boundary
  https://code.nanto.org/nanto/lifeloop/-/work_items/23
- Lifeloop #24 — Refresh docs/status and add a kernel-purity boundary gate
  https://code.nanto.org/nanto/lifeloop/-/work_items/24
- Lifeloop #25 — Capture live Codex and Claude adapter conformance evidence
  https://code.nanto.org/nanto/lifeloop/-/work_items/25
- Lifeloop #26 — Generalize lifecycle integration asset profiles beyond
  CCD compatibility
  https://code.nanto.org/nanto/lifeloop/-/work_items/26
- Lifeloop #27 — Shape Lifeloop v0.2/v1 product surface and release gates
  https://code.nanto.org/nanto/lifeloop/-/work_items/27
- Lifeloop #28 — Graduate a non-CCD client from shape proof to product
  pilot
  https://code.nanto.org/nanto/lifeloop/-/work_items/28
- CCD #723 — CCD slimdown (downstream)
  https://code.nanto.org/dusk-network/ccd/-/work_items/723