Expand description
Host integration asset rendering and merge behavior.
Lifeloop owns the file shape, merge safety, and status reporting for
lifecycle integration assets installed into harness host directories
(.claude/, .codex/, .hermes/, .openclaw/). The host apply
and host inspect compatibility commands route here.
§Boundary (issue #4)
This module owns:
- rendering source/applied asset content as in-memory data,
- additive-merge logic that preserves user-owned entries,
- asset status reporting (
Present/Missing/Drifted/InvalidMode/NotApplicable), - supported-mode rules for each adapter.
This module does not own:
- the hook protocol command strings themselves (those are issue #3 — the strings appear here only as opaque compatibility labels that the merge logic must recognize so it can scrub stale entries);
- the full adapter manifest registry (issue #6);
- lifecycle routing (issue #7);
- telemetry parsing (issue #5);
- filesystem IO. Callers handle reads, writes, mode bits, and atomic
replace. This module is pure: it operates on
serde_json::Value, strings, and byte slices.
§CCD compatibility
The command-prefix constants and legacy recognizer patterns
(CCD_COMPAT_*) are CCD compatibility labels — Lifeloop’s first
client wires its own binary into harness hooks via these prefixes.
They are not core Lifeloop semantics: a future non-CCD client
gets its own profile in the same shape. Keeping them in one place
makes the compat surface auditable.
§Lifecycle integration profiles (issue #26)
LifecycleProfile generalizes the CCD-shaped command-prefix /
managed-event surface into a per-client-profile struct. The free
functions exported from this module keep their CCD-compat default
behavior (they delegate to CCD_COMPAT_PROFILE); paired
*_with_profile variants accept any profile so a non-CCD client
(e.g. LIFELOOP_DIRECT_PROFILE, the post-slimdown shape where
the harness invokes the lifeloop CLI directly without CCD as
broker) can render and merge its own lifecycle hook assets without
editing core merge logic. This is the bridge contemplated by
docs/release-gates.md for the CCD slimdown
(dusk-network/ccd#723) — the slimdown lands by switching active
installs from CCD_COMPAT_PROFILE to a non-CCD profile, not by
rewriting the renderer.
Structs§
- Lifecycle
Profile - Per-client-profile data driving lifecycle integration asset rendering and merge.
- Merged
File - Outcome of merging managed entries into an existing settings/hooks
file.
existingis the prior file content (Noneif the file did not exist);renderedis the merged content the caller should write. - Rendered
Asset - One file Lifeloop renders for a host adapter.
relative_pathis relative to the repository root the caller is rendering into.modeis a Unix permission bitmask when present; callers on non-Unix targets may ignore it, but cross-checking is still meaningful for status reporting.
Enums§
- Asset
Status - Status of an installed asset relative to the rendered template.
- File
Action - Action taken for one asset during apply.
- Host
Adapter - Host adapters Lifeloop ships asset rendering and merge support for.
- Host
Asset Error - Errors returned by merge or render entry points. Callers convert as needed; the variants are pinned so downstream tests can match.
- Integration
Mode - Integration modes supported by host asset rendering.
Constants§
- CCD_
COMPAT_ CLAUDE_ COMMAND_ PREFIX - Command prefix Lifeloop renders into
.claude/settings.jsonfor CCD-managed hook entries. Equal toCCD_COMPAT_PROFILE.claude_command_prefix. - CCD_
COMPAT_ CLAUDE_ LEGACY_ PYTHON_ HOOK - Substring that identifies the pre-v1 Python bridge entries in
.claude/settings.json. Merge logic scrubs these even when the modern command prefix has changed. - CCD_
COMPAT_ CODEX_ COMMAND_ PREFIX - Command prefix Lifeloop renders into
.codex/hooks.jsonfor CCD-managed hook entries. Equal toCCD_COMPAT_PROFILE.codex_command_prefix. - CCD_
COMPAT_ PROFILE - CCD compatibility profile: the harness invokes
${CCD_BIN:-ccd} host-hook ...and CCD acts as the broker that calls back into Lifeloop. This is Lifeloop’s first client and its current production install shape. - CLAUDE_
SOURCE_ SETTINGS - CLAUDE_
TARGET_ SETTINGS - CODEX_
SOURCE_ CONFIG - CODEX_
SOURCE_ HOOKS - CODEX_
SOURCE_ LAUNCHER - CODEX_
SOURCE_ README - CODEX_
TARGET_ CONFIG - CODEX_
TARGET_ HOOKS - CODEX_
TARGET_ LAUNCHER - HERMES_
SOURCE_ ADAPTER - HERMES_
TARGET_ ADAPTER - LIFELOOP_
DIRECT_ PROFILE - Lifeloop-direct callback profile: the harness invokes
${LIFELOOP_BIN:-lifeloop} host-hook ...directly, with no CCD in the loop. This is the post-slimdown shape contemplated by dusk-network/ccd#723 — landing it as a built-in profile lets a non-CCD pilot exercise the full host-asset rendering path before the slimdown work commits to it. - OPENCLAW_
SOURCE_ ADAPTER - OPENCLAW_
TARGET_ ADAPTER
Functions§
- aggregate_
status - Combine per-asset statuses into a single bundle status.
DrifteddominatesMissingdominatesPresent; an empty input isNotApplicable. - asset_
status - Compute status for one rendered asset by dispatching to the appropriate per-path comparison. Falls back to byte-equal comparison for any path that doesn’t match a merge-aware target.
- byte_
equal_ asset_ status - Status of an installed asset that uses byte-equal comparison (every asset except the merge-aware Claude settings, Codex hooks, and Codex config files).
- ccd_
compat_ claude_ command - Render a CCD-compat
.claude/settings.jsonhook command forhook_arg. - ccd_
compat_ codex_ command - Render a CCD-compat
.codex/hooks.jsonhook command forhook_arg. - claude_
settings_ status - Status of
.claude/settings.jsonagainst the rendered template for the defaultCCD_COMPAT_PROFILE.existingis the file body (Nonemeans missing). The merge is re-run and compared byte-for-byte to detect drift. - claude_
settings_ status_ with_ profile - Status of
.claude/settings.jsonagainst the rendered template forprofile. - codex_
config_ status - Status of
.codex/config.toml. ReturnsPresentonly when the[features].hooks = trueflag is set; the rest of the file is ignored because users are free to add their own config. - codex_
hooks_ contain_ managed_ lifecycle - True when
hooks_docalready contains the full CCD-managed Codex lifecycle hook set (defaultCCD_COMPAT_PROFILE). Used by status reporting to detect “Codex hooks installed externally” vs. “needs apply”. - codex_
hooks_ contain_ managed_ lifecycle_ with_ profile - True when
hooks_docalready contains the full set ofprofile’s managed Codex lifecycle hooks. - codex_
hooks_ feature_ is_ enabled - True when the parsed TOML enables
[features].hooks. - codex_
hooks_ status - Status of
.codex/hooks.jsonagainst the rendered template for the defaultCCD_COMPAT_PROFILE. - codex_
hooks_ status_ with_ profile - Status of
.codex/hooks.jsonagainst the rendered template forprofile. - combine_
actions - Combine
currentwithnextso a multi-file apply reports the strongest action seen.UpdateddominatesInstalleddominatesAlreadyPresent. - merge_
claude_ settings - Additive merge of CCD-managed lifecycle hooks into a Claude
settings.jsonvalue, using the defaultCCD_COMPAT_PROFILE. - merge_
claude_ settings_ text - Merge an existing serialized
.claude/settings.jsonbody into the CCD-managed shape (defaultCCD_COMPAT_PROFILE). Seemerge_claude_settings_text_with_profilefor the contract. - merge_
claude_ settings_ text_ with_ profile - Merge an existing serialized
.claude/settings.jsonbody intoprofile’s managed shape. Returns: - merge_
claude_ settings_ with_ profile - Additive merge of
profile’s managed lifecycle hooks into a Claudesettings.jsonvalue. - merge_
codex_ config_ text - Merge
[features].hooks = trueinto an existing Codexconfig.toml, preserving every other key. - merge_
codex_ hooks - Additive merge of CCD-managed lifecycle hooks into a Codex
hooks.jsonvalue (defaultCCD_COMPAT_PROFILE). Seemerge_codex_hooks_with_profilefor the algorithm. - merge_
codex_ hooks_ text - Merge an existing serialized
.codex/hooks.jsonbody using the defaultCCD_COMPAT_PROFILE. Seemerge_codex_hooks_text_with_profilefor the contract. - merge_
codex_ hooks_ text_ with_ profile - Merge an existing serialized
.codex/hooks.jsonbody usingprofile. ReturnsOk(None)when the existing body is invalid JSON or has an incompatible top-level shape;_forceis reserved for symmetry withmerge_claude_settings_text_with_profileand currently behaves the same regardless of value (the previous CCD implementation never branched on it). - merge_
codex_ hooks_ with_ profile - Additive merge of
profile’s managed lifecycle hooks into a Codexhooks.jsonvalue. Seemerge_claude_settings_with_profilefor the algorithm; the only differences are the managed event table and the per-entrytimeout/statusMessagefields Codex carries. - render_
applied_ assets - Assets to apply into the host’s runtime directories (
.claude/,.codex/,.hermes/,.openclaw/) using the defaultCCD_COMPAT_PROFILE. Empty when the (host, mode) pair has no installable files (e.g. Codex manual-skill mode is scaffold-only). - render_
applied_ assets_ with_ profile - Assets to apply into the host’s runtime directories rendered with
profile’s command prefixes and managed event tables. - render_
required_ source_ assets - Subset of
render_source_assetsrequired for the given mode. Modes that pin only a few of a host’s source files (Codex manual-skill, launcher-wrapper) trim the list so absent files don’t trigger spurious “missing scaffold” errors. - render_
source_ assets - Full set of source-tree assets for a host using the default
CCD_COMPAT_PROFILE. These are the templates that land under.ccd-hosts/<host>/. - render_
source_ assets_ with_ profile - Full set of source-tree assets for a host rendered with
profile’s command prefixes and managed event tables. Seerender_applied_assets_with_profilefor the per-profile vs. per-host scope split. - supported_
modes - Modes the adapter accepts, in declaration order, for diagnostic messaging. Order is informational.
- supports_
mode - Whether
hostsupports the requested install mode. Gatesapplyso a caller can refuse before mutating files.