Skip to content

First Boot

Current ISO validation note: the live ISO path is moving to a QML installer followed by post-install /setup in the Clawdie controlplane. Provider keys and Telegram are no longer install-time requirements. The setup.txt flow below documents the older non-interactive contract and will be rewritten after the current ISO live-install validation completes.

The first-boot model below is intentionally small. You edit a single first-boot setup file (setup.txt), flash the USB, boot the machine, and the installer reads your file on first start. No interactive out-of-the-box wizard, no autogenerated secrets you have to write down later.

The first-boot setup file is versioned. If you do not set these yourself, the installer fills safe defaults:

SETUP_SCHEMA_VERSION=1
ISO_RELEASE=v0.10.0
ISO_GIT_COMMIT=
  • SETUP_SCHEMA_VERSION tracks the file format the installer understands
  • ISO_RELEASE records which Clawdie release the install media came from
  • ISO_GIT_COMMIT is optional exact build provenance
  • The Clawdie ISO (tags)
  • A USB stick (16 GB+)
  • A flashing tool (dd, Etcher, Rufus — your call)
  • An OpenRouter account (the recommended bootstrap path; you can switch to direct provider keys later)
  • A Telegram account and a bot token from @BotFather
  • Your Telegram numeric user ID from @userinfobot

If you do not know your disk names, pool layout, PF-facing interface names, or whether the machine already contains a Clawdie install, run inspect first from the live environment:

Terminal window
./scripts/inspect-system.sh --output /path/to/writable/media

On a full Clawdie repo checkout, npm run inspect -- --output ... is just a convenience wrapper around the same shell script.

To write the suggested install/storage values straight back into your first-boot setup file:

Terminal window
./scripts/inspect-system.sh \
--output /path/to/writable/media \
--apply-setup /path/to/writable/media/setup.txt

That only fills blank or missing fields. It does not overwrite values you already chose explicitly.

To populate the hardware contract file directly:

Terminal window
./scripts/inspect-system.sh \
--output /path/to/writable/media \
--apply-system-env /path/to/writable/media/system.env

That fills blank or missing hardware fields in system.env such as:

  • SYSTEM_SCHEMA_VERSION
  • NETWORK_EXTERNAL_IF
  • NETWORK_INTERNAL_IF
  • TAILSCALE_IF
  • ZFS_POOL
  • ZFS_LAYOUT
  • ZFS_DATA_DISKS
  • ZFS_HOT_SPARES
  • ZFS_DISKS
  • ZFS_SPARE_DISKS
  • ZFS_PREFIX
  • GPU_DEVICE
  • SND_DEVICE

That writes:

  • system.txt — a human summary
  • system.env — hardware contract values the installer can use directly
  • inspect-facts.env — richer machine-readable inspect metadata
  • suggested-setup.txt — lines you can copy back into setup.txt
  • raw artifacts such as dmesg.txt, ifconfig.txt, zpool-status.txt, zfs-list.txt, and pf-interfaces.txt

The summary includes:

  • detected disk device names
  • observed ZFS pools, layouts, and datasets
  • suggested INSTALL_MODE
  • suggested ZFS_LAYOUT, ZFS_DATA_DISKS, and ZFS_HOT_SPARES
  • detected interface names you can later reuse for PF/network setup

Open the first-boot setup file (setup.txt) in a text editor. The required cognitive surface is four lines:

OPENROUTER_API_KEY=sk-or-v1-...
TELEGRAM_BOT_TOKEN=123456:AA...
TELEGRAM_ADMIN_ID=12345678
ASSISTANT_NAME=Atlas

That is the minimum for a working install. Everything else in the first-boot setup file is either prefilled with a sensible default or optional. Leave any line you don’t care about blank — the installer will fall back.

LineWhat it controls
OPENROUTER_API_KEYThe LLM provider used for chat and compaction.
TELEGRAM_BOT_TOKENThe bot identity your assistant runs as.
TELEGRAM_ADMIN_IDThe one Telegram account that can talk to it as operator.
ASSISTANT_NAMEWhat your assistant calls itself in chat. It is display-only and does not rename shared DBs, datasets, or the service account. Blank → Clawdie.

You don’t have to fill these in. They exist because you might want them later or because some installs need them on day one.

INSTALL_MODE=auto
  • auto — detect an existing install and choose fresh vs upgrade
  • fresh — fail if an existing install is detected
  • upgrade — require an existing install and upgrade it in place
  • rescue — require an existing install and attempt recovery/repair

auto is the default and the right starting point for most operators. It also supports reinstall, upgrade, and rescue flows when paired with system.env and existing ZFS metadata.

If you ran inspect first, system.txt will suggest the install mode it thinks fits the machine right now.

PROFILE=balanced

economy, balanced, or quality. Maps to a coordinated bundle of chat + fallback + compaction models. balanced is the prefilled default. Switch only if you have a reason.

TIMEZONE=Europe/Ljubljana
HOSTNAME=

TIMEZONE defaults to UTC. HOSTNAME defaults to clawdie unless you set it explicitly. It does not derive from ASSISTANT_NAME.

ZFS_POOL=zroot
ZFS_LAYOUT=single
ZFS_DATA_DISKS=1
ZFS_HOT_SPARES=0
ZFS_PREFIX=clawdie-runtime

These fields declare the intended storage shape.

  • ZFS_POOL — pool name, usually zroot
  • ZFS_LAYOUTsingle, mirror, raidz1, or raidz2
  • ZFS_DATA_DISKS — number of disks in the main data layout
  • ZFS_HOT_SPARES — standby disks reserved as hot spares
  • ZFS_PREFIX — dataset root for the install

Defaults:

  • single is the default because it matches the simplest one-disk install
  • single is not the recommended long-running layout
  • raidz1 is the recommended durable multi-disk shape once the operator opts in

Examples:

# Simple one-disk install
ZFS_LAYOUT=single
ZFS_DATA_DISKS=1
ZFS_HOT_SPARES=0
# Three-disk raidz1
ZFS_LAYOUT=raidz1
ZFS_DATA_DISKS=3
ZFS_HOT_SPARES=0
# Four disks total: 3 in raidz1, 1 hot spare
ZFS_LAYOUT=raidz1
ZFS_DATA_DISKS=3
ZFS_HOT_SPARES=1

The installer derives full dataset paths from these values. You do not type raw dataset paths into the first-boot setup file.

These storage declarations are also part of the long-term upgrade contract. The installer can later compare:

  • setup.txt operator intent
  • system.env hardware intent
  • persisted ZFS dataset metadata

For advanced operators, that metadata lives as ZFS user properties on the root dataset <ZFS_POOL>/<ZFS_PREFIX>, using keys such as:

  • org.clawdie:install-uuid
  • org.clawdie:setup-schema
  • org.clawdie:system-schema
  • org.clawdie:iso-release
  • org.clawdie:iso-commit
  • org.clawdie:assistant-name
  • org.clawdie:hostname
  • org.clawdie:telegram-admin-hash
  • org.clawdie:zfs-layout
  • org.clawdie:zfs-data-disks
  • org.clawdie:zfs-hot-spares

This is deliberate: the upgrade fingerprint lives with the data, survives reflash, and can be inspected with native zfs get.

If you ran inspect first, it will already have written suggested storage lines based on:

  • detected disk count
  • observed ZFS pool topology
  • existing pool/dataset state when present
OPERATOR_EMAIL=you@example.com
OPERATOR_PASSWORD=...

Optional. If you set both, the dashboard is preconfigured. If you leave them blank, the dashboard waits until you run npm run set-operator -- <email> from the running system. Telegram is your operator interface in the meantime.

Plaintext warning: OPERATOR_PASSWORD lives in plaintext on the install media until you reformat it. The installer will warn you about this in the post-install summary. Reformat the USB before storing it or handing it to anyone else.

For installs you don’t sit at the console for:

SSH_AUTHORIZED_KEY=ssh-ed25519 AAAAC3... you@laptop
CLAWDIE_USER_PASSWORD=

SSH_AUTHORIZED_KEY is the recommended way. Public keys are not secrets, so plaintext on the USB is fine. When set, the installer enables key-only SSH for the service user and disables password SSH.

CLAWDIE_USER_PASSWORD is a fallback for console login or sudo, used only if no SSH key is provided. Same plaintext warning as above. There is no ROOT_PASSWORD field — root login is locked by design. Use sudo from the service user.

The flashed USB exposes a writable FAT32 config surface. Edit these files there:

  • setup.txt
  • system.env

The installer reads those files on first boot.

Why this path works:

  • it is writable from Windows, macOS, Linux, and FreeBSD
  • it supports long API keys without console typing
  • it works with the inspect loop naturally
  • it matches the ISO repo’s existing “editable config on removable media” direction without requiring a second USB

Operator flow:

  1. Flash the USB.
  2. Reinsert it on your normal computer.
  3. Open the writable config surface.
  4. Edit setup.txt.
  5. Optionally leave system.env blank and let inspect populate it.
  6. Boot the target machine from that USB.

The installer treats:

  • setup.txt as operator intent
  • system.env as hardware intent

Both files are versioned and can be compared against persisted ZFS metadata during later upgrade and rescue flows.

  1. Plug the USB into the target machine.
  2. Power on. Boot from USB (BIOS/UEFI key varies by hardware).
  3. The installer reads the first-boot setup and proceeds without prompting.

Expect first boot to take several minutes — the installer provisions databases, jails, and copies skills. The post-install summary tells you what’s ready and surfaces any warnings (plaintext passwords, unset optional fields).

Open Telegram, find the bot you registered, send /start. If your TELEGRAM_ADMIN_ID matches, you’re talking to your operator channel.

Set dashboard credentials (if you skipped them)

Section titled “Set dashboard credentials (if you skipped them)”

If you left OPERATOR_EMAIL / OPERATOR_PASSWORD blank in the first-boot setup:

Terminal window
npm run set-operator -- you@example.com

You’ll be prompted for a password (twice, no echo). The dashboard becomes available afterwards. This is first-set only — to rotate a password later, use the dashboard’s change-password flow.

OpenRouter is the bootstrap path, not a permanent commitment. To move chat to a direct provider:

  • Per chat: /model in Telegram lets you swap provider/model for a single chat.
  • System-wide: set DEEPSEEK_API_KEY in provider.env. The agent uses DeepSeek by default. Provider Fallback.

If your first-boot setup contained any password fields (OPERATOR_PASSWORD, CLAWDIE_USER_PASSWORD), the installer did not delete the file (by design — operators have lost installs to overzealous auto-wipes). Reformat the USB once you’ve confirmed the install is healthy.

Check the first-boot log and progress files first:

Terminal window
tail -100 /var/log/${AGENT_NAME}-firstboot.log
cat /var/log/${AGENT_NAME}-firstboot.progress

If the install stopped after a named setup step, resume from that step:

Terminal window
cd /home/${AGENT_NAME}/clawdie-ai
just install-from <step>

For a full post-install verification pass, use the Fresh install checklist.

Use INSTALL_MODE to choose how the installer treats an existing system:

  • auto — detect the existing install and choose the safest path
  • fresh — fail if an existing install is detected
  • upgrade — require an existing install and upgrade it in place
  • rescue — require an existing install and attempt recovery/repair

Keep backups before upgrade or rescue work, especially when changing storage layout values.