The CLI is published on npm (npm i -g @aex-lang/cli). APIs are experimental and may change before v1.0. Roadmap →
Skip to content

Quickstart ​

Run your first AEX contract in under five minutes.

Install ​

bash
npm install -g @aex-lang/cli

Or run without installing:

bash
npx @aex-lang/cli check tasks/fix-test.aex

Create a Policy ​

Every repo starts with a policy — the ambient security boundary:

bash
aex init --policy

This creates .aex/policy.aex:

aex
policy workspace v0

goal "Default security boundary for this repository."

allow file.read, file.write, tests.run, git.*
deny network.*, secrets.read

confirm before file.write

budget calls=100

Edit it to match your repo's needs. Policies define what tools are available, which are denied, and which require human approval.

Draft a Contract from a Prompt ​

The fastest way to create a task contract:

bash
aex draft "fix the failing test in src/foo.ts" --model anthropic

This generates a validated contract in .aex/runs/. Review it:

bash
aex review .aex/runs/20260502-fix-failing-test.aex

Approve and execute:

bash
aex review .aex/runs/20260502-fix-failing-test.aex --run

The model drafts. You review. AEX executes with full enforcement.

Write a Contract by Hand ​

For reusable workflows, write contracts directly. Create tasks/fix-test.aex:

aex
task fix_test v0

goal "Fix the failing test with the smallest safe change."

use file.read, file.write, tests.run
deny network.*, secrets.read

need test_cmd: str
need target_files: list[file]

do tests.run(cmd=test_cmd) -> failure
do file.read(paths=target_files) -> sources

make patch: diff from failure, sources with:
  - fix the failing test
  - preserve public behavior
  - do not touch unrelated files

check patch is valid diff
check patch touches only target_files
confirm before file.write

do file.write(diff=patch) -> result
do tests.run(cmd=test_cmd) -> final

check final.passed
return final

Validate It ​

bash
aex check tasks/fix-test.aex

Scaffold Files ​

bash
aex init --task fix-test

This generates a starter contract plus matching inputs and policy files under tasks/.

Preview Effective Permissions ​

See the merged permissions when policy and task are combined:

bash
aex effective --contract tasks/fix-test.aex

Output:

Policy:   .aex/policy.aex
Contract: tasks/fix-test.aex

Allowed:
  file.read
  file.write
  tests.run

Denied:
  network.*
  secrets.read

Confirmation required:
  file.write

Budget:
  calls=20

The allow list is the intersection (only tools both policy and task agree on), deny is the union (everything either blocks), and budget is the minimum.

Compile to JSON IR ​

bash
aex compile tasks/fix-test.aex

The JSON output captures permissions, needs, and step sequence for downstream runtimes. The CLI validates the result against the official IR schema before printing.

Format the Contract ​

bash
aex fmt tasks/fix-test.aex

Add --check to ensure formatting during CI without rewriting files:

bash
aex fmt tasks/fix-test.aex --check

Run It ​

bash
aex run tasks/fix-test.aex \
  --inputs examples/fix-test/inputs.json \
  --policy examples/fix-test/policy.json \
  --auto-confirm

The runtime enforces contract permissions and policy budgets. Without --auto-confirm, the CLI blocks at confirm before file.write and reports that confirmation is required.

Audit Log ​

The runtime logs every tool call and check to stdout:

json
{"event":"run.started","agent":"fix_test","version":"v0"}
{"event":"tool.allowed","tool":"tests.run","step":1}
{"event":"tool.result","tool":"tests.run","bind":"failure"}
{"event":"tool.allowed","tool":"file.read","step":2}
{"event":"tool.result","tool":"file.read","bind":"sources"}
{"event":"make.result","bind":"patch","type":"diff"}
{"event":"check.passed","condition":"patch is valid diff"}
{"event":"check.passed","condition":"patch touches only target_files"}
{"event":"confirm.required","tool":"file.write"}
{"event":"confirm.approved","tool":"file.write"}
{"event":"tool.allowed","tool":"file.write","step":3}
{"event":"tool.result","tool":"file.write","bind":"result"}
{"event":"tool.allowed","tool":"tests.run","step":4}
{"event":"tool.result","tool":"tests.run","bind":"final"}
{"event":"check.passed","condition":"final.passed"}
{"event":"run.finished","status":"success"}

Enforce with Claude Code ​

Built-in tools (aex gate) ​

Add to .claude/settings.json:

json
{
  "hooks": {
    "PreToolUse": [{ "matcher": ".*", "command": "aex gate" }]
  }
}

aex gate maps Claude Code tools (Write, Bash, etc.) to AEX capabilities (file.write, shell.exec) and gates them against your policy.

MCP tools (aex proxy) ​

bash
aex proxy --auto-confirm -- npx -y your-mcp-server

The proxy auto-discovers .aex/policy.aex. See the Claude Code and Codex integration guides for full setup.

How make Works ​

make steps ask a model to generate an artifact (like a diff or a draft). When you run aex run, the runtime delegates make to a model handler.

Default behavior: Without a model handler, aex run blocks at the first make step and reports that no model handler is configured.

Using OpenAI:

bash
export AEX_MODEL=openai
export OPENAI_API_KEY=sk-...
aex run tasks/fix-test.aex --inputs examples/fix-test/inputs.json --policy examples/fix-test/policy.json

Using a custom handler:

bash
aex run tasks/fix-test.aex --model-handler ./my-handler.ts

A model handler is a function that receives the make step description (type, inputs, instructions) and returns the generated artifact. See the OpenAI Agents integration for a full example.

Sign and Verify the Contract ​

Attach provenance metadata before shipping a contract:

bash
aex sign tasks/fix-test.aex --id maintainer --key-file ./signing.key

Verify the metadata later:

bash
aex verify tasks/fix-test.aex \
  --signature tasks/fix-test.aex.signature.json \
  --key-file ./signing.key

The signature file records the hash, signer, and timestamp, giving security teams an audit trail for every contract revision.

Prompts are not permissions. Plans are not contracts.