Reference
Pairing a device
Two things have to line up: a route — burrowee binds your
device to a gateway — and trust — your clawee device key is
enrolled on the box running claweed. The first device on a fresh host has two
routes, and neither needs a device already enrolled: knock from the new device and approve
it on the host itself — the route claweed setup prints — or enroll it
by hand before it ever knocks. Every device after that pairs the same knock, but the
approval comes from an already-enrolled device instead of the host.
Nothing has to exist on the host before that first knock. Since claweed v0.2.16 a knock at a
login that has never enrolled anything is recorded — the tenant directory is created
by it — so claweed devices list on the host shows the request and
claweed devices approve completes it, with no claweed setup or
tenant add run first. Earlier daemons answered that knock unknown user
(the client shows it as user refused by the gateway) and recorded nothing. The gate
is the OS account: a name that is no login on the host is still refused, and creates nothing.
To enroll the first device by hand, skipping the knock:
-
Get your device key
clawee mints
~/.clawee/id_ed25519the first time it runs; the private key never leaves the client.clawee statusguarantees the key exists and prints its fingerprint — or mint it on its own withclawee doctor --fix. Then read the public half:$ clawee status # brings up the chain; mints the key + shows its fingerprint $ clawee doctor --fix # (or) mint / repair the identity key on its own $ cat ~/.clawee/id_ed25519.pub # the public key to enroll
-
Send the public key to the host
Copy that
id_ed25519.publine to the box runningclaweed— paste it,scpit, however you like. Only the public key travels. -
Enroll it on the host
On the claweed box, register the key for your tenant — it enrolls against the invoking OS user (auth/devices/tenant all act on your own host login; there's no per-call user override).
claweed authis sugar over the full verb,claweed tenant add— renamed from the oldtenant add-keyspelling, which the released binary now refuses:$ claweed auth @id_ed25519.pub # from a file — sugar over `tenant add` $ claweed auth "ssh-ed25519 AAAA… " # or paste the key inline $ claweed tenant add @id_ed25519.pub --data-dir <dir> # the full verb — --data-dir is required here
Setting up your own login on a fresh host?
claweed setupno longer imports~/.ssh/authorized_keys— enroll by hand with the steps above, or pair by knock and approve it yourself, on this host. See the daemon's setup section for whatsetupdoes instead.
clawee: an untrusted key can't open a session, so the picker opens as
a pairing form instead — a header naming the gateway, the status, and the
device key fingerprint, with one action on the top row — Enter runs it. What differs between the two routes
is only where the approval happens: on the host itself for the first device on a
fresh host, with nothing else enrolled yet — or from any already-enrolled device for every
device after.
gateway workshop (SHA256:a1b2c3d4)
status not paired
key SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
re-check (c) · re-send key (s) · relays (l) · quit (q)
The form opens before the gateway has answered — the first check runs on this screen rather than on a blank terminal — so the row you see first names the user being checked and offers no action, because there is no answer yet to act on. l and q work throughout; the bar below is replaced by one of the bars on this page as soon as the gateway replies.
status checking… — alice
relays (l) · quit (q)
-
Send the request
Press Enter on the
pairrow. That queues a knock on the host and the status becomeswaiting for approvalwith a running clock. If your ssh-agent holds several keys clawee asks which one to enrol first — pairing enrols exactly one key.claweed only records a knock for a hello that offers exactly one key — a multi-key hello can't say which one you meant to enrol. That's the difference between the form's two typed keys: c re-check asks again with what you already have — with exactly one key resolved that is a single-key hello and can queue a knock just like s; with several keys resolved and none chosen it offers them all, which the gateway refuses without recording anything. s re-send key is the one that always sends exactly one (your chosen key, the lone key you have, or a prompt to pick one) — however many keys your agent holds; whether that becomes a knock still depends on the gateway answering and accepting the user. It's also why Enter does nothing on the waiting screen below: both keys are auth attempts against a gateway that's already answered "queued, waiting for a human," and neither is urgent enough to bind to the key you'd hit by reflex. s is offered on
unreachabletoo, as an explicit "try sending my key now" against a verdict that may already be stale —pairnever is, because it reads as progress a gateway that can't (or won't) answer cannot make. -
Approve it from an enrolled device
On a device that's already paired, approve the pending fingerprint — shown with the knocking machine's self-reported
<user>@<host>device name beside it — from the CLI, or in the picker's devices view (v, on a burrowee route: Enter approves the selected pending key, x revokes):$ clawee devices # pending knocks + enrolled keys $ clawee devices approve [<#>|<fp>] [--label <x>] # bare = first asking, #N = pending index $ clawee devices revoke <fp> # remove a key or drop a knock
-
Back on the new device
The form re-checks itself every 10 seconds and drops into the ordinary picker once the key is trusted. Enter isn't bound here (see above) — the top row reads
waiting…instead of naming a key, and the two real actions stay typed:status waiting for approval ... · 7s re-check (c) · re-send key (s) · relays (l) · quit (q)Automatic polling stops after 10 minutes. A
devices revokeon a pending key merely drops it — there's no "denied" on the wire — so a revoked knock looks exactly like a waiting one until the elapsed clock and the stopped row say otherwise; s is named there, not c, because it's the one action guaranteed to queue the knock again:status waiting for approval · 1m 30s · stopped — s re-send key re-check (c) · re-send key (s) · relays (l) · quit (q)
If the gateway itself can't be reached the form says unreachable (with the reason,
when there is one) and its top row offers continue rather than pairing (a knock can't be queued through a gateway that
never answers). l opens the relay list from any pairing state — relay choice needs
no gateway trust, and a bad relay is the usual reason a gateway looks unreachable:
status unreachable
re-check (c) · re-send key (s) · relays (l) · quit (q)
A gateway holds a list of OS users. The form only runs once one is chosen: with
none set, or when the gateway refuses the user — a hello it rejects before ever looking at a key —
clawee hands you back to the box chooser on that box, where
+ add user picks the right one (<box> has no user — ⏎ on + add user to add one).
Without a terminal the same refusal reads
the gateway refused this OS user, so pairing cannot help; add and select the right one with `clawee gateways user <gateway> add <user>` (or pass -user <name>).
On a daemon at claweed v0.2.16 or later a right name is never refused for having no tenant yet —
the knock is recorded and waits for claweed devices approve on the host — so a refusal
there means the name is no OS login on that box. On an older daemon a login that has never enrolled
anything is refused: enrol it there (claweed setup as that user, or
claweed tenant add) and try again — re-typing a name that was correct all along changes
nothing.
reconnecting… — the
revocation was invisible until the operator happened to look. Closed: three consecutive
auth-class refusals during a captive reconnect now bail out of the retry loop and drop back to
this pairing view instead.
Reference
Devices
Every device that opens a session is a key enrolled on the box running
claweed — trust is per (gateway, user), so the list you see is
always for one tenant. The devices view leads with the numbered pending queue
(devices waiting to be let in), then the enrolled keys; its title reads
devices · <gateway> · <user>. Open it with v in the
session picker, on a burrowee route. It needs a paired device: an
untrusted key can't read the list.
PENDING # FINGERPRINT DEVICE KNOCKS LAST SEEN #1 SHA256:cccc… jc@air 3 2026-07-02T09:00:00Z #2 SHA256:dddd… — 1 2026-08-20T14:02:11Z APPROVED FINGERPRINT LABEL DEVICE ROLE ADDED SHA256:aaaa… laptop jc@Mac-mini owner 2026-07-01T10:00:00Z SHA256:bbbb… — — viewer 2026-06-01T08:00:00Z
DEVICE is <user>@<host>, self-reported by the knocking
machine when it offers its key — evidence for a human decision, never an authorization input;
nothing here or downstream branches on it. — marks a key enrolled or knocking
before this existed. The picker's v devices view leads each row with the same name;
its bar reads move (↑↓) · revoke (x) · back (q).
↑↓ · k/jMove between keys.EnterApprove the selected pending key (optionally labelling it). Confirms first, naming the full fingerprint.xRevoke an enrolled key, or drop a pending knock. Also confirms — and warns separately if the key is this device's, which would lock you out.qBack.The same actions exist as commands, over the same list — use whichever fits:
$ clawee devices # pending knocks + enrolled keys, for the current user $ clawee devices approve [<#>|<fp>] [--label <x>] [--role <role>] # bare = first asking, #N = pending index, or a fingerprint $ clawee devices revoke <fp> # remove a key or drop a knock $ clawee devices role <fp> <owner|viewer> # change an enrolled key's device role
approve prints the resolved fingerprint it just enrolled — quote that line back if
you need to prove which key it was.
The daemon side has the same verbs, host-local, on the box running claweed —
they act on the invoking user only (a cross-user manage is referenced in
claweed's own help text but is not yet built — don't reach for it):
$ claweed devices # pending knocks + enrolled keys, host-local $ claweed devices approve [<#>|<fp>] [--label <x>] [--role <role>] # same semantics as clawee's $ claweed devices revoke <fp> # remove a key or drop a knock $ claweed devices role <fp> <owner|viewer> # change an enrolled key's device role
Every enrolled key has a device role. owner (the default) may take a session's
writer role; viewer may only watch, follow, snapshot and chat — never write. Enrol a
debugging device as a viewer with approve --role viewer, or change an enrolled key with
devices role <fp> viewer on either side. A viewer's take is refused
read-only device: this key is enrolled viewer-only (see
the writer role).
Revoking a device stops it opening new sessions immediately. A session it already has
attached keeps running until its next reconnect — three consecutive auth refusals during that
reconnect now bail the retry loop and drop back to the pairing view
instead of redialing forever behind a silent reconnecting….
Reference
CLI reference
Verbatim help pages for the device verbs, generated by clawee docs / claweed docs from each binary's own help renderer.
clawee devices
enroll + manage device keys on the gateway
clawee devices — enroll + manage device keys on the gateway
Usage:
clawee devices <list|approve|revoke|role>
Commands:
list enrolled keys + the numbered pending queue (numbers are approve
indices)
approve approve a pending knock (bare = the first asking key)
<#> the pending knock at that number in the queue
<fp> the pending knock with that exact SHA256: fingerprint
[--label <label>] label for the enrolled key (single token, [A-Za-z0-9._-]{0,32})
[--role <role>] device role: owner (default) may take a session's writer role;
viewer may only watch, follow, snapshot and chat
revoke drop an enrolled key or a pending knock
<fp>
role set an enrolled key's device role (viewer = watch, follow,
snapshot, chat — never write)
<fp> <owner|viewer>
clawee devices list
enrolled keys + the numbered pending queue (numbers are approve indices)
clawee devices list — enrolled keys + the numbered pending queue (numbers are approve indices) Usage: clawee devices list
clawee devices approve
approve a pending knock (bare = the first asking key)
clawee devices approve — approve a pending knock (bare = the first asking key)
Usage:
clawee devices approve [<#>|<fp>] [flags]
approve
<#> the pending knock at that number in the queue
<fp> the pending knock with that exact SHA256: fingerprint
[--label <label>] label for the enrolled key (single token, [A-Za-z0-9._-]{0,32})
[--role <role>] device role: owner (default) may take a session's writer role;
viewer may only watch, follow, snapshot and chat
clawee devices revoke
drop an enrolled key or a pending knock
clawee devices revoke — drop an enrolled key or a pending knock
Usage:
clawee devices revoke <fp>
revoke
<fp>
clawee devices role
set an enrolled key's device role (viewer = watch, follow, snapshot, chat — never write)
clawee devices role — set an enrolled key's device role (viewer = watch, follow, snapshot, chat — never write)
Usage:
clawee devices role <fp> <owner|viewer>
role
<fp> <owner|viewer>
claweed devices
manage device keys host-locally (invoking user only)
claweed devices — manage device keys host-locally (invoking user only)
Usage:
claweed devices <command>
Commands:
list enrolled keys + the numbered pending queue (numbers are approve
indices)
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of
the user this run is for — under sudo the human who elevated,
otherwise this account (root's own included))
approve approve a pending knock (bare = the first asking key)
<#> the pending knock at that number in the queue
<fp> the pending knock with that exact SHA256: fingerprint
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of
the user this run is for — under sudo the human who elevated,
otherwise this account (root's own included))
[--label <label>] label for the enrolled key ([A-Za-z0-9._-]{0,32})
[--role <role>] device role: owner (default) may take a session's writer role;
viewer may only watch, follow, snapshot and chat
revoke drop an enrolled key or a pending knock
<fp>
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of
the user this run is for — under sudo the human who elevated,
otherwise this account (root's own included))
role set an enrolled key's device role (viewer = watch only, never
write)
<fp> <owner|viewer>
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of
the user this run is for — under sudo the human who elevated,
otherwise this account (root's own included))
claweed devices list
enrolled keys + the numbered pending queue (numbers are approve indices)
claweed devices list — enrolled keys + the numbered pending queue (numbers are approve indices)
Usage:
claweed devices list [flags]
list
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of the
user this run is for — under sudo the human who elevated, otherwise
this account (root's own included))
claweed devices approve
approve a pending knock (bare = the first asking key)
claweed devices approve — approve a pending knock (bare = the first asking key)
Usage:
claweed devices approve [<#>|<fp>] [flags]
approve
<#> the pending knock at that number in the queue
<fp> the pending knock with that exact SHA256: fingerprint
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of
the user this run is for — under sudo the human who elevated,
otherwise this account (root's own included))
[--label <label>] label for the enrolled key ([A-Za-z0-9._-]{0,32})
[--role <role>] device role: owner (default) may take a session's writer role;
viewer may only watch, follow, snapshot and chat
claweed devices revoke
drop an enrolled key or a pending knock
claweed devices revoke — drop an enrolled key or a pending knock
Usage:
claweed devices revoke <fp> [flags]
revoke
<fp>
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of the
user this run is for — under sudo the human who elevated, otherwise
this account (root's own included))
claweed devices role
set an enrolled key's device role (viewer = watch only, never write)
claweed devices role — set an enrolled key's device role (viewer = watch only, never write)
Usage:
claweed devices role <fp> <owner|viewer> [flags]
role
<fp> <owner|viewer>
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of the
user this run is for — under sudo the human who elevated, otherwise
this account (root's own included))
claweed tenant add
enroll a trust key for YOURSELF
claweed tenant add — enroll a trust key for YOURSELF
Usage:
claweed tenant add <pubkey|@file> [flags]
add
<pubkey> the public key line itself
@<file> read the public key from the named file
[--data-dir <dir>] claweed data dir (required; `claweed auth` resolves a default)
claweed auth
pair a device key (sugar over tenant add)
claweed auth — pair a device key (sugar over tenant add)
Usage:
claweed auth <pubkey|@file> [flags]
auth
<pubkey|@file>
[--data-dir <dir>] claweed data dir (default: installed boot unit, then the tree of the
user this run is for — under sudo the human who elevated, otherwise
this account (root's own included))
See the full generated references: clawee CLI reference · claweed CLI reference.
Docs synced 2026-10-17 against clawee v0.3.46 · claweed v0.3.29 — a partial pass over the guard-aware update and restart, the tab title that shows a session asking for you, and the installer exit codes, on top of the v0.3.42 catch-up. See docs_sync.json for what is not covered.