Skip to main content
Docs navigation

Pack reference

An action pack is a versioned, content-addressed directory of YAML action declarations. The runner loads the pack, advertises every action to the control plane, and refuses anything outside this catalog. This is the contract between your ops team and the LLM.

Pack and action schemas are v1 compatibility surfaces. Read Compatibility and deprecation before you depend on a schema version.

Layout#

my-pack/
  pack.yaml                # pack-level metadata
  actions/
    nodetool_status.yaml   # one declared action per file
    nodetool_repair.yaml
  scripts/                 # optional — packaged scripts for kind: script actions
    repair_report.sh

pack.yaml#

yaml
schema_version: 1
id: cassandra
name: Cassandra operations
version: 0.4.0
description: Cassandra triage + scoped repair
vendor: acme
homepage: https://github.com/acme/cassandra-pack
allow_symlinks: false

requires:
  os: [linux]
  binaries: [nodetool]

setup:
  summary: >
    How the pack reaches its target and authenticates.
  env:
    - name: CQLSH_PASSWORD
      description: Password for cqlsh-backed actions.
  verify: cassandra.nodetool_status

actions:
  - actions/nodetool_status.yaml
  - actions/nodetool_repair.yaml

allow_symlinks defaults to false. The loader rejects symlinked action YAMLs and scripts unless you opt in.

requires lists what the pack's host needs — OS and binaries. They are advertised as host readiness, and a missing binary fails at run time, not at load. The setup block powers emisar pack info, pack verify, and the install probe: a summary, the env names the tool reads, and one low-risk verify action.

When an action needs protected host access, add a host_access group. It names the exact actions, the resource they need, complete persistent grant and verification commands, and the authority the grant gives the runner identity. Emisar displays these commands; it never runs them.

yaml
setup:
  host_access:
    - actions: [my.journal_tail]
      requirement: Read the system journal.
      recipes:
        - name: systemd Linux — default emisar service user
          commands:
            - sudo usermod -aG systemd-journal emisar
            - sudo systemctl restart emisar
          verify:
            - sudo -u emisar journalctl -n 1 --no-pager
          impact: The emisar service identity can read the complete system journal.

An action YAML#

yaml
schema_version: 1
id: linux.grep_log
title: Grep a log file
kind: exec
risk: low

description: >
  Greps an extended regex against a log file under /var/log.
  Read-only. Returns matching lines with line numbers.
side_effects:
  - Reads a log file under /var/log.

args:
  - name: file
    type: path
    required: true
    validation:
      allowed_prefixes: ["/var/log/"]
  - name: pattern
    type: string
    required: true
    validation:
      pattern: "^.{1,512}$"

execution:
  command:
    binary: grep        # bare name — resolved via PATH on the host
    argv: ["-E", "-n", "{{ args.pattern }}", "{{ args.file }}"]
  timeout: 30s
  user: syslog        # optional — run as this lower-privilege local user

output:
  parser: text
  max_stdout_bytes: 524288
  max_stderr_bytes: 8192

# Optional.
examples:
  - title: Search syslog for sshd auth failures
    args:
      file: /var/log/syslog
      pattern: "sshd.*Failed password"
  - title: Tail nginx access for 5xx
    args:
      file: /var/log/nginx/access.log
      pattern: ' 5\d\d '

Field reference#

  • kindexec (run a binary with an explicit argv) or script (run a script packaged in the pack, its contents SHA-256-verified at load). There is no shell kind. Both run as argv arrays through execve. An exec action can invoke /bin/sh -c for a fixed, pack-authored program. Open-ended strings and paths must reach that program through environment variables or whole positional arguments. Only finite choices and two-sided bounded numbers can be substituted into its text. The critical, default-denied shell pack is the break-glass exception where the operator supplies the program itself.
  • risklow | medium | high | critical. The policy engine assigns a default decision per tier, and a higher tier must be at least as restrictive as a lower one. Risk is declared in the pack — the caller cannot override it.
  • args — every argument is declared. Types: string, integer, number, boolean, duration, path, string_array, integer_array. Validation tightens the type. Enum, regex pattern, allowed_prefixes / denied_prefixes for paths, max_items for arrays, min/max for numbers, max_duration for durations.
  • side_effects — the plain-language list of what the action touches. The LLM reads it verbatim when it decides what to call, so an honest list is a safety control, not documentation polish.
  • execution.user — Linux-only. Drops the child process to that local user's uid and primary gid before exec. A runner under a privileged service account still runs the action as the declared, lower-privilege user.
  • output.parsertext (default), json, or json (parser_required: true) to force the run to fail if stdout is not valid JSON.
  • output.max_*_bytes — stdout/stderr ceilings. The control plane can lower these per call, and it cannot raise them past the declared maximum.
  • redact — per-action rules layered on top of 20 built-in patterns (GitHub, GitLab, Slack tokens, JWTs, authentication, and secret assignments). Redaction runs before output leaves the host, so the control plane receives the redacted stream. The local journal records each rule's hit count, and the terminal result sends rule names, types, and counts to the control plane.
  • examples — optional list of {title, args} entries. Each one renders as a clickable hint on the dispatch form, so operators and LLMs see a realistic invocation before they type. Examples do not validate anything — they are documentation, not policy.

Pack trust#

Every pack is content-addressed: a SHA-256 hash over all its files. The control plane pins the exact hash the account trusts, and the runner recomputes it and refuses to load files that do not match. A hash carried by the published catalog is trusted automatically — any other, like a pack you wrote or a hand-edited tree, waits for an administrator before dispatch. This protects content integrity, not publisher identity.

Drift detection#

Once a pack is installed on at least one runner, the console's Packs page groups every observed (pack_id, version, hash) in your account. Two runners on the same pack version with different hashes mean somebody hand-edited a pack on a host — the page flags it as drift, and re-deploying from the canonical source clears it.

Browse the public registry — each pack's page lists its declared actions and a hash-pinned install command. Examples include linux-core, postgres, docker, kubernetes, nginx, redis, AWS, and Vault. To publish your own, read Author your own pack.

Last reviewed August 26, 2026