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:

  1. Get your device key

    clawee mints ~/.clawee/id_ed25519 the first time it runs; the private key never leaves the client. clawee status guarantees the key exists and prints its fingerprint — or mint it on its own with clawee 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
  2. Send the public key to the host

    Copy that id_ed25519.pub line to the box running claweed — paste it, scp it, however you like. Only the public key travels.

  3. 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 auth is sugar over the full verb, claweed tenant add — renamed from the old tenant add-key spelling, 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 setup no 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 what setup does instead.

Pair from the picker — the knock half of both routes. On the new device just run 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)
  1. Send the request

    Press Enter on the pair row. That queues a knock on the host and the status becomes waiting for approval with 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 unreachable too, as an explicit "try sending my key now" against a verdict that may already be stale — pair never is, because it reads as progress a gateway that can't (or won't) answer cannot make.

  2. 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
  3. 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 revoke on 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.

Revocation now bails to this screen. A device that's already attached when its key is revoked used to keep re-dialing forever behind a silent 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.