> ## Documentation Index
> Fetch the complete documentation index at: https://docs.atlasent.io/llms.txt
> Use this file to discover all available pages before exploring further.

# atlasent-policy CLI

> Keep AtlaSent policies as files in a repo: validate and test them offline, plan changes on pull requests, and apply on merge.

# atlasent-policy CLI

`atlasent-policy` treats your authorization policies like code. Keep them
as YAML or JSON files in a repo, review them in pull requests, see exactly
what will change with `plan`, and publish on merge with `apply`.

`validate`, `test`, `convert`, and `verify-bundle` run **without network
access**, using the same rule engine the runtime uses. `plan`, `pull`, and
`apply` talk to AtlaSent, and only `apply` writes.

***

## Install

<Note>
  The CLI is **not published to npm.** `npm install -g @atlasent/cli`
  returns a 404; don't use it. The CLI ships as one bundled file in the
  public [Atlasent/atlasent-policies](https://github.com/Atlasent/atlasent-policies)
  repository.
</Note>

Nothing to install beyond Node 20 or later. Run it straight from the public
repository, pinned to a release tag for reproducible runs:

```sh theme={null}
npx github:Atlasent/atlasent-policies#v1 --help
npx github:Atlasent/atlasent-policies#v1 validate policies
```

The examples below write `atlasent-policy` for short; substitute
`npx github:Atlasent/atlasent-policies#v1`.

## Configuration

| Variable | Default | Used by |
| - | - | - |
| `ATLASENT_API_KEY` | none | `plan` and `pull` need `policy:read`; `apply` needs `policy:write`. |
| `ATLASENT_BASE_URL` | `https://api.atlasent.io/functions/v1` | All network commands. |

## Commands

| Command | Network | What it does |
| - | - | - |
| `validate [dir]` | no | Parse and lint every policy and test file. Unknown keys and operators are errors. |
| `test [dir]` | no | Run `*.tests.yaml` / `*.tests.json` cases through the real rule engine. |
| `plan [dir]` | read | Diff each policy against the live published version, with server-side validation. No writes. `--format markdown` prints a comment ready to post on a PR; `--detailed-exitcode` exits `2` when there are changes. |
| `apply [dir]` | write | Publish every policy whose rules differ from what's live. Writes nothing if any file fails preflight. `--source-digest` and `--reason` record provenance. |
| `pull [--out dir]` | read | Download live published policies, YAML by default. Use it to adopt policies first authored in the console. |
| `convert [dir]` | no | Rewrite JSON policy and test files as YAML, or back with `--to json`. |
| `verify-bundle <file>` | no | Offline check of a `/v1/export-audit` bundle. `--trusted-key <pem>` pins the signing key; exit `0` ok, `1` failure, `2` usage error. |

`dir` defaults to `policies/`.

## A policy file

One file per action type. `rules` is the same rule object the runtime
evaluates:

```yaml theme={null}
# yaml-language-server: $schema=https://raw.githubusercontent.com/Atlasent/atlasent-policies/main/schema/policy.schema.json
action_type: production.deploy
description: Two approvals, business hours only.
rules:
  change_window:
    timezone: America/Los_Angeles
    days_of_week: [1, 2, 3, 4]
    hours: { start: "09:00", end: "17:00" }
  require_approvals:
    count: 2
    exclude_actor: true
  templates:
    - decision: allow
```

The action class must already exist in your organization; `plan` tells you
if it doesn't.

## Tests

Put test cases next to the policy as `<action_type>.tests.yaml`. `now` fixes
the clock, so tests are deterministic whenever they run:

```yaml theme={null}
bundle: production.deploy
tests:
  - name: two recent approvals inside the window is allowed
    actor_id: alice
    now: "2026-04-14T18:00:00Z"
    context:
      approvers:
        - { id: bob, role: security, timestamp: "2026-04-14T17:00:00Z" }
        - { id: carol, role: engineering, timestamp: "2026-04-14T17:30:00Z" }
    expect: allow
  - name: Friday is outside the change window
    actor_id: alice
    now: "2026-04-17T18:00:00Z"
    expect: deny
    expect_deny_code: OUTSIDE_CHANGE_WINDOW
```

```sh theme={null}
atlasent-policy test policies
```

Local tests cover a policy's `rules`. They don't exercise action-class
requirements such as MFA, verified actor identity, or human approval, which
the runtime enforces separately, so a passing test isn't a guarantee of a
live `allow`.

## CI integration

The public repository also ships a GitHub Action that runs `plan` on pull
requests and `apply` on merge:

```yaml theme={null}
- uses: Atlasent/atlasent-policies/actions/policy@v1
  with:
    mode: plan                     # or: check (offline), apply
    api_key: ${{ secrets.ATLASENT_POLICY_READ_KEY }}
```

Or run the offline checks directly:

```yaml theme={null}
- uses: actions/setup-node@v4
  with:
    node-version: '20'
- run: npx --yes github:Atlasent/atlasent-policies#v1 validate policies
- run: npx --yes github:Atlasent/atlasent-policies#v1 test policies
```

Use two keys: a `policy:read` key for pull-request plans and a
`policy:write` key only on the apply job.

## What this CLI doesn't do

* **Decide for the runtime.** The runtime is always the source of truth for
  authorization decisions. The CLI lets you check that the rules you wrote
  say what you meant before you publish them.
* **Bypass governed publishing.** `apply` publishes through the governed
  path in the runtime. If an action class has an approval chain, the publish is
  refused and the job exits `1` with the reason.

## Source

[Atlasent/atlasent-policies](https://github.com/Atlasent/atlasent-policies)
holds the CLI source (Apache-2.0), starter policies with test suites, the
policy JSON Schema, and the GitHub Action.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.