Run AXL locally
AXL is a server. You run axl-server, it loads your agents from a configuration
directory, and you talk to it over HTTP on port 5000. The axl command line tool is
a separate binary that talks to that server for you.
What you need first
Redis with the RediSearch module. AXL keeps sessions, memory, tasks, and search
indexes there. The redis/redis-stack-server image has what you need:
docker run -d -p 6379:6379 redis/redis-stack-serverA model provider key. You need at least one. AXL will refuse to start without any, and
tells you so: No LLM providers configured. Set at least one API key.
A signing keypair for tokens. AXL authenticates callers with RS256 JSON Web Tokens, so it needs a key to verify them:
axl key generate-jwtThat writes a private and public PEM. Keep the private one private.
If you would rather bring up Redis alongside the optional services - document
extraction, S3-compatible storage, an identity provider - the repository root has a
compose.yml with all of them. It uses its own ports, so set REDIS_URL to match
rather than assuming 6379.
What the first start looks like
- The first start is slower than later ones. AXL embeds a local model for memory and search, and
prints
Initializing local embedder...while it loads. If you configure no memory and no doc sets, it is skipped entirely. - Warnings scroll past.
TAVILY_API_KEY not set - web tools disabledand similar lines mean an optional feature is off because you have not configured it. (PII_VAULT_KEYis the exception: with any shielded agent it is required, and the server refuses to start without it.) The server is telling you what it turned off. - A line naming your agents is the real "up" signal - one
Agent readyper agent, then the listening line.
Start the server
export CONFIG_DIR=/path/to/axl-config
export REDIS_URL=redis://localhost:6379
export ANTHROPIC_API_KEY=sk-ant-...
export JWT_PRIVATE_KEY="$(cat ~/.axl/keys/jwt_private.pem)"
export JWT_PUBLIC_KEY="$(cat ~/.axl/keys/jwt_public.pem)"
axl-serverThose five are the whole minimum. REDIS_URL defaults to
redis://localhost:6379 and PORT defaults to 5000, so you can drop those two if
they match your setup. Everything else has a working default; the full list is in
.
From a source checkout, the command is cargo run --bin axl-server instead.
Start with just a few agents
By default the server loads every agent listed in agents.toml. While you are
finding your feet, it is often nicer to boot one or two and leave the rest alone -
startup is quicker, and an agent you have no credentials for cannot distract you with
warnings. AGENT_CONFIGS takes a comma-separated list of agent directories, relative
to CONFIG_DIR, and uses them instead of the agents.toml list. Each entry points at
a directory holding an agent.toml, the same paths agents.toml lists:
export AGENT_CONFIGS=agents/acme/acme-support-agent
axl-serverSkills still come from agents.toml, so agents you name here keep working normally.
Unset it whenever you want the full roster back.
Check it came up
curl http://localhost:5000/health{ "status": 200, "msg": "OK", "data": { "status": "healthy", "version": "0.1.0" } }/health is the one route that does not need a token. Everything under /api/v1
does.
Get a token
axl config init \
--jwt-private-key ~/.axl/keys/jwt_private.pem \
--user-id you@example.comThis mints a token signed with your private key and saves it, so the axl command
line tool is authenticated from here on. It does not contact the server; it signs
locally with the same key the server verifies against.
It also saves the API URL it will use from now on, defaulting to
http://localhost:5000/api/v1. If your server is on another port, say so here or every
later command will quietly aim at the wrong place:
axl config init … --api-url http://localhost:5055/api/v1Three more values have to agree with the server, and config init cannot check them for
you because it never calls it. If your deployment overrides any of these, pass the
matching flag or verification fails and every call returns 401:
| Flag | Must match the server's | Default |
|---|---|---|
--jwt-kid | JWT_KID | axl-key-1 |
--issuer | JWT_ISSUER | axl |
--audience | JWT_AUDIENCE | axl |
--tenant is different: it sets the token's azp claim, which the server reads as your
tenant rather than checking against a configured value. It defaults to default.
Defaults line up out of the box, so on a fresh local setup you need none of these.
axl config show prints what was saved.
Say hello
axl agents listYou should see the agents in your configuration directory. Then talk to one:
axl chat <agent-key>That opens an interactive session. To ask one question and get one answer back - handy for a first smoke test, or for pasting the result into a ticket:
axl chat <agent-key> -m "Hello, what can you do?"To do the same over HTTP, see .
When it does not start
| What you see | What it means |
|---|---|
CONFIG_DIR is not set | Point it at the directory holding agents.toml |
No LLM providers configured | Set at least one provider API key |
A panic mentioning length is lower than 1 | JWT_PRIVATE_KEY or JWT_PUBLIC_KEY is empty. Run axl key generate-jwt |
Connection refused on startup | Redis is not reachable at REDIS_URL |
401 Missing Authorization header | The route needs a token. Run axl config init |
401 with a token that looks fine | A kid, issuer, or audience mismatch. See Get a token |
models.toml is required | CONFIG_DIR points at a directory without one; it is the model registry |
PII_VAULT_KEY is unset but N agent(s) have the shield enabled | Set PII_VAULT_KEY to CSPRNG key material (e.g. openssl rand -hex 32; the 32-byte key is derived from it) and keep it stable, or disable the shield for every agent |
MCP_ALLOWED_HOSTS must be set in production | A production boot needs MCP_ALLOWED_HOSTS (or PUBLIC_BASE_URL, from which it is derived); without one, /mcp accepts only loopback Host headers |
The process exits with an Error: after listing some agents | One agent's configuration could not be loaded. The message names the file - fix it, or narrow the roster with AGENT_CONFIGS while you do |
| Memory silently does nothing | Redis without the RediSearch module. The log says unknown command 'FT.CREATE' and the agent starts with memory: "disabled" |
| It seems to hang for a while | Probably the embedder loading on a cold start. See What the first start looks like |
Read the log first. The server explains itself: it prints one line per agent as it loads, names the file behind any configuration error, and says which optional features it turned off and why.