Skip to main content

Module host_assets

Module host_assets 

Source
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§

LifecycleProfile
Per-client-profile data driving lifecycle integration asset rendering and merge.
MergedFile
Outcome of merging managed entries into an existing settings/hooks file. existing is the prior file content (None if the file did not exist); rendered is the merged content the caller should write.
RenderedAsset
One file Lifeloop renders for a host adapter. relative_path is relative to the repository root the caller is rendering into. mode is a Unix permission bitmask when present; callers on non-Unix targets may ignore it, but cross-checking is still meaningful for status reporting.

Enums§

AssetStatus
Status of an installed asset relative to the rendered template.
FileAction
Action taken for one asset during apply.
HostAdapter
Host adapters Lifeloop ships asset rendering and merge support for.
HostAssetError
Errors returned by merge or render entry points. Callers convert as needed; the variants are pinned so downstream tests can match.
IntegrationMode
Integration modes supported by host asset rendering.

Constants§

CCD_COMPAT_CLAUDE_COMMAND_PREFIX
Command prefix Lifeloop renders into .claude/settings.json for CCD-managed hook entries. Equal to CCD_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.json for CCD-managed hook entries. Equal to CCD_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. Drifted dominates Missing dominates Present; an empty input is NotApplicable.
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.json hook command for hook_arg.
ccd_compat_codex_command
Render a CCD-compat .codex/hooks.json hook command for hook_arg.
claude_settings_status
Status of .claude/settings.json against the rendered template for the default CCD_COMPAT_PROFILE. existing is the file body (None means missing). The merge is re-run and compared byte-for-byte to detect drift.
claude_settings_status_with_profile
Status of .claude/settings.json against the rendered template for profile.
codex_config_status
Status of .codex/config.toml. Returns Present only when the [features].hooks = true flag 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_doc already contains the full CCD-managed Codex lifecycle hook set (default CCD_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_doc already contains the full set of profile’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.json against the rendered template for the default CCD_COMPAT_PROFILE.
codex_hooks_status_with_profile
Status of .codex/hooks.json against the rendered template for profile.
combine_actions
Combine current with next so a multi-file apply reports the strongest action seen. Updated dominates Installed dominates AlreadyPresent.
merge_claude_settings
Additive merge of CCD-managed lifecycle hooks into a Claude settings.json value, using the default CCD_COMPAT_PROFILE.
merge_claude_settings_text
Merge an existing serialized .claude/settings.json body into the CCD-managed shape (default CCD_COMPAT_PROFILE). See merge_claude_settings_text_with_profile for the contract.
merge_claude_settings_text_with_profile
Merge an existing serialized .claude/settings.json body into profile’s managed shape. Returns:
merge_claude_settings_with_profile
Additive merge of profile’s managed lifecycle hooks into a Claude settings.json value.
merge_codex_config_text
Merge [features].hooks = true into an existing Codex config.toml, preserving every other key.
merge_codex_hooks
Additive merge of CCD-managed lifecycle hooks into a Codex hooks.json value (default CCD_COMPAT_PROFILE). See merge_codex_hooks_with_profile for the algorithm.
merge_codex_hooks_text
Merge an existing serialized .codex/hooks.json body using the default CCD_COMPAT_PROFILE. See merge_codex_hooks_text_with_profile for the contract.
merge_codex_hooks_text_with_profile
Merge an existing serialized .codex/hooks.json body using profile. Returns Ok(None) when the existing body is invalid JSON or has an incompatible top-level shape; _force is reserved for symmetry with merge_claude_settings_text_with_profile and 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 Codex hooks.json value. See merge_claude_settings_with_profile for the algorithm; the only differences are the managed event table and the per-entry timeout/statusMessage fields Codex carries.
render_applied_assets
Assets to apply into the host’s runtime directories (.claude/, .codex/, .hermes/, .openclaw/) using the default CCD_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_assets required 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. See render_applied_assets_with_profile for 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 host supports the requested install mode. Gates apply so a caller can refuse before mutating files.