Skip to content
Anlyon
Esc
↑↓navigate↵open⌘Jpreview
On this page

Config as code

Keep an environment's actions, packs, approval policies, impact limits and budgets in anlyon.yaml. anlyon plan shows each change as tightening or loosening, anlyon apply applies it, anlyon pull writes what is live.

anlyon.yaml holds what your agent may do in each environment: its actions, the packs installed, the approval policies, the impact limits and the budgets. You change it in a pull request like any other code. anlyon plan shows the difference with what is live, anlyon apply makes it live, and anlyon pull writes what is live back to the file.

Know why you would use it

Guardrails changed by hand in a console drift: nobody remembers why a limit was raised, staging and production stop matching, and a change that loosens a rule ships with no review.

  • Less risk. Every change is marked tightening or loosening before it applies. Tightening applies at once. Loosening, from a CLI login or an API key, waits for a workspace admin to approve it at a sign-off link: your agent, or the CI job it can trigger, can never loosen its own guardrails.
  • Less effort. One file per repository, every environment in it. Review the plan in the pull request, apply on merge.
  • A record. The file’s history says who changed which rule, when and why.

Start from what is live

anlyon auth login --scope anlyon:guardrails
anlyon pull

pull writes the environment your credential is bound to into anlyon.yaml, creating the file if there is none. Other environments in the file and its comments are kept. Commit the file.

The Guardrails consent group lets a CLI login read and change policies and limits. It starts unticked on the consent screen. In CI, use an API key with policies:read, policies:write, impact-limits:write, actions:write, and budgets:read and budgets:write if the file has budgets.

The file

# anlyon.yaml
version: 1
environments:
  production:                       # an environment's slug
    secrets: [POSTMARK, GITHUB]     # names that must exist. Never values.
    packs:
      github: { actions: [list-issues, create-issue], withLimits: true }
    actions:
      send-receipt:
        description: Email a receipt
        method: POST
        url: https://api.postmarkapp.com/email
        headers: { X-Postmark-Server-Token: "{{secret:POSTMARK}}" }
        governed: true
        impact: { dimension: emails, amount: count(input.to), bound: exact }
    policies:
      big-refunds:
        name: Refunds over $500 need two approvers
        target: { action: refund }
        when: input.amount >= 50000
        approvals: 2
    limits:
      Emails per day: { dimension: emails, amount: 500, period: day }
      Old limit: null               # archive it
    budgets:
      <api-key-id>: { monthlyCostCentsCap: 5000, dimensionCaps: { actionInvokes: 10000 } }
  staging:
    limits:
      Emails per day: { dimension: emails, amount: 50, period: day }
Section Holds When it is not in the file
secrets Secret names the actions need. plan lists a missing one as needs you: store its value with anlyon connections add or in the console. Not checked.
packs Catalogue packs by name (github) or a pack directory, with the pack flags: actions, withLimits, secretNames, params, credential, noPrefix. Installed packs are left alone.
actions Actions by name: description, method, url, headers, body, inputSchema, requiresApproval, enabled, governed, impact, verify. A field you leave out is not managed. Left alone.
policies The policies block of a policy file. The file owns them: removing one from the file deletes it. Left alone.
limits Impact limits by name: dimension, amount, period, and currency, action, resourcePrefix, scope (environment or end_user). null archives one. Left alone.
budgets Budgets by the API key id they cap: monthlyCostCentsCap, dimensionCaps, alertThreshold, enabled. null removes one. Left alone.

A credential acts on the environment it is bound to, so plan and apply use that environment’s entry. Policies are stored under the policy file id anlyon.yaml; set policyFile: at the top to use another.

Secret values never go in the file. A value that looks like a credential (an Authorization header that does not reference {{secret:NAME}}, or a string shaped like a provider key) stops the command and names where it is.

Plan

anlyon plan
Plan for anlyon.yaml: environment production (<environment-id>)

  ! secrets.GITHUB                 needs you   store its value: anlyon connections add, or Secrets in the console. The file holds names only.
  ~ actions.send-receipt           tightening  adds an impact declaration
  + policies.big-refunds           tightening  adds a policy that gates calls
  ~ limits.Emails per day          tightening  lowers the limit from 1000 to 500
  - limits.Old limit               loosening   archives the limit (10 emails per day)

3 tightening, 1 loosening (waits for a person's sign-off), 0 neutral, 1 needs you, 4 unchanged.

plan sends no change. --markdown prints a table for a pull-request comment; --json prints {data: {changes, summary, errors}}.

How each change is read:

Change Direction
Add an action, enable one, change where or what it sends, remove an impact or a read-back loosening
Disable an action, require approval, make it governed, add an impact or a read-back tightening
Add a policy that gates or denies; make one stricter tightening
Delete or disable a policy that gates calls; make one looser; change what it matches loosening
Add a limit, or lower one tightening
Raise, archive or replace a limit loosening
Add or lower a budget cap, turn a budget on, alert earlier tightening
Raise or remove a cap, turn a budget off, alert later loosening
A description, a rename, a disabled policy neutral

The server makes the final call when you apply. A change it reads differently is reported by apply.

Apply

anlyon apply --yes

apply plans, then makes the changes: tightening and neutral ones at once, loosening ones last. Policies go in two passes, so a new rule that tightens is never held up behind one that loosens.

A loosening change made with a CLI login or an API key is not applied. The server answers with a sign-off request, and apply prints its link:

These changes loosen a guardrail. A workspace admin approves each one at its link; nothing here can approve them:
  limits.Old limit: needs a person's sign-off
    https://console.anlyon.com/sign-offs/sor_...

  limits.Emails per day  applied
  limits.Old limit  sign-off pending (sor_...)

1 change(s) wait for a person's sign-off. Run anlyon plan after they decide.

--wait 30m waits for the decisions and reports them. Exit codes: 0 when everything applied, 15 when a sign-off is pending, 9 when --wait ran out, 14 when a change failed or a sign-off was rejected or expired.

Run plan on pull requests and apply on merge

Store an API key with the scopes above as the repository secret ANLYON_API_KEY, one per environment.

# .github/workflows/anlyon.yml
name: Anlyon guardrails
on:
  pull_request:
    paths: [anlyon.yaml]
  push:
    branches: [main]
    paths: [anlyon.yaml]

permissions:
  contents: read
  pull-requests: write

jobs:
  guardrails:
    runs-on: ubuntu-latest
    env:
      ANLYON_API_KEY: ${{ secrets.ANLYON_API_KEY }}
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - name: Plan
        if: github.event_name == 'pull_request'
        run: npx --yes @anlyonhq/cli plan --markdown > plan.md
      - name: Comment the plan
        if: github.event_name == 'pull_request'
        env:
          GH_TOKEN: ${{ github.token }}
        run: gh pr comment ${{ github.event.pull_request.number }} --body-file plan.md --edit-last || gh pr comment ${{ github.event.pull_request.number }} --body-file plan.md
      - name: Apply
        if: github.event_name == 'push'
        run: npx --yes @anlyonhq/cli apply --yes

On merge, tightening changes apply and the job succeeds. Loosening ones exit 15 with their sign-off links in the job log, so the run shows as failed until a workspace admin decides. Pin the CLI version once you rely on it.

Pull

anlyon pull --yes

Writes the live environment: every action except those of packs the file lists, the policies the file owns, the limits that are not archived, the budgets (when the credential can read them), and the secret names the actions reference. Line endings and comments elsewhere in the file are kept. --yes replaces an environment already in the file without asking.

Was this page helpful?