Skip to content

Define Module → Driver → Profile → Pack execution contract (v1)

Status

Proposed — Establish a stable contract for how HybridOps modules are executed and verified, independent of internal tooling changes.

1. Context

HybridOps.Core is the product runtime for governed, repeatable platform runs. It requires:

  • A stable module contract that does not change when internal tooling evolves.
  • A clear separation between intent (module) and execution policy (profile) and tool plans (packs).
  • Deterministic runtime layout, evidence capture, and redaction behaviour.
  • A packaging model that remains functional without a Git repository context (tarball-safe distribution).

This ADR formalises the execution contract as the basis for modules shipped to users and for internal platform evolution.

2. Decision

HybridOps.Core adopts a four-part execution model:

1) Module — intent contract (what) 2) Driver — execution engine (how) 3) Profile — policy and defaults (how, consistently) 4) Pack — tool plan bundle (what to run, tool-specific data)

The module spec MUST select:

  • execution.driver — driver reference (e.g., iac/terragrunt)
  • execution.profile — profile reference (e.g., default@v1.0)
  • execution.pack_ref.id — pack identifier, resolved by the driver (e.g., gcp/org/00-project-factory@v1.0)

3. Contract definitions

3.1 Module

A module is declarative data describing intent and verification.

A module MUST define:

  • inputs.defaults — default inputs (operator may override)
  • execution.driver
  • execution.profile
  • execution.pack_ref.id

A module SHOULD define:

  • requirements.credentials (credential pack identifiers, not values)
  • outputs.publish (what to expose from normalized outputs)
  • probes (verification steps or probe identifiers, where applicable)
  • constraints (semantic constraints on inputs and environment)

A module MUST NOT embed tool implementation details, including but not limited to:

  • Terraform/Terragrunt module sources
  • backend/state/workspace wiring
  • CLI flags and tool invocation parameters
  • secrets or secret material
  • environment naming assumptions (dev/prod/staging)
  • repo-specific path assumptions

3.2 Driver

A driver is the execution engine that:

  • prepares an isolated work directory for a run
  • resolves and materialises the selected pack
  • interprets the selected profile
  • invokes tools (e.g., Terragrunt)
  • captures evidence (redacted) and returns a deterministic result payload

Drivers MUST be tarball-safe and MUST NOT depend on .git, get_repo_root(), or working directory conventions.

Drivers MUST write evidence under the resolved runtime root and MUST NOT write secrets into evidence artifacts.

3.3 Profile

A profile is a versioned policy bundle interpreted by a driver.

Profiles MUST be owned by the driver domain (e.g., terragrunt driver profiles live with the terragrunt driver).

Profiles SHOULD govern:

  • runner model (local vs remote)
  • backend/state selection and workspace naming
  • toolchain policy (pinned/allowed versions)
  • templates/hooks that are driver-owned (generated into the run workdir)
  • logging and redaction defaults
  • retry/timeouts, safety flags

Profiles MUST NOT redefine module intent. Profiles are permitted to provide defaults only where consistent policy is required.

3.4 Pack

A pack is a tool-specific plan bundle executed by a driver (e.g., a Terragrunt stack tree).

Packs MUST be immutable inputs to a run (drivers copy packs into an isolated workdir).

Packs MUST be tarball-safe: packs MUST NOT depend on repo-specific functions or paths. Any runtime-injected configuration MUST be provided via environment variables or generated files owned by the driver/profile.

Packs MUST NOT own backend/workspace naming rules. This belongs to driver/profile policy.

4. Runtime invariants

4.1 Runtime root precedence

All commands that write runtime artifacts MUST resolve the runtime root using:

1) --root <path> 2) $HYOPS_RUNTIME_ROOT 3) ~/.hybridops

Commands MUST NOT infer a repository root for runtime outputs.

4.2 Evidence paths

Evidence MUST be deterministic and structured:

  • Module runs: <root>/logs/module/<module_id>/<run_id>/

Evidence must be redacted by default for subprocess stdout/stderr.

4.3 Execution workdir (pack materialisation)

For each module run, the driver MUST create an isolated work directory under the runtime root:

  • Workdir: <root>/work/<module_id>/<run_id>/
  • Stack working copy: <root>/work/<module_id>/<run_id>/stack/

The driver MUST materialise the selected pack by copying the pack stack directory into the stack working copy:

  • Pack source: packs/<execution.driver>/<execution.pack_ref.id>/stack/
  • Run destination: <root>/work/<module_id>/<run_id>/stack/

The driver MAY render profile-owned templates and generated inputs into the same stack working copy (for example inputs.auto.tfvars.json and driver/profile-owned *.hcl overlays).

5. Input override contract

Operator-provided inputs are resolved in this precedence order:

1) inputs.defaults in module spec 2) --inputs <file>.yml (if provided) 3) Environment overrides (HYOPS_INPUTS_JSON, HYOPS_INPUT_*) when enabled by the runtime

The runtime MUST document the override mechanisms and MUST treat them as stable behaviour for users once enabled.

6. Consequences

6.1 Positive

  • Stable module contract with clear boundaries.
  • Drivers and packs can evolve independently without breaking the public spec.
  • Tarball-safe packaging is achievable without repository assumptions.
  • Evidence and output normalisation becomes consistent across tools.

6.2 Negative / risks

  • Requires strict discipline to keep modules tool-agnostic.
  • Requires CI checks to prevent “policy creep” into packs and “intent creep” into drivers.

7. Alternatives considered

  • Tool-first structure (driver/packs define everything) — rejected due to unstable user contract.
  • Repo-layout-driven execution (implicit roots) — rejected due to tarball incompatibility and non-deterministic runtime outputs.
  • Embedding backend/state in packs — rejected; backend policy is a profile concern.

8. References