Access & the raw API
Log in, switch between instances with contexts, manage personal access tokens, and call any API route directly with alaf server api.
These commands are how the CLI knows which Alaf Server it's talking to and who you are — plus an escape
hatch (alaf server api) for reaching any route that doesn't have its own command yet.
Where auth lives
The CLI keeps its settings in ~/.alaf server/config.json (mode 0600). That file holds one or more named
contexts — each pins an API URL, a dashboard URL, and a personal access token (a opsh_pat_… string).
One context is active at a time; every authenticated command reads from it. The default context is called
default and points at your local instance (http://localhost:4000).
JSON output
--json is a global flag — put it before the subcommand (alaf server --json token list). In JSON mode the
data is written to stdout as JSON while status messages go to stderr, so a piped stream stays clean. Setting
ALAFSERVER_JSON=1 in the environment does the same thing. alaf server api always prints the response body.
alaf server login
Authenticate against an instance and save the token into a context. Run with no --token and it opens the
dashboard's Settings page — where Personal Access Tokens live — and waits for you to paste one; pass
--token to log in non-interactively (CI, scripts). The token is validated against the API before it's stored, and it must
start with opsh_pat_.
# Interactive — opens the dashboard, prompts for a pasted token
alaf server login
# Non-interactive — against a remote self-hosted instance, stored as a named context
alaf server login \
--token opsh_pat_xxxxxxxx \
--api-url https://alaf server.example.com \
--dashboard-url https://alaf server.example.com \
--context prod| Flag | Purpose | Default |
|---|---|---|
--token <token> | Personal access token (opsh_pat_…) for non-interactive login. | (prompted) |
--api-url <url> | API base URL to authenticate against. | http://localhost:4000 |
--dashboard-url <url> | Dashboard base URL (used to open the token page). | http://localhost:3001 |
--context <name> | Name of the context to store this login under. | default |
Can't reach the API?
If login reports it couldn't reach the API, the host in --api-url isn't responding. Point it at the right
instance — for a remote self-hosted box that's the same URL you open in the browser.
alaf server logout
Remove the stored token from a context. The endpoints stay saved, so a later login just re-adds the token.
alaf server logout # active context
alaf server logout --context prod # a specific one| Flag | Purpose | Default |
|---|---|---|
--context <name> | Log out of a specific context. | (active context) |
alaf server context
Manage the named connections in ~/.alaf server/config.json. This is pure local config editing — no API calls.
Use it to keep several instances side by side (local, staging, production) and switch between them. Alias:
alaf server ctx. Running it bare prints the active context and the full list (the active row is starred).
alaf server context # show active + list all
alaf server context use prod # switch the active context| Subcommand | Purpose |
|---|---|
list (alias ls) | List configured contexts. |
use <name> | Switch the active context. |
add <name> | Create or update a context's endpoints/token. |
rm <name> (alias remove) | Remove a context (can't remove the active one — switch away first). |
The list shows one row per context: current (* marks the active one), name, apiUrl,
dashboardUrl, and auth (token when a token is stored, - when not).
context add
Register an instance without logging in interactively. add only writes config — use login when you want
the token checked against the API first.
alaf server context add staging \
--api-url https://staging.example.com \
--dashboard-url https://staging.example.com \
--token opsh_pat_xxxxxxxx \
--use| Flag | Purpose |
|---|---|
--api-url <url> | API base URL. |
--dashboard-url <url> | Dashboard base URL. |
--token <token> | Personal access token to store. |
--use | Switch to this context after adding. |
alaf server token
Create and manage the personal access tokens that authenticate the CLI and the API. Tokens are self-scoped — every call operates on your own tokens. In the dashboard these live under Settings → Personal Access Tokens.
| Subcommand | Purpose |
|---|---|
list | List your personal access tokens. |
create <name> | Mint a new token (the secret is shown once). |
revoke <id> | Revoke one of your tokens. |
token create
# A full-access, non-expiring token
alaf server token create "laptop"
# A read-only token that expires in 30 days
alaf server token create "ci-reader" --read-only --expires 30
# Scope a token to one project with specific permissions (repeatable)
alaf server token create "deploy-bot" --grant project:abc123:read,write| Flag | Purpose | Default |
|---|---|---|
--read-only | Reject mutation methods (POST/PUT/PATCH/DELETE). | off |
--expires <days> | Expire after N days (1–365); omit for a non-expiring token. | never |
--grant <type:id:perms> | Scope the token to a resource. Repeatable. Format type:id:perm1,perm2, e.g. project:abc123:read,write. | (full access) |
Copy the secret immediately
token create prints the full opsh_pat_… secret once and never again. token list only ever shows a
short prefix. If you lose it, revoke the token and mint a new one.
The list table shows: id, name, prefix, readOnly, scoped, expires, lastUsed, and revoked.
Pass a token's id (they look like pat_…) to revoke:
alaf server token list
alaf server token revoke pat_abc123alaf server api
The escape hatch. Make an authenticated request to any API route using the active context's token —
much like gh api. This is what keeps the CLI small: anything without a dedicated command (audit log,
one-off reads, routes added after your CLI version) is still reachable here.
The <path> argument is relative to /api, so alaf server api /projects calls
<your-api-url>/api/projects. The method defaults to GET, or POST when you pass --data.
# GET a collection
alaf server api /projects
# GET a single resource
alaf server api /deployments/dep_abc123
# POST with a JSON body (method defaults to POST when --data is given)
alaf server api /domains -d '{"projectId":"proj_123","hostname":"app.example.com"}'
# DELETE with an explicit method
alaf server api /tokens/pat_abc123 -X DELETE
# Add query parameters (repeatable)
alaf server api /domains -q projectId=proj_123| Flag | Purpose | Default |
|---|---|---|
-X, --method <method> | HTTP method. | GET, or POST when --data is set |
-d, --data <json> | Request body as a JSON string. | (none) |
-q, --query <kv...> | Query parameter key=value. Repeatable. | (none) |
The response body is printed to stdout — pretty-printed when it's JSON, raw otherwise. On a non-2xx
response the body is still printed and the command exits non-zero, so you can pipe it into jq and still
detect failures in scripts.
Which routes exist?
Browse the API reference for paths, methods, and required permissions. The resource commands
(project, service, domain, and friends) wrap the common ones in a friendlier
form — reach for alaf server api when there's no dedicated command.