Skip to content

Remote access ​

The connection token ​

Every client presents the token to connect. Set it one of three ways:

FlagKeyDoes
--connection-token-file <path>connectionTokenFileRead the token from the file. Writes a new one, mode 0600, if it is missing
--connection-token <secret>connectionTokenUse this token
--without-connection-tokenwithoutConnectionTokenAccept any connection

With none of them, the host accepts loopback only.

Listen on the network ​

bash
ahpd start --host 0.0.0.0 --connection-token-file ~/.config/ahpd/connection-token

DANGER

--host 0.0.0.0 refuses to start without a token. A client with the token can run anything the agents can run on this machine.

To reach it asAdd
Another IP or name, such as http://203.0.113.5:9187--origin http://203.0.113.5:9187 (key origins, a list)
An https name for sign-in--resource https://ahpd.example.com/
A public URL with no open portthe @ahpd/tunnel-devtunnel plugin

For a person's own token instead of the shared one, see Users.

Test a token ​

A plain GET /?tkn=<token> on the daemon's port tells a client whether the host accepts the token. A refused token gets 401 with A connection token is required, the same sentence the WebSocket handshake gives. An accepted token gets 426, because the port speaks AHP over WebSocket. A host with no token answers 426 to every request.

bash
curl -i "http://127.0.0.1:9187/?tkn=$(cat ~/.config/ahpd/connection-token)"

Both answers carry Access-Control-Allow-Origin: *, so a page on any origin can read them. From a browser, put the token in ?tkn= and not in a header, so the request needs no preflight. /api and /v1 keep their own answers and their origins check.

HTTP API ​

Turn it on to run the ahpd commands over HTTP:

json
{ "http": true }
json
{ "http": { "port": 9188, "host": "127.0.0.1" } }

With true the API is at http://127.0.0.1:9187/api, beside the WebSocket. The startup log says where: http on http://127.0.0.1:9187/api. It needs a connection token or a user directory.

bash
curl http://127.0.0.1:9187/api/status -H "Authorization: Bearer $TOKEN"

A refusal says why:

HTTP/1.1 403 Forbidden
{ "message": "ada may not config:read here" }

GET /api/cli-manifest lists every command, with no token. The model proxy is served beside it at /v1.

Who may run what ​

The deployment's connection token may run everything. A person's token needs the grant:

CommandNeeds
status, plugin listconfig:read
configconfig:write
user listuser:read, role:read
user add, user rm, user token, user memberuser:write
team list / team add, team rmteam:read / team:write
project list / project add, project rmproject:read / project:write
usageown pools; any pool with usage:read
vault listconfig:read for host:; team:write for the team's; own
vault set, vault deleteconfig:write for host:; team:write for the team's; own
automation export / automation importautomation:list / automation:create
plugin install, remove, update, config, enable, disable, restartdeployment token only

One thing a remote client reads is not a command and so has no row here: the account each agent bills to, which is a value of the root config rather than an ahpd verb, needs account:read and is shown to nobody else - HOST.md has that row.

Browser safety ​

A request must have one of the daemon's own names as its Host, and the same for its Origin when a browser sends one. The names are the loopback names, the bound address, the resource host and each entry in origins. A body must be application/json; anything else gets 415.

Run commands from another machine ​

bash
ahpd --remote http://203.0.113.5:9187 --token "$TOKEN" status
ahpd --remote http://203.0.113.5:9187 --token-file ~/token plugin list
AHPD_TOKEN="$TOKEN" ahpd --remote http://203.0.113.5:9187 restart

The remote daemon must have the HTTP API on. Help, completion and --json work as at its own terminal. start and stop stay local.

The command list is cached in ~/.cache/ahpd/remote. --refresh fetches it again.

WARNING

Plain http:// to a host that is not loopback sends the token in the clear. Use https:// or a tunnel.