Skip to content

Runtime root and packaging

Purpose: Define the HybridOps runtime root contract and how code must behave when executed from a tarball release (no Git metadata).

See also: - Evidence and redaction

This standard ensures that: - hyops operations are self-contained and tarball-safe - runtime artefacts are written to a single, explicit root - evidence, readiness, and state paths are stable and predictable

Runtime root contract

Root selection precedence

All runtime-writing commands MUST resolve the runtime root using this precedence:

  1. --root <path> (explicit operator intent)
  2. $HYOPS_RUNTIME_ROOT (environment override)
  3. --env <name> or $HYOPS_ENV (environment namespace)
  4. ~/.hybridops (default)

Norm: Commands MUST NOT infer a “repo root” for runtime outputs.

Norm: --root and --env are mutually exclusive.

Environment namespaces

When --env <name> (or $HYOPS_ENV) is set, the runtime root MUST be:

  • ~/.hybridops/envs/<name>/

<name> MUST be a short, filesystem-safe identifier (no path separators, no traversal).

Runtime layout

Commands MUST create the runtime layout if missing. Minimum directories:

  • <root>/config/
  • <root>/credentials/
  • <root>/vault/
  • <root>/meta/
  • <root>/logs/
  • <root>/state/
  • <root>/work/

Norm: <root>/work/ is a transient execution area (workdirs), not an evidence store.

Drivers MAY create additional runtime directories when needed, for example:

  • <root>/tmp/ (temporary space; preferred over system /tmp for large IaC toolchains)
  • <root>/cache/ (plugin/cache storage)

State snapshots (module outputs)

HybridOps persists a normalised module state snapshot after successful module runs.

Location:

  • <root>/state/modules/<module_id>/latest.json

This file is used for dependency wiring between modules and MUST be treated as:

  • non-secret
  • safe to persist locally
  • overwrite-on-success (latest.json is updated each successful run)

Evidence and readiness locations

Evidence paths

Evidence MUST be written under the runtime root, using stable paths:

  • Init: <root>/logs/init/<target>/<run_id>/
  • Module: <root>/logs/module/<module_id>/<run_id>/
  • Driver: <root>/logs/driver/<driver_id>/<run_id>/

If an external evidence root is supported (--out-dir), it MUST be treated as an override root and the structure MUST remain stable:

  • Init (override): <out_dir>/init/<target>/<run_id>/
  • Module (override): <out_dir>/module/<module_id>/<run_id>/
  • Driver (override): <out_dir>/driver/<driver_id>/<run_id>/

Readiness markers

Readiness markers MUST be written under:

  • <root>/meta/<target>.ready.json

Vault bundle

Bootstrap-only secrets MAY be cached locally in an encrypted vault bundle:

  • <root>/vault/bootstrap.vault.env (Ansible Vault encrypted env-format file)

The vault password MUST be sourced out-of-band (for example via a password command) and MUST NOT be committed to Git.

Runtime stamp

Every init/module/driver command SHOULD attempt to write a best-effort runtime stamp:

  • <root>/meta/runtime.json

If written, the stamp MUST be non-secret, MUST be safe to persist, and MUST NOT block execution if stamping fails.

Minimum fields:

  • timestamp_utc
  • pid
  • root
  • command (e.g. init)
  • target / module_id / driver_id
  • run_id
  • evidence_dir
  • extra (non-secret, optional)

Packaging and “release root”

Definition

A “release root” is the directory containing shipped assets when installed from a tarball or copied directory (no .git), including:

  • packaged packs/
  • packaged tools/ (where applicable)
  • driver-owned templates/profiles shipped with the runtime

Norms (Bash)

Scripts that need access to packaged assets MUST resolve paths relative to the script location, not Git.

Allowed pattern:

  • SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
  • RELEASE_ROOT="$(cd -- "${SCRIPT_DIR}/../.." && pwd)"

Disallowed pattern:

  • git rev-parse --show-toplevel (tarball has no .git)

Norms (Python)

Python code that needs access to packaged assets MUST resolve paths relative to the installed package location (via __file__), not Git and not the current working directory.

Allowed pattern:

  • Path(__file__).resolve() and parent traversal to the installed “release root”
  • explicit environment overrides (e.g. HYOPS_PACKS_ROOT) for relocation

Disallowed pattern:

  • get_repo_root() / Git introspection
  • assuming cwd is a repo root

Requirements files

When a setup script accepts a --requirements <path> argument:

  • absolute paths MUST be used verbatim
  • relative paths MUST be resolved relative to RELEASE_ROOT

Non-goals

  • Defining retention or archival policy for <root>/logs/ or <root>/work/
  • Replacing Terraform/Terragrunt state design or CI execution models