# iac

`iac` is a deterministic, serial runbook CLI for infrastructure and operations automation.

Current release: `0.1.0a1` (alpha).

## Core Commands

- `iac init book <name>`
- `iac list books|steps|modules --output table|json|yaml`
- `iac get book <ref> --output table|json|yaml`
- `iac get step <book@step> --output table|json|yaml`
- `iac get module <module> --output table|json|yaml`
- `iac check module <module> --output table|json|yaml`
- `iac check modules --output table|json|yaml`
- `iac run fn <module@function> --output table|json|yaml`
- `iac check book <ref> --output table|json|yaml`
- `iac deps install <ref> [--apply] --output table|json|yaml`
- `iac run cmd <command>`
- `iac run book <ref>`
- `iac run step <book@step>`

Run execution supports:

- one-off command execution with stdin helpers: `--stdin-file`, `--stdin-text`, `--stdin-json`, `--stdin-env`
- command argv mode: `--no-shell` with repeatable `--arg`
- stdout/stderr file management: `--stdout-file`, `--stderr-file`, `--file-mode`
- step selection controls: `--from-step`, `--to-step`, `--only-step`, `--skip-step`, `--tag`
- timeout override: `--timeout`
- retry overrides: `--retries`, `--retry-delay`

## Runbook Schema (`kind: pyplines.runbook.v1`)

Top-level keys:

- `kind` (must be `pyplines.runbook.v1`)
- `name`
- `title`
- `description`
- `tags`
- `inputs`
- `packages`
- `hooks`
- `steps`
- `outputs`

Runbooks use CEL expressions for dynamic references in:

- `steps[].when`
- `steps[].vars.*`
- `steps[].outputs.*`
- `outputs.*.when`
- `outputs.*.value`

Run with typed input overrides:

```bash
iac run book runbook_spec_draft --input month=2026-03 --output yaml
iac run step runbook_spec_draft@export_csv --input month=2026-03
```

### Inputs

`inputs` defines typed run parameters. Use `iac run book ... --input key=value` to override defaults.

```yaml
inputs:
  month:
    type: string
    regex: '^\d{4}-(0[1-9]|1[0-2])$'
  accounts:
    type: array
    default: ["prod"]
    minItems: 1
  include_pdf:
    type: boolean
    default: false
```

Supported types: `string`, `boolean`, `array`, `integer`, `number`.

### Packages

`packages` declares runbook dependencies:

```yaml
packages:
  os:
    - name: bash
      min_version: ">=3.2.0"
      check: "bash --version"
  py:
    - name: requests
      min_version: ">=2.32.5"
```

Install hints are derived automatically:

- `os` -> `dnf install -y <name>`
- `py` -> `python3 -m pip install <name>[constraint]`

### Steps

Each step must define exactly one executor:

- `sh` (safe argv-style command list)
- `fn` (`module@function`)

Both executors support:

- `vars` (CEL-evaluated bindings)
- `when` (CEL condition)
- `outputs` (CEL projection for `steps.<name>.outputs.*`)
- `timeout`, `retries`, `retry_delay`, `on_fail`

Example:

```yaml
steps:
  - name: export_csv
    sh: ["python3", "-m", "reporting.export", "--month", "$MONTH"]
    vars:
      MONTH: inputs.month
    outputs:
      csv_url: json(result.stdout).csv_url
```

### Failure Policy

Step `on_fail` and hook `on_fail` are both standardized to:

- `halt`: stop execution immediately
- `warn`: continue, emit warning
- `pass`: continue quietly (non-blocking failure)

### Step Execution Controls

Each step can define:

- `timeout` (seconds, `> 0`)
- `retries` (integer, `>= 0`)
- `retry_delay` (seconds, `>= 0`)

`iac run` reports include attempt counts (`ATTEMPTS`) and prints a failure summary with a rerun hint when a hard failure occurs.

## Packaging

`pyproject.toml` is configured for explicit package discovery with:

```toml
[tool.setuptools.packages.find]
include = ["iac*"]
```

This avoids accidental inclusion of `books/` as a Python package.

## PyPI Publishing

This project is configured for release publishing with GitHub Actions in:

- `.github/workflows/publish-pypi.yml`

Release flow:

1. Create/publish a GitHub release.
2. Workflow runs tests, builds sdist/wheel, validates with `twine check`.
3. On release events, package is published to PyPI via trusted publishing.

Prerequisite:

- Configure PyPI trusted publisher for this GitHub repository and workflow in the PyPI project settings.

## Known Limitations (Alpha)

- Coverage gate is enforced at 100% for the alpha-tested scope defined in `pyproject.toml` coverage omit rules.
- `iac run cmd` JSON/YAML output is structured, but command stdout/stderr still stream unless `--quiet` is set.
- Dependency install commands are advisory; `iac deps install --apply` executes derived package install hints.
