Actana CLI Pairing
You are on the machine being paired — not on the Core. Somebody there ran actana pair new; since 0.4.3 its handout ends in this very command with every value filled in, so usually you paste rather than type:
actana core pair NAME core.example:8443 XXXX-XXXX --session <id> --fingerprint AA:BB:…
NAME is what this machine will call the Core in its local registry (actana core ls, actana core use) — swap the placeholder, or it registers a Core literally called NAME (recoverable with actana core rm NAME). It is not the --label passed to pair new; that label is what the Core lists in actana pair ls. The address is host:port (or https:// / wss://) — the Core's TLS port, 8443 by default. Plain http:// and ws:// are refused: there is no certificate on a plaintext dial, so there is no fingerprint to check.
Pass --session <id> from the handout — it is not optional; a bare code without it is refused. A single <session>:<XXXX-XXXX> ticket works too; the two ids must agree if you pass both.
Which address to dial
The address you dial must be a name on the Core's certificate — the TLS stack verifies it before anything else happens. Since 0.4.2, ACTANA_PUBLIC_HOST on the Core is a comma-separated list and the certificate carries every name in it, so any entry verifies. Pick the one that routes from this machine:
| You are pairing from | Dial |
|---|---|
| the same host as a published Core port | localhost:8443 |
| inside another container (Docker Desktop) | host.docker.internal:8443 |
| inside the Core's compose network | the service name, core:8443 |
| another machine on the network | the Core's LAN IP or DNS name |
The handout prints one command per configured address, each annotated with which endpoint the credential will register — that comes from the code (pair new --public-host <addr>), not from the address you dial. If the registered endpoint would not route from here, mint a fresh code with the right --public-host rather than pairing a client that then cannot reach its own Core.
Fingerprint, or refuse
--fingerprint is the scriptable path, and the pasted handout command carries it. On a terminal, omit it and the CLI dials with nothing trusted, prints the fingerprint the Core presents, and asks whether it matches pair new. There is no skip flag. Unconfirmed — no flag, no TTY, or you answered no — refuses, and the code is unsent.
What success looks like
At a terminal, a framed confirmation and the next steps:
┌────────────────────────────────────────────────────────────────────────┐
│ │
│ ✓ Paired Core "NAME" │
│ │
│ Endpoint 192.168.1.50:8443 │
│ Sent as laptop — the name this machine gave │
│ Current "NAME" — every later verb talks to this Core │
│ Credential ~/.config/actana/cores/NAME.json (mode 0600) │
│ │
└────────────────────────────────────────────────────────────────────────┘
Next steps
actana core status
Reach the Core and report what it says. …
actana project ls
actana harness ls
actana session start <project> "<prompt>"
actana core shell
The Current row is the one to read on a machine that already had a Core: pairing a second Core does not move the current pointer, and the block then leads with actana core use NAME. On success the Core signs a CSR this machine generated; the private key never leaves this machine, and the issued credential is written at mode 0600 and never printed — not on --verbose, not in an error.
If this registry already has that NAME, the command replaces the stored credential in place — that is how you re-pair after token regenerate. The Panel is the opposite: it refuses a duplicate address before spending the code.
What failure looks like
Each class of refusal gets its own framed explanation at a terminal — what happened, and the exact command that fixes it — and its own exit code for scripts:
| Exit | Failure | The fix it prints |
|---|---|---|
| 10 | Core unreachable | check the address, the port, and the route from this machine |
| 11 | endpoint answered but is not a pairable Core | check you dialled a Core's TLS port |
| 12 | no CA presented | the dial hit something that is not this Core |
| 13 | fingerprint unconfirmed | confirm interactively or pass --fingerprint |
| 14 | fingerprint mismatch | stop; get a current fingerprint from a fresh pair new |
| 15 | TLS hostname mismatch | dial a name that is on the certificate — the table above |
| 16 | certificate invalid | mint a fresh code; the material moved underneath this one |
| 17 | refused (wrong / expired / spent code) | mint a fresh code on the Core |
| 18 | rate limited | wait, then retry with a fresh code |
| 19–21 | rejected / Core error / malformed response | read the Core's log; mint a fresh code |
Down a pipe, output stays the plain lines earlier releases printed — the frame is terminal-only, and behaviour never differs by where output goes.