Onboarding Wizard
The Onboarding module provides a step-by-step setup wizard with validation, security hardening, and configuration generation.
Overview
Guide users through initial setup:
- Step-by-Step Flow - 6 built-in steps
- Input Validation - Zod schemas for all inputs
- Security - Path traversal prevention, command whitelisting
- Configuration Generation - Creates config.json, .env, .mcp.json
- Event System - Track progress and errors
Installation
typescript
import {
OnboardingWizard,
createOnboardingWizard,
DEFAULT_STEPS,
WELL_KNOWN_MCP_SERVERS,
SAFE_MCP_COMMANDS,
} from '@aiversum/aiv-agents/onboarding';Quick Start
typescript
const wizard = createOnboardingWizard({
configDir: '~/.aiv',
});
// Track progress
wizard.on('step:complete', ({ step }) => {
console.log(`✓ ${step.name}`);
});
wizard.on('progress', ({ percentage }) => {
console.log(`Progress: ${percentage}%`);
});
// Start the wizard
wizard.start();
// Complete each step
await wizard.completeStep(); // Welcome
await wizard.completeStep({ // Provider
type: 'anthropic',
apiKey: 'sk-ant-...',
});
await wizard.completeStep({ // Workspace
rootPath: '~/aiv-workspace',
createStructure: true,
});
await wizard.completeStep([]); // MCP (skip)
await wizard.completeStep(); // Validate
await wizard.completeStep(); // Complete
// Get result
const result = wizard.getResult();
console.log('Config saved to:', result.configPath);Built-in Steps
| Step | ID | Required | Description |
|---|---|---|---|
| 1 | welcome | Yes | Introduction to AIV |
| 2 | provider | Yes | Configure AI provider |
| 3 | workspace | Yes | Set up workspace |
| 4 | mcp | No | Configure MCP servers |
| 5 | validate | Yes | Test configuration |
| 6 | complete | Yes | Save configuration |
Step Details
1. Welcome
No input required. Displays introduction.
typescript
await wizard.completeStep();2. Provider Configuration
Configure your AI provider:
typescript
// Anthropic
await wizard.completeStep({
type: 'anthropic',
apiKey: 'sk-ant-api03-...',
model: 'claude-sonnet-4-20250514', // Optional
});
// Azure OpenAI
await wizard.completeStep({
type: 'azure',
endpoint: 'https://resource.openai.azure.com',
apiKey: '...', // Optional if using az login
model: 'gpt-4o',
});
// OpenRouter
await wizard.completeStep({
type: 'openrouter',
apiKey: 'sk-or-v1-...',
model: 'anthropic/claude-sonnet-4',
});3. Workspace Configuration
Set up your working directory:
typescript
await wizard.completeStep({
rootPath: '~/aiv-workspace',
vaultPath: '~/aiv-workspace/vault', // Optional
projectsPath: '~/aiv-workspace/projects', // Optional
createStructure: true,
});When createStructure is true, creates:
aiv-workspace/
├── vault/
├── projects/
├── inbox/
└── reports/4. MCP Servers (Optional)
Configure Model Context Protocol servers:
typescript
// Use well-known servers
const servers = wizard.getWellKnownServers();
// [
// { name: 'microsoft-learn', ... },
// { name: 'context7', ... },
// { name: 'filesystem', ... },
// ]
// Enable some
await wizard.completeStep([
{ name: 'context7', enabled: true, command: 'npx', args: ['-y', '@context7/mcp-server'] },
]);
// Or skip
wizard.skipStep('User chose to skip');5. Validation
Tests the configuration:
typescript
await wizard.completeStep();
// Validates:
// - Provider has API key (except Azure with az login)
// - Workspace is configured
// - No duplicate MCP server names6. Complete
Saves configuration files:
typescript
await wizard.completeStep();
// Creates:
// - ~/.aiv/config.json
// - ~/.aiv/.env (with API keys)
// - {workspace}/.mcp.json (if MCP configured)Navigation
Going Back
typescript
if (wizard.goBack()) {
console.log('Returned to previous step');
}Skipping Optional Steps
typescript
const mcpStep = wizard.getCurrentStep();
if (!mcpStep.required) {
wizard.skipStep('User chose to skip MCP setup');
}Aborting
typescript
wizard.abort('User cancelled');
// Check if aborted
if (wizard.isAborted()) {
console.log('Wizard was aborted');
}Resetting
typescript
wizard.reset();
// Returns to initial stateEvents
typescript
wizard.on('step:start', ({ step }) => {
console.log(`Starting: ${step.name}`);
});
wizard.on('step:complete', ({ step, data }) => {
console.log(`Completed: ${step.name}`);
});
wizard.on('step:skip', ({ step, reason }) => {
console.log(`Skipped: ${step.name} - ${reason}`);
});
wizard.on('step:error', ({ step, error }) => {
console.error(`Error in ${step.name}:`, error);
});
wizard.on('validation:start', ({ step }) => {
console.log(`Validating ${step.name}...`);
});
wizard.on('validation:complete', ({ step, result }) => {
if (!result.valid) {
console.error('Validation failed:', result.errors);
}
});
wizard.on('progress', ({ currentStep, totalSteps, percentage }) => {
console.log(`Step ${currentStep + 1}/${totalSteps} (${percentage}%)`);
});
wizard.on('complete', ({ result }) => {
console.log('Wizard complete!');
console.log('Config:', result.configPath);
console.log('Created:', result.createdPaths);
});
wizard.on('abort', ({ reason }) => {
console.log(`Aborted: ${reason}`);
});Custom Steps
Register custom step handlers:
typescript
import { registerStepHandler } from '@aiversum/aiv-agents/onboarding';
registerStepHandler('custom-step', async (step, context, input) => {
// Validate input
if (!input || typeof input !== 'object') {
return {
success: false,
error: new Error('Invalid input'),
warnings: [],
};
}
// Perform step logic
const result = await doSomething(input);
return {
success: true,
data: result,
warnings: [],
};
});
// Use custom steps
const wizard = createOnboardingWizard({
steps: [
...DEFAULT_STEPS.slice(0, 3),
{
id: 'custom-step',
name: 'Custom',
description: 'My custom step',
required: true,
status: 'pending',
order: 3,
},
...DEFAULT_STEPS.slice(3),
],
});Security Features
API Key Validation
typescript
// Format validation
'sk-ant-...' // Anthropic ✓
'sk-or-...' // OpenRouter ✓
'invalid' // Error ✗
// No whitespace
'key with spaces' // Error ✗Path Validation
typescript
// Path traversal blocked
'../../../etc/passwd' // Error ✗
// Null bytes blocked
'/path\0/file' // Error ✗
// Invalid characters blocked
'<script>alert(1)</script>' // Error ✗MCP Command Whitelisting
Only allowed commands:
npxnodepythonpython3uvxdocker
typescript
// Safe
{ command: 'npx', args: ['-y', '@test/mcp'] } // ✓
// Blocked
{ command: '/bin/bash', args: ['-c', 'rm -rf /'] } // Error ✗Environment Variable Validation
typescript
// Name must be uppercase
{ env: { 'API_KEY': 'value' } } // ✓
{ env: { 'apiKey': 'value' } } // Error ✗
// No newlines in values
{ env: { 'KEY': 'value\nmalicious' } } // Error ✗File Permissions
Generated files have secure permissions:
config.json- 0o600 (owner read/write).env- 0o600 (owner read/write)- Config directory - 0o700 (owner only)
State Management
typescript
// Get current state
const state = wizard.getState();
// {
// currentStep: 2,
// totalSteps: 6,
// steps: [...],
// provider: {...},
// workspace: {...},
// mcpServers: [...],
// startedAt: Date,
// }
// Get current step
const step = wizard.getCurrentStep();
// { id: 'provider', name: 'AI Provider', ... }
// Get progress
const progress = wizard.getProgress(); // 33 (percentage)
// Check completion
const complete = wizard.isComplete(); // booleanAPI Reference
See the OnboardingWizard API Reference for complete documentation.
Testing
bash
# Run onboarding module tests
npm test -- --grep "onboarding"
# Test count: 146 tests