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

# CLI

> File-based rule authoring and eligibility evaluation from the terminal.

## Install

```bash theme={null}
# Isolated, no venv juggling:
uv tool install aethis-cli
```

## Evaluate immediately — no API key

Evaluate against any public ruleset. No login is required for public ruleset discovery, field inspection, explanations, or decisions.

```bash theme={null}
# Browse the public catalogue
aethis rulesets list --public

# Inspect a public ruleset
aethis fields -b aethis/uk-fsm/child-eligibility

# Evaluate a public ruleset
aethis decide -b aethis/uk-fsm/child-eligibility \
  -i '{"child.age": 10, "child.school_type": "state_funded"}'
```

Login is required for tenant projects, private rulesets, composed rulebooks, and authoring commands.

The Free School Meals rulesets from the worked example are live:

```bash theme={null}
aethis decide \
  -b aethis/uk-fsm/child-eligibility \
  -i '{"child.age": 10, "child.school_type": "state_funded"}'
```

```
Decision:  eligible
Fields:    2 provided, 2 evaluated
```

```bash theme={null}
aethis decide \
  -b aethis/uk-fsm/child-eligibility \
  -i '{"child.age": 10, "child.school_type": "independent"}' \
  --explain
```

```
Decision:  not_eligible

Explanation:
  school_type_check  FAIL — school_type must be state_funded (Regulation 3, Education Act 1996 s.512ZA)
```

```bash theme={null}
# Inspect the fields a ruleset expects
aethis fields -b aethis/uk-fsm/child-eligibility
```

```
Fields for aethis/uk-fsm/child-eligibility

  child.age          Int     Age in whole years at start of academic year
  child.school_type  Enum    state_funded | independent | home_educated
```

***

## Author your own rules

Authoring is invite-only private beta ([request access](https://aethis.ai/developer-access)). Set `ANTHROPIC_API_KEY` for default Sonnet 5 generation. For DeepSeek, set `DEEPSEEK_API_KEY` and select `--model deepseek-flash`. The selected provider key is sent with that generation request only and never stored.

```bash theme={null}
# 1. Initialise a project (the wizard prompts for a name, runs sign-in, scaffolds)
aethis init my-rules
cd my-rules
```

<Note>
  **No separate sign-in step.** `aethis init` runs the browser OAuth flow for you the first time, then scaffolds. Alternatively, run `aethis login` explicitly first — same result. As of v0.6.0, any authoring command (`aethis generate`, `aethis publish`, …) also prompts you to sign in inline if no key is cached, so the order doesn't matter.

  For CI / scripted use, set an `AETHIS_API_KEY` env var or pass `--no-prompt` (combined with a missing key, this fails fast instead of hanging on a browser prompt).
</Note>

<Note>
  **A login key authors rulebooks today, via a transition alias.** `aethis login` mints ruleset-authoring scopes and not `rulebooks:*`, but the engine treats `rulesets:write` as satisfying `rulebooks:write`, so `aethis rulebooks create` / `activate` works. That alias is temporary and will be removed once every key carries the canonical scope, so mint the full scope set for any key you intend to keep. Run `aethis whoami` to see your scopes. Full details — the alias table, the scope model, rotation, profiles, CI — on the [Authentication & API keys](/reference/authentication) page.
</Note>

```
Project initialised: my-rules (ruleset)
  aethis.yaml          project config
  sources/             put your policy documents here
  fields/fields.yaml   the field vocabulary for this ruleset
  guidance/hints.yaml  guidance hints (optional)
  tests/scenarios.yaml test cases
```

<Note>
  **Scaffolding a rulebook.** `aethis init my-rulebook --kind rulebook` scaffolds a rulebook (shared `fields/` + `guidance/`, no `sources/` of its own — those belong to its member rulesets). `--kind ruleset` (the default) scaffolds a single rule set.
</Note>

```bash theme={null}
# 2. Add source documents
cp policy.pdf sources/
# or .md, .txt — any text format

# 3. Write test cases (see format below)
# 4. Generate rules
aethis generate
```

```
Uploading sources...   ✓  1 document
Uploading guidance...  ✓  0 hints
Triggering generation...
Polling...  ████████████████████  done (87s)

Ruleset generated: income_eligibility:20260416-f3a1b2c3
```

```bash theme={null}
# 5. Run tests
aethis test
```

```
Running 4 test cases against income_eligibility:20260416-f3a1b2c3

  PASS  Below threshold — eligible
  PASS  Above threshold — not eligible
  FAIL  Edge case — at exact threshold
        Expected: eligible   Got: not_eligible
        Hint: the threshold condition may be using strict < rather than ≤

1 failure. Run `aethis generate` after adding guidance.
```

```bash theme={null}
# 6. Add guidance and regenerate
#    Edit guidance/hints.yaml (see format below), then re-run generate:
aethis generate && aethis test
```

```
Ruleset generated: income_eligibility:20260416-g4b2c3d4
Running 4 test cases...  4/4 passing ✓
```

```bash theme={null}
# 7. Publish
aethis publish
```

```
Published: income_eligibility:20260416-g4b2c3d4 (v2)
Tests:     4/4 passing
Previous:  income_eligibility:20260416-f3a1b2c3 → deprecated
```

***

## Publish with citations

`aethis publish --source-targets <file>` resolves the ruleset's citation keys to
the documents they cite, so every criterion ships bound to the verbatim text it
rests on. Available in `aethis-cli` **v0.31.0+**.

The targets file is YAML or JSON, keyed by citation key. Each entry names
**exactly one** of `url` (a public HTTPS document) or `file` (a local file,
uploaded to the project and cited as a retained artefact), plus `title`,
`authority`, `licence` and the verbatim `quote.exact`:

```yaml theme={null}
# targets.yaml
"GRANT-RULES#2.1":
  url: https://example.org/grants/rules
  title: Community Grants Rules, section 2
  authority: Example Council
  licence: OGL-UK-3.0
  quote:
    exact: "must be a resident of the borough"

"GRANT-GUIDE#4.2":
  file: ./corpus/grant-guidance.pdf
  title: Community Grants Guidance
  authority: Example Council
  licence: OGL-UK-3.0
  quote:
    exact: "Applications must include proof of address"
```

```bash theme={null}
aethis publish --source-targets targets.yaml
```

The file is validated locally — before any credential, config or HTTP — so a
typo costs no round trip. The engine then verifies every quote against the
source bytes at publish time and refuses the whole publish if any citation
fails. A `file` entry becomes an **authenticated** artefact reference, never an
anonymously readable link, and the CLI labels the two kinds distinctly so you
cannot mistake one for the other.

Full semantics — reference schemas, the public-visibility rule, failure reason
codes — are on [Provenance and citations](/authoring/provenance).

***

## Review a project (Authoring Coach)

`aethis review` scores the current project — or a named one — against the Authoring Coach rubric: grounded rationales, discovery, sources, test coverage, iteration, and version discipline. It's **advisory only** — it never blocks publishing — and the deterministic score needs no LLM key. Available in `aethis-cli` **v0.27.0+**.

```bash theme={null}
aethis review                       # review the current project directory
aethis review proj_abc123           # review a specific project by id
aethis review --coach               # add LLM mentoring prose (needs ANTHROPIC_API_KEY)
aethis review --verbose             # full per-check breakdown
aethis review --json | jq .score    # machine-readable report
```

```
Authoring review — score 56/100

  Do next:  Add source-cited 'why' rationales — upload the governing document
            and re-generate so each field's rationale cites it.  (G1)

  Strengths
    ✓ Golden test coverage meets the bar — 6 test cases (threshold 5)
    ✓ The refine loop was driven to green — final pass rate 6/6

  8 checks evaluated. Run with --verbose for the full table.
```

Each check links to the [Review checks](/authoring/review-checks) reference, which documents every check, its weight, and its pass/warn/fail thresholds. `--coach` adds an opt-in mentoring narrative synthesised with your own Anthropic key; the deterministic layer ignores the key entirely.

***

## Project structure

```
my-rules/
├── aethis.yaml              # project config
├── sources/                 # policy documents (PDF, MD, TXT)
├── fields/
│   └── fields.yaml          # field vocabulary — manage with `aethis fields`
├── guidance/
│   └── hints.yaml           # guidance hints
├── tests/
│   └── scenarios.yaml       # test cases
└── .aethis/
    └── state.json           # local tool state — auto-updated, don't hand-edit
```

### aethis.yaml

```yaml theme={null}
project: my-rules
api_key_env: AETHIS_API_KEY
```

### guidance/hints.yaml

```yaml theme={null}
hints:
  - process_type: rule_generation
    text: >
      The £30,000 threshold is inclusive — an applicant with exactly £30,000
      annual income qualifies. Use ≤ not <.

  - process_type: field_extraction
    text: >
      All income fields represent annual gross income in whole pounds sterling.
      Do not use monthly or weekly figures.
```

`process_type` is either `rule_generation` (affects how rules are generated) or `field_extraction` (affects how fields are identified from source text).

### tests/scenarios.yaml

```yaml theme={null}
tests:
  - name: "Below threshold — eligible"
    inputs:
      applicant.annual_income: 25000
    expect:
      outcome: eligible

  - name: "Above threshold — not eligible"
    inputs:
      applicant.annual_income: 35000
    expect:
      outcome: not_eligible

  - name: "Exactly at threshold — eligible"
    inputs:
      applicant.annual_income: 30000
    expect:
      outcome: eligible
```

Test coverage strategy: test boundaries (values just below, at, and above thresholds), every enum value, and any combination of fields that exercises a different code path. Five tests minimum — more is better.

***

## Error scenarios

**Generation fails immediately:**
Check that `AETHIS_API_KEY` is set and valid. Run `aethis account keys` to verify.

**Generation times out:**
Don't re-trigger blindly — the server may keep running after your client
disconnects. Run `aethis status` (or `aethis status --project-id <id>`) before
retrying. Cancel only when you explicitly intend to abandon the run; see
[Handling generation timeouts](/authoring/rule-generation#handling-generation-timeouts).

**Tests fail on publish:**
`aethis publish` refuses if tests are failing. Fix with `aethis generate` (after adding guidance) or pass `--force` to override (not recommended for production).

**Date field listed in `field_errors`:**
The value parsed as neither an ISO `"YYYY-MM-DD"` string nor an integer ordinal (e.g. an ISO datetime, or an invalid calendar date). See [Date field values](/reference/errors#date-field-values).

***

## Commands

### Decision (no API key)

| Command | Description |
| - | - |
| `aethis rulesets list --public` | List public showcase rulesets |
| `aethis decide -b <ruleset_id> -i '<json>'` | Evaluate eligibility. Add `--explain` for trace output. |
| `aethis fields -b <ruleset_id>` | Show input fields the ruleset expects |
| `aethis explain -b <ruleset_id>` | Human-readable rule descriptions |

### Authoring

| Command | Description |
| - | - |
| `aethis init [<name>] [--kind ruleset\|rulebook]` | Scaffold a new project (runs `login` first if needed). Default kind `ruleset`. |
| `aethis generate [--model <model>] [--acceptance-contract <json>] [--poll\|--no-poll] [--timeout <seconds>]` | Upload sources + guidance, trigger generation, and normally poll. With `--no-poll`, use `aethis status` to inspect the queued job. |
| `aethis refine [--model <model>] [--acceptance-contract <json>] [--hint <text>]` | Make the minimal edit to fix failing tests on the active ruleset (vs a from-scratch `generate`) |
| `aethis status` | Show CLI context and generation status, including telemetry availability, server-authoritative worker lifecycle, and retry readiness |
| `aethis cancel [--project-id <id>] [--job-id <observed_job_id>] [--yes]` | Observe and display the exact active job, then explicitly cancel only that job and release its ownership. `--job-id` refuses if the target changed; responses distinguish `cancelled` from idempotent `already_cancelled`. Worker shutdown can be cooperative; never invoked automatically. |
| `aethis test` | Run test cases against the latest ruleset |
| `aethis publish [--force] [--source-targets <file>]` | Set the latest ruleset as active; `--source-targets` binds its citation keys to verified sources. See [below](#publish-with-citations). |
| `aethis review [<project_id>] [--coach] [--json] [--verbose]` | Score the project against the Authoring Coach rubric (advisory). See [below](#review-a-project-authoring-coach). |

### Guidance (project-level)

Project guidance is authored in `guidance/hints.yaml` and uploaded by `aethis generate`. These commands manage hints server-side after upload.

| Command | Description |
| - | - |
| `aethis guidance list` | List active hints for the current project |
| `aethis guidance export --output-file <file>` (or `-o`) | Export the current project's hints to YAML |
| `aethis guidance import <file>` | Import hints from a YAML file |
| `aethis guidance deactivate <hint_id>` | Deactivate a specific hint |

### Fields — inspect & manage the vocabulary

`aethis fields` (no subcommand) inspects a ruleset's fields. The subcommands manage the
local `fields/fields.yaml` vocabulary during authoring.

| Command | Description |
| - | - |
| `aethis fields -b <ruleset_id>` | Show the input fields a ruleset expects (public or tenant) |
| `aethis fields discover` | Discover candidate fields from the project's sources and merge them into `fields/fields.yaml` |
| `aethis fields pull` | Sync the server's authoritative field definitions back into `fields/fields.yaml` |
| `aethis fields validate` | Validate `fields/fields.yaml` (known types, no duplicate keys, enums have `enum_values`, well-formed [`notes`](/authoring/field-vocabulary#pin-field-notes-exactly)) |

### Projects & tenant rulesets (login required)

| Command | Description |
| - | - |
| `aethis projects list` | List your projects |
| `aethis projects show <project_id>` | Show project details |
| `aethis projects archive <project_id>` | Archive a project |
| `aethis rulesets list --project-id <project_id>` | List rulesets for one of your projects |
| `aethis rulesets archive <ruleset_id>` | Archive a ruleset |

### Rulebooks (the converged 2-term model, login required for authoring)

A Rulebook is the whole form — the unit `/decide` evaluates against. It owns a locked field vocabulary, an `outcome_logic` composition expression, rulebook-level test cases, and an integer version history. Rulesets are named, versioned members of a Rulebook. See [Nomenclature](/concepts/nomenclature) for the full model. Commands shipped in CLI v0.14.0+ (rulebooks group) and v0.15.0+ (rulesets lifecycle).

| Command | Description |
| - | - |
| `aethis rulebooks list` | List your tenant's rulebooks — or, with no API key, the cross-tenant public catalogue (e.g. `aethis/uk-fsm`; CLI v0.20.0+) |
| `aethis rulebooks show <id-or-slug>` | Full configuration including outcome\_logic |
| `aethis rulebooks create <name> --domain <d> [--slug ...]` | Create a draft rulebook |
| `aethis rulebooks set-fields <id> -f fields.yaml` | Replace the locked field vocabulary |
| `aethis rulebooks lock-fields <id>` / `unlock-fields <id>` / `get-fields <id>` | Manage the field-lock state |
| `aethis rulebooks set-logic <id> -f logic.yaml` | Set the composition expression (Expr AST) |
| `aethis rulebooks tests add <id> -f scenario.yaml` | Embed a full-form test case |
| `aethis rulebooks tests list <id>` / `delete <id> <tc_id>` | Manage rulebook-level test cases |
| `aethis rulebooks activate <id>` / `archive <id>` | Lifecycle |
| `aethis rulebooks decide <id-or-slug> -i '<json>'` | Evaluate the composed rulebook |
| `aethis rulebooks schema <id-or-slug>` / `explain <id-or-slug>` | Inspect the composed surface |
| `aethis rulesets create <rulebook> <ruleset_name>` | Create a draft ruleset inside a rulebook |
| `aethis rulesets list <rulebook>` | List rulesets in a rulebook (grouped by name, with version counts and live version) |
| `aethis rulesets show <rulebook> <ruleset_name>` | Full version history for one ruleset name |
| `aethis rulesets promote-to-live <rulebook> <ruleset_name> <ruleset_id>` | **The only path to `live`.** Atomically demote prior live → archived, promote candidate, update pins, cut a new Rulebook version. |

### Account & identity

See [Authentication & API keys](/reference/authentication) for the scope model and the
rulebook-authoring key recipe.

| Command | Description |
| - | - |
| `aethis login` | Sign in and store an API key locally — first-time setup, this is all you need |
| `aethis whoami` | Show the key's identity, tier, scopes, and whether authoring is available (diagnose a `403` before you hit one) |
| `aethis account generate [-n <name>] [-s <scope>]…` | Mint an *additional* API key (rotation, multi-machine, scoped access). `-s` **replaces** the default scope set. |
| `aethis account keys` | List your API keys (masked) |
| `aethis account revoke <key_id>` | Revoke a key |
| `aethis update` | Update the aethis CLI to the latest release |

### Profiles (switch between identities)

Store multiple credential profiles (e.g. admin vs dev) instead of swapping env vars.

| Command | Description |
| - | - |
| `aethis profile list` | Show all profiles and which one is active |
| `aethis profile use <name>` | Set the sticky default profile |
| `aethis profile add <name>` | Create or update a named profile |
| `aethis profile remove <name>` | Delete a profile |

Override for a single command with `aethis --profile <name> …` (or `--profile anonymous`
to force unsigned mode).

### MCP server

Wire up the [Aethis MCP server](/mcp-server/overview) in Claude Code, Cursor, Claude Desktop, or Windsurf without hand-editing JSON.

| Command | Description |
| - | - |
| `aethis mcp install --target <client>` | Install. Targets: `claude-code`, `cursor`, `claude-desktop`, `windsurf`, or `all`. Idempotent. |
| `aethis mcp uninstall --target <client>` | Remove the `aethis` server entry, leaving any other configured servers in place |

***

## Generation model selection

`generate` and `refine` in aethis-cli 0.41.0 or later accept
`--model claude-sonnet-5` or
`--model deepseek-flash`. Omit the flag to preserve the server default
(Sonnet 5 unless the server operator has overridden it).

```bash theme={null}
aethis generate --model deepseek-flash
aethis refine --model deepseek-flash --hint "Apply the lower age bound inclusively."
```

For DeepSeek, populate `DEEPSEEK_API_KEY` securely in your environment.
To use another environment variable name, set `deepseek_key_env` in
`aethis.yaml`. The configuration stores the variable name, not the key:

```yaml theme={null}
deepseek_key_env: MY_DEEPSEEK_API_KEY
```

Only the selected provider's credential accompanies generation. A missing
provider key fails the request rather than using a platform credential.
The selection is per invocation; pass it again to `refine` when needed.

## Structured acceptance contracts

CLI 0.42.0 or later provides `--acceptance-contract <json>` on `generate` and `refine` when
the target engine supports versioned authoring contracts. The file carries test
cases and optional review-binding assertions as one replacement. The CLI checks
that the engine retained the exact contract before generation starts. See
[structured acceptance contracts](/authoring/rule-generation#structured-acceptance-contracts)
for the supported assertions and the distinction between an omitted and empty
binding catalogue.

## Environment variables

| Variable | Required | Default |
| - | - | - |
| `AETHIS_API_KEY` | Authoring, private rulesets, project commands | — |
| `ANTHROPIC_API_KEY` | Sonnet generation/refinement and other Anthropic-backed authoring operations | — |
| `DEEPSEEK_API_KEY` | Draft `generate` / `refine --model deepseek-flash` option | — |
| `AETHIS_NONINTERACTIVE` | Set truthy (`1`/`true`/`yes`) in CI or a background job to bypass every confirmation prompt (destructive commands proceed instead of hanging on `[y/N]`). Prints a one-line notice so it's never silently active. | — |
| `CI` | Same effect as `AETHIS_NONINTERACTIVE` when truthy. | — |

## Shell completions

```bash theme={null}
aethis --install-completion zsh    # or bash, fish, powershell
```

## Worked example

See [UK Free School Meals](/getting-started/examples) — full three-section example with source documents, guidance hints, and test cases ready to run.

<Note>
  **Help improve this page**

  If something here is unclear or missing an example, use the feedback button at the bottom of the page.

  Found a bug? [Open a GitHub issue](https://github.com/Aethis-ai/feedback/issues). Evaluating Aethis for a regulated workflow? [Contact us directly](https://aethis.ai/developer-access).
</Note>


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