CLI

Point the CLI at a deployment

Four things decide what a command reaches:

  • the server it calls,
  • the credential it presents,
  • the Redis behind that deployment,
  • the axl-config bundle it reads agents, skills, and document sets from.

Typing all four on every command is unworkable, and getting one wrong is worse than typing it. A profile is those four under a name.

The resolution chain

Every one of the four resolves the same way, and the first source that has an answer wins:

flag → environment variable → the profile in use → fallback

axl config show

prints each resolved value with the source that supplied it, which shows why each value is set the way it is, without guessing:

  Profile
  Name: prod (from axl config use)
  File: /Users/you/.axl/profiles/prod.json

  Resolved settings
  api-url:    https://axl.internal/api/v1  (profile 'prod')
  token:      eyJ0eXAi…Gk0fZg              (profile 'prod')
  redis-url:  redis://10.0.0.4:6379        ($REDIS_URL)
  config-dir: /Users/you/src/axl/axl-config (discovered)

Only one has a default

--api-url falls back to http://localhost:5000/api/v1. The other two destinations have no built-in default at all.

A wrong API URL fails loudly: nothing answers, and you find out immediately. A wrong Redis does not. It connects, reads an empty keyspace, writes into it, and reports success - so a default of redis://localhost:6379 on a machine running Redis on several ports is a way to ingest a corpus into the wrong database and not notice. The same is true of a config bundle: point at the wrong one and every command works, against the wrong agents.

So an unset Redis URL or bundle is an error that names every way to set it:

no redis-url is set: pass --redis-url, set REDIS_URL, or store one with
`axl config set redis-url <value> --profile prod`

Locating the bundle

The config bundle has one source no default could provide: if nothing names it, the CLI walks up from the working directory looking for an axl-config directory.

Standing in a checkout selects that checkout's bundle. Nothing is stored, nothing has to be kept in sync, and several worktrees of the same repository each get their own - which is what makes axl rag ingest safe to run from whichever tree you happen to be in.

Create and select a profile

# Creates `prod` and stores a server in it
axl config set api-url https://axl.internal/api/v1 --profile prod
axl config set redis-url redis://10.0.0.4:6379 --profile prod

# Mint a credential into it
axl config init --profile prod --user-id you@example.com --role admin \
  --jwt-private-key ~/.axl/keys/jwt_private.pem

# Use it for every later command
axl config use prod

config set and config init are the only commands that may name a profile that does not exist yet - they are how one comes into existence. For every other command a name that resolves to nothing is an error, because the alternative is running against the fallback server and reporting whatever was found there as the profile's truth.

axl config list              # every profile, with its server; active and in-use marked
axl config unset redis-url   # back to flag or environment
axl config remove staging

Where it all lives

PathContents
~/.axl/credentials.jsonthe profile named default
~/.axl/profiles/<name>.jsona named profile
~/.axl/settings.jsonwhich profile axl config use selected
~/.axl/keys/signing and JWT keypairs

AXL_HOME moves that directory. It is deliberately not AXL_CONFIG_DIR: one names where your bearer token is kept, the other names a checkout of agents and documents, and a single variable meaning both is how you end up looking for credentials inside a config bundle.

Profiles hold a bearer token, so they are written owner-only (0600) inside an owner-only directory. A profile name becomes a file name and is validated as one - letters, digits, -, _, . - so a name can never place a credential outside that directory.

Several deployments, several checkouts

The two axes are independent:

  • Which deployment is a profile decision - a flag, AXL_PROFILE, or axl config use.
  • Which bundle is a directory decision - wherever you are standing.

So a laptop that talks to dev, staging, and prod holds three profiles and switches with one command, while a repository with eight worktrees needs no configuration at all for each to operate on its own bundle.

export AXL_PROFILE=staging      # for this shell
axl --profile prod agents list  # for this command

Piping the token

axl config token writes the bearer credential alone on stdout. Everything else the CLI prints goes to stderr, which is what makes this work:

TOKEN=$(axl config token)
curl -H "Authorization: Bearer $TOKEN" http://localhost:5000/api/v1/agents

Next

On this page