# Projects, SSH keys & tokens with `aral`

## Projects (workspaces)

    aral project list
    aral project create --name staging
    aral project use <id>       # saves the default project for this machine
    aral project delete <id>    # refused while it still holds resources

## Running several agents at once

`project use` writes a shared default (`~/.aral/config.yaml`), so two agents
switching projects would fight over it. Pin each agent instead:

    ARAL_PROJECT=<project-id> aral server list   # per-invocation, no shared state
    aral --project <project-id> server create ...

`ARAL_PROJECT` (or `--project`) beats the saved default and never touches the
config file, so parallel agents in different projects cannot interfere. For
full isolation (own credentials and device key too), give an agent its own
state dir with `ARAL_HOME=/path/to/dir`. Session tokens are cached per
(token, project) pair — bursts of commands stay within rate limits.

## Account SSH keys

    aral sshkey create --name laptop --public-key "ssh-ed25519 AAAA..."
    aral sshkey list
    aral sshkey delete <id>

## API tokens (for other agents / CI)

    aral token create --all --name ci-bot                   # unrestricted (prints a warning)
    aral token create --scope servers:read --name ro        # scoped
    aral token create --all --name agent --spend-limit 50000  # at most 50 000 so'm, lifetime
    aral token list           # SOURCE (agent|manual), SPENT/LIMIT in so'm ("?" = unknown)
    aral token update <id> --name renamed
    aral token update <id> --spend-limit 100000   # or --no-limit
    aral token update <id> --scope servers:write  # or --all; replaces the scope list
    aral token delete <id>

The secret is shown once. A token acts in the organization it was minted in.
Tokens approved through `aral auth login --browser` are listed with source
`agent`. In JSON, `spend_limit_cents` and `spent_cents` are tiyin
(100 = 1 so'm); `spend_limit_cents: null` is unlimited, `spent_cents: null`
means billing did not answer.

A spend limit never stops what already runs: past it, new paid creates and
upsizes made with that token are refused with `"code": "token_spend_limit"`
(`params: {spent_cents, limit_cents, required_cents}`). A token's limit and
scopes are read when its session is minted, so a change can take up to the
session's lifetime (~30 minutes) to reach a running agent.
