# Aral Cloud for AI agents — getting started

Aral Cloud is managed end-to-end with one CLI: `aral`. Every command accepts
`-o json` (or `ARAL_OUTPUT=json`) and prints machine-readable JSON. Errors go
to stderr as `{"error": "..."}` and the exit code is non-zero. A refusal you
can act on also carries `"code"` (e.g. `insufficient_balance`,
`token_spend_limit`) and `"params"` — branch on the code, not the sentence.

## Install

    curl -fsSL https://aralcloud.uz/dl/install | sh    # or download from the console

## Authenticate

The simplest way: ask your human to approve a browser sign-in. Propose what
you need — they see it prefilled, can change it, and approve:

    aral auth login --browser --name claude-agent --spend-limit 50000 \
        --scope servers:write --scope dns:write --expires-days 30

Every flag is optional; anything left out defaults to full access, no spend
limit, 90 days. `--all` proposes full access explicitly. The answer (JSON with
`-o json`) says what the human actually approved: `name`, `scopes`,
`spend_limit_cents` (null = unlimited). The code and link go to stderr.

Or ask for an API token (Console → Settings → API tokens, or they run
`aral token create --all --name my-agent --spend-limit 50000`), then:

    aral auth login --token nex_...     # stores it in ~/.aral/config.yaml
    aral auth whoami                    # verify

The CLI silently swaps the token for a short-lived session JWT and caches it in
`~/.aral/session.json`; you never manage that. `ARAL_TOKEN=nex_...` as an env
var works too and overrides the stored one.

## Model

- **Organization** — the billing boundary. A token acts in the org it was
  minted in.
- **Project** — a workspace inside the org. `aral project list`, and
  `aral project use <id>` saves the default. Resources you create land in the
  active project. An agent running beside other agents should pin its project
  per invocation with `ARAL_PROJECT=<id>` (or `--project <id>`) instead of
  `project use` — the env var wins and never touches shared state.
- **Money** — `aral billing balance` answers `{balance_cents, has_paid, ...}`
  in UZS tiyin (100 tiyin = 1 so'm). `has_paid:false` means creates will be
  refused with 402 — tell your human to top up.
- **Spend limit** — a token may carry a lifetime spend limit (so'm). Once
  what it has spent plus the next hour of a new resource would pass it, paid
  creates and upsizes are refused with `"code": "token_spend_limit"` and
  `params: {spent_cents, limit_cents, required_cents}`. Running resources keep
  running. Ask your human to raise it (`aral token update <id> --spend-limit
  <so'm>` or Console → Settings → API tokens); don't retry. `token_spend_unknown`
  means the limit could not be checked — retry shortly.

## Conventions that hold everywhere

- List commands return a JSON array; get commands return one object; ids are
  UUIDs. Pass ids positionally: `aral server get <id>`.
- Create is asynchronous for anything that boots a VM: the response returns
  immediately with `status: pending|creating|configuring`; poll the `get`
  command until `active`/`ready` (10s interval is polite; a fresh VM takes
  ~2 minutes, a managed database or one-click app several).
- Deletes are immediate commands but teardown is asynchronous too.
- Regions today: `hel1` (Helsinki). `aral server regions` is authoritative.
