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 the OS and binaries the pack's host needs. The runner advertises them 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. It holds a summary, the env names the tool reads, and an optional 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-pack.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: medium

description: >
  Search a log file under /var/log with an extended regular expression.
  Return matching lines with line numbers. Raw application messages can contain
  personal or sensitive data that pattern redaction cannot fully detect.
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", "-e", "{{ 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: Search nginx access logs for 5xx
    args:
      file: /var/log/nginx/access.log
      pattern: ' 5[0-9][0-9] '

Field reference#

  • kind: exec (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 call /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 numbers with both a minimum and a maximum can be substituted into its text. The critical, default-denied shell pack is the break-glass exception where the operator supplies the program itself.
  • risk: low | 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, and 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 word for word when it decides what to call, so an honest list is a safety control.
  • 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.parser: text (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, but 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 appears as a clickable hint on the dispatch form, so operators and LLMs see a realistic call before they type. Examples are documentation only and do not validate anything.

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 hash, such as one from a pack you wrote or a hand-edited tree, waits for an administrator before dispatch. The hash protects content integrity. It does not verify the publisher's 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 original source clears it.

Browse the public registry to see each pack's declared actions and hash-pinned install command. Published packs include linux-core, postgres, docker, kubernetes, nginx, redis, AWS, and Vault. To publish your own, read Author your own pack.

Last reviewed September 22, 2026