bot0 Onboarding Flow
This document describes the desktop app onboarding flow that guides users through setting up bot0 for the first time.
Overview
The onboarding flow is a multi-step wizard that configures:
- Hardware Security - Verifies Secure Enclave / TPM 2.0 availability
- Authentication - Connects to Bytespace account
- Memory Setup - Configures ctx0 (Bytespace-hosted or self-hosted)
- Device Registration - Creates hardware-bound device key
- Identity - Names the daemon
- Model Selection - Chooses AI model and API key source
┌──────────────────────────────────────────────────────────────────┐
│ ONBOARDING FLOW │
│ │
│ ┌─────────┐ ┌──────┐ ┌────────┐ ┌────────┐ ┌─────────┐ │
│ │ Welcome │──▶│ Auth │──▶│ Memory │──▶│ Device │──▶│Identity │ │
│ └─────────┘ └──────┘ └────────┘ └────────┘ └─────────┘ │
│ │ │ │ │
│ │ Hardware │ Self-hosted │ │
│ │ Check │ Sub-flow ▼ │
│ ▼ ▼ ┌─────────┐ │
│ ┌─────────┐ ┌──────────┐ │ Model │ │
│ │ BLOCKED │ │ Supabase │ │Selection│ │
│ │ (no │ │ Setup │ └─────────┘ │
│ │hardware)│ │ (5 steps)│ │ │
│ └─────────┘ └──────────┘ ▼ │
│ ┌─────────┐ │
│ │Complete │ │
│ └─────────┘ │
└──────────────────────────────────────────────────────────────────┘
Step 1: Welcome + Hardware Check
The welcome screen introduces bot0 and immediately checks for hardware security.
Hardware Detection
On mount, the onboarding component calls:
const info = await window.bot0.hardware.checkSupport();
This returns:
interface HardwareInfo { platform: 'macos' | 'windows' | 'linux'; hardwareType: 'secure_enclave' | 'tpm2' | 'vtpm' | 'unsupported'; isSupported: boolean; errorReason?: string; osVersion?: string; chipInfo?: string; }
Supported Devices
| Platform | Hardware | Requirements |
|---|---|---|
| macOS | Secure Enclave | Apple Silicon or T2 chip (2018+) |
| Windows | TPM 2.0 | Most 2016+ PCs, all Windows 11 |
| Linux | TPM 2.0 | TPM hardware + tpm2-tools |
| Cloud VMs | vTPM | AWS Nitro, Azure vTPM, GCP vTPM |
Blocking Unsupported Devices
If hardware security is not available:
- The "Get Started" button is disabled
- An error message explains why
- A list of supported devices is shown
- There is no way to proceed without hardware security
┌──────────────────────────────────────────────────────────────────┐
│ │
│ ✗ Hardware Security Not Available │
│ │
│ bot0 cannot run on this device. │
│ │
│ Your device: MacBook Pro (2015) │
│ Missing: T2 Security Chip or Apple Silicon │
│ │
│ Supported devices: │
│ • Mac with Apple Silicon or T2 chip (2018+) │
│ • Windows PC with TPM 2.0 │
│ • Linux with TPM 2.0 │
│ • Cloud VMs with vTPM (AWS/Azure/GCP) │
│ │
│ [ Get Started ] (disabled) │
│ │
└──────────────────────────────────────────────────────────────────┘
Step 2: Authentication
Users authenticate via Bytespace OAuth flow.
Flow
- User clicks "Sign in with Bytespace"
- Desktop app generates a session ID
- Browser opens to
bytespace.ai/login/desktop?session={id} - User completes authentication in browser
- Desktop app polls for completion
- On success, session token is stored
API Calls
// Start auth flow const result = await window.bot0.bytespace.startAuth(); // { success: true, sessionId: 'abc123' } // Poll for completion const status = await window.bot0.bytespace.pollAuth(sessionId); // { status: 'complete', userId: '...', email: '...' }
State Persistence
On successful auth:
- Session token saved to
~/.bot0/config.json - User ID and email cached for display
authVerifiedflag set for resume logic
Step 3: Memory Setup
Users choose between Bytespace-hosted or self-hosted ctx0.
Options
| Option | Description | Setup Required |
|---|---|---|
| Bytespace Hosted | Managed by Bytespace | None (default) |
| Self-hosted | User's own Supabase project | 5 sub-steps |
Self-hosted Sub-flow
If self-hosted is selected, users go through:
- Create Project - Instructions to create Supabase project
- Credentials - Enter Supabase URL and keys
- Schema Setup - Run SQL migration in Supabase
- Storage Bucket - Create
ctx0-vaultbucket - Data Migration - Optional: migrate from Bytespace
// Save credentials await window.bot0.ctx0.configure({ mode: 'self-hosted', supabaseUrl: '...', supabaseAnonKey: '...', supabaseServiceKey: '...', }); // Test connection await window.bot0.ctx0.testConnection(); // Verify schema await window.bot0.ctx0.verifySchema(); // Verify storage await window.bot0.ctx0.verifyStorage();
Resume Logic
Each sub-step sets a verification flag:
connectionVerified- Credentials workschemaVerified- Tables existstorageVerified- Bucket exists
On app restart, onboarding resumes from the last incomplete step.
Step 4: Device Registration
This step creates a hardware-bound device key and registers it with the proxy.
Why Device Registration?
Even if an attacker extracts the session token via prompt injection:
- They cannot sign requests without the device key
- The device key lives in Secure Enclave / TPM
- It's physically impossible to extract
Flow
- Generate Ed25519 keypair in hardware
- Get device name from system
- Register public key with proxy
- Store device ID locally
// Generate keypair in hardware (private key never leaves chip) const keyPair = await window.bot0.hardware.getOrCreateDevice(); // { deviceId: 'sha256-hash', publicKey: 'base64-encoded' } // Get device name const deviceName = await window.bot0.system.getDeviceName(); // Register with proxy const result = await window.bot0.hardware.registerDevice({ publicKey: keyPair.publicKey, platform: hardwareInfo.platform, hardwareType: hardwareInfo.hardwareType, name: deviceName, }); // Store device ID in config await window.bot0.config.setDeviceRegistered(keyPair.deviceId);
UI Display
┌──────────────────────────────────────────────────────────────────┐
│ │
│ 🔐 Device Security │
│ │
│ ┌────────────────────────────────────────────────────────────┐ │
│ │ ✓ Secure Enclave detected │ │
│ │ Platform: macos │ │
│ │ Chip: Apple M2 Pro │ │
│ └────────────────────────────────────────────────────────────┘ │
│ │
│ Your device will generate a cryptographic keypair stored in │
│ hardware. This key is used to sign all API requests. │
│ │
│ 🔐 Hardware-bound security: Your private key never leaves │
│ the Secure Enclave. Requests are signed locally and verified │
│ by the proxy. │
│ │
│ [ Register Device ] │
│ │
└──────────────────────────────────────────────────────────────────┘
Step 5: Identity
Users name their daemon.
// Save to local config await window.bot0.config.setDaemonName('jarvis'); // Register to ctx0_daemons table (if authenticated) await window.bot0.ctx0.registerDaemon({ name: 'jarvis', default_model: 'claude-opus-4-5-20251101', });
Step 6: Model Selection
Users choose their AI model and API key source.
Model Options
- Claude Opus 4.5 (recommended) - Most capable
- Claude Sonnet 4 - Balanced performance
API Key Options
- Bytespace Credits (default) - Pay-as-you-go through Bytespace
- Own API Key - Use personal Anthropic API key
await window.bot0.config.setModelConfig({ model: 'claude-opus-4-5-20251101', useOwnKey: false, apiKey: undefined, // Only if useOwnKey: true });
Step 7: Complete
Shows a summary of the configuration:
- Daemon name
- Memory hosting (Bytespace or self-hosted)
- Selected model
- API key source
- Device security status
- Bytespace email
User clicks "Start Using bot0" to exit onboarding.
Resume Logic
The onboarding component can resume from any step based on saved progress.
Progress Query
const progress = await window.bot0.onboarding.getProgress();
Returns:
interface OnboardingProgress { daemonName: string | null; hasDaemonName: boolean; hostingMode: 'self-hosted' | 'bytespace' | null; hasCtx0Mode: boolean; hasCredentials: boolean; isConnectionVerified: boolean; isSchemaVerified: boolean; isStorageVerified: boolean; isAuthVerified: boolean; isDeviceRegistered: boolean; bytespaceEmail: string | null; bytespaceUserId: string | null; isDaemonRegistered: boolean; isModelConfigured: boolean; isOnboardingComplete: boolean; }
Resume Step Selection
// Determine which step to resume from if (progress.isOnboardingComplete) → Terminal if (progress.isModelConfigured) → Terminal if (progress.isDaemonRegistered) → model-selection if (progress.isDeviceRegistered) → identity if (progress.isStorageVerified || progress.hostingMode === 'bytespace') → device-register if (progress.isSchemaVerified) → memory-storage if (progress.isConnectionVerified) → memory-schema if (progress.hasCredentials) → memory-credentials if (progress.hasCtx0Mode && hostingMode === 'self-hosted') → memory-create-project if (progress.isAuthVerified) → memory-choice else → welcome
File Locations
| Component | Location |
|---|---|
| Onboarding Component | packages/desktop/src/components/Onboarding/Ctx0Onboarding.tsx |
| Page Router | packages/desktop/src/app/page.tsx |
| Type Definitions | packages/desktop/src/types/global.d.ts |
| IPC Preload | packages/desktop/electron/src/preload.ts |
| IPC Main Handlers | packages/desktop/electron/src/main.ts |
State Storage
| State | Storage Location |
|---|---|
| Session token | ~/.bot0/config.json |
| Device ID | ~/.bot0/config.json |
| Daemon name | ~/.bot0/config.json |
| Model config | ~/.bot0/config.json |
| Onboarding flags | ~/.bot0/config.json |
| Supabase credentials | ~/.ctx0/credentials.json |
| Device private key | Secure Enclave / TPM (hardware) |
| Device public key | Bytespace proxy database |
Sidebar Progress
The sidebar shows progress through main steps:
1. Welcome ✓ (includes hardware check)
2. Authentication ✓
3. Memory ✓ (with sub-steps if self-hosted)
4. Device Security ● (current)
5. Identity
6. Model
Sub-steps for self-hosted:
3. Memory
a. Create Project ✓
b. Credentials ✓
c. Schema Setup ✓
d. Storage Bucket ✓
e. Data Migration ● (current)
Error Handling
Hardware Check Failure
- Display error in welcome step
- Block progression
- Show supported device list
Auth Timeout
- 5-minute polling timeout
- Show "try again" option
Connection Failure
- Display specific error message
- Allow retry without losing credentials
Schema Verification Failure
- Show which tables are missing
- Provide SQL to run again
Device Registration Failure
- Display proxy error
- Allow retry