oneie
Version:
Build apps, websites, and AI agents in English. Zero-interaction setup for AI agents (Claude Code, Cursor, Windsurf). Download to your computer, run in the cloud, deploy to the edge. Open source and free forever.
631 lines (492 loc) • 13.6 kB
Markdown
title: Agent Onboard Usage
dimension: knowledge
category: agent-onboard-usage.md
tags: agent, ai, ai-agent, backend, installation, testing
related_dimensions: events, groups, people, things
scope: global
created: 2025-11-03
updated: 2025-11-03
version: 1.0.0
ai_context: |
This document is part of the knowledge dimension in the agent-onboard-usage.md category.
Location: one/knowledge/agent-onboard-usage.md
Purpose: Documents agent-onboard usage guide
Related dimensions: events, groups, people, things
For AI agents: Read this to understand agent onboard usage.
# Agent-Onboard Usage Guide
**Version:** 1.0.0
**Status:** Production Ready
**Purpose:** How to use the agent-onboard system
## Quick Start
### From CLI (Recommended)
```bash
npx oneie init
```
The CLI will:
1. Prompt for user details
2. Call the onboarding mutation
3. Display analysis results
4. Write files to installation folder
5. Present feature recommendations
6. Hand off to Claude Code
### From Convex Console (Testing)
```javascript
// backend/convex/mutations/onboarding.ts
await ctx.runMutation(api.mutations.onboarding.analyzeWebsite, {
name: "Tom O'Connor",
organizationName: "ONE Platform",
websiteUrl: "https://one.ie",
email: "tom@one.ie"
});
```
## API Reference
### analyzeWebsite Mutation
**Purpose:** Main entry point for onboarding analysis
**Input:**
```typescript
{
name: string; // User's full name
organizationName: string; // Organization name
websiteUrl: string; // Website to analyze
email: string; // User's email
installationSlug?: string; // Optional custom slug
}
```
**Output (Success):**
```typescript
{
success: true;
data: {
installationSlug: string; // Generated slug
analysis: {
url: string;
brand: BrandIdentity;
features: DetectedFeatures;
businessModel: string;
analyzedAt: number;
};
ontology: {
document: OntologyDocument;
markdown: string;
};
brandGuide: {
guide: BrandGuide;
markdown: string;
};
recommendations: FeatureRecommendation[];
};
}
```
**Output (Error):**
```typescript
{
success: false;
error: string; // Error message
}
```
### createOnboardingGroup Mutation
**Purpose:** Create initial group for new organization
**Input:**
```typescript
{
name: string; // Group name
slug: string; // URL slug
ownerEmail: string; // Owner email
plan?: 'starter' | 'pro' | 'enterprise';
}
```
**Output:**
```typescript
{
success: boolean;
groupId?: Id<"groups">; // If successful
error?: string; // If failed
}
```
### checkSlugAvailability Query
**Purpose:** Check if installation slug is available
**Input:**
```typescript
{
slug: string; // Desired slug
}
```
**Output:**
```typescript
{
available: boolean;
slug: string;
}
```
## Service Layer API
### Website Analyzer
```typescript
import { runWebsiteAnalysis } from '../services/websiteAnalyzer';
const analysis = await runWebsiteAnalysis('https://example.com');
// Returns:
{
url: string;
brand: {
colors: { primary, secondary, accent? };
logo: { url, format };
fonts: { heading, body };
voice: { tone, audience };
};
features: {
contentTypes: string[];
monetization: string[];
community: string[];
techStack: { frontend?, backend?, hosting? };
};
businessModel: string;
analyzedAt: number;
}
```
### Ontology Generator
```typescript
import { runOntologyGeneration } from '../services/ontologyGenerator';
const { document, markdown } = await runOntologyGeneration(
analysis,
'Organization Name'
);
// document: OntologyDocument with 6 dimensions
// markdown: Ready-to-write string
```
### Brand Guide Generator
```typescript
import { runBrandGuideGeneration } from '../services/brandGuideGenerator';
const { guide, markdown } = await runBrandGuideGeneration(
analysis.brand,
'Organization Name',
'https://example.com'
);
// guide: BrandGuide object
// markdown: Ready-to-write string
```
### Feature Recommender
```typescript
import { runFeatureRecommendation } from '../services/featureRecommender';
const recommendations = await runFeatureRecommendation(
analysis.features
);
// Returns: FeatureRecommendation[]
// Each with: feature, reason, priority
```
## Common Workflows
### Workflow 1: Complete Onboarding
```typescript
// 1. Analyze website
const result = await ctx.runMutation(
api.mutations.onboarding.analyzeWebsite,
{
name: "Jane Doe",
organizationName: "Acme Corp",
websiteUrl: "https://acme.com",
email: "jane@acme.com"
}
);
if (!result.success) {
console.error(result.error);
return;
}
// 2. Write files to installation folder
const { installationSlug, ontology, brandGuide } = result.data;
await writeFile(
`/${installationSlug}/knowledge/ontology.md`,
ontology.markdown
);
await writeFile(
`/${installationSlug}/knowledge/brand-guide.md`,
brandGuide.markdown
);
// 3. Create group
await ctx.runMutation(
api.mutations.onboarding.createOnboardingGroup,
{
name: "Acme Corp",
slug: installationSlug,
ownerEmail: "jane@acme.com",
plan: "pro"
}
);
// 4. Update .onboarding.json
await writeFile('.onboarding.json', JSON.stringify({
status: "features_presented",
...result.data
}, null, 2));
```
### Workflow 2: Check Availability First
```typescript
// 1. Generate slug from org name
const slug = organizationName
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-');
// 2. Check if available
const { available } = await ctx.runQuery(
api.queries.onboarding.checkSlugAvailability,
{ slug }
);
if (!available) {
// Prompt for alternative slug
// Or append number: 'acme-corp-2'
}
// 3. Proceed with analysis
```
### Workflow 3: Re-analyze Existing Installation
```typescript
// 1. Get current analysis from .onboarding.json
const current = JSON.parse(
await readFile('.onboarding.json', 'utf8')
);
// 2. Re-analyze (e.g., after website update)
const updated = await ctx.runMutation(
api.mutations.onboarding.analyzeWebsite,
{
...current.user,
...current.organization,
installationSlug: current.organization.slug
}
);
// 3. Compare changes
const changes = compareAnalysis(current.analysis, updated.data.analysis);
// 4. Optionally regenerate files
if (changes.brand.colorsChanged) {
await writeFile(
`/${current.organization.slug}/knowledge/brand-guide.md`,
updated.data.brandGuide.markdown
);
}
```
## Error Handling
### Website Not Accessible
```typescript
try {
const result = await analyzeWebsite({...});
} catch (error) {
if (error._tag === 'WebsiteNotAccessible') {
console.error(`Cannot access ${error.url}: ${error.reason}`);
// Offer manual input option
}
}
```
### Invalid URL
```typescript
if (result.success === false && result.error.includes('invalid')) {
console.error('Invalid website URL. Please check and try again.');
// Prompt for corrected URL
}
```
### Slug Already Exists
```typescript
const groupResult = await createOnboardingGroup({...});
if (!groupResult.success) {
if (groupResult.error.includes('already exists')) {
// Generate alternative: 'acme-corp-2'
// Or prompt user for custom slug
}
}
```
## File Structure After Onboarding
```
/
├── .onboarding.json # Onboarding state
├── {installation-slug}/
│ ├── knowledge/
│ │ ├── ontology.md # Generated ontology
│ │ └── brand-guide.md # Brand identity
│ ├── groups/
│ │ └── {org-slug}/
│ │ └── README.md # Organization overview
│ └── things/
│ └── vision.md # Optional custom vision
└── .env.local # Updated with brand colors
```
## Environment Variables
### Generated in .env.local
```bash
# Organization
INSTALLATION_NAME="{installation-slug}"
ORG_NAME="{Organization Name}"
ORG_SLUG="{installation-slug}"
ORG_OWNER_EMAIL="{email}"
ORG_OWNER_NAME="{name}"
# Branding (from analysis)
BRAND_PRIMARY_COLOR="{primary-color}"
BRAND_SECONDARY_COLOR="{secondary-color}"
BRAND_LOGO_URL="{logo-url}"
# Website
ORIGINAL_WEBSITE="{analyzed-website}"
```
## Testing
### Unit Test Example
```typescript
import { describe, it, expect } from 'vitest';
import { analyzeWebsite } from './websiteAnalyzer';
describe('Website Analyzer', () => {
it('should extract brand colors', async () => {
const result = await runWebsiteAnalysis('https://example.com');
expect(result.brand.colors.primary).toMatch(/^#[0-9A-F]{6}$/i);
expect(result.brand.colors.secondary).toMatch(/^#[0-9A-F]{6}$/i);
});
it('should detect content types', async () => {
const result = await runWebsiteAnalysis('https://blog-site.com');
expect(result.features.contentTypes).toContain('blog');
});
});
```
### Integration Test Example
```typescript
import { convexTest } from 'convex-test';
import { describe, it, expect } from 'vitest';
import schema from '../schema';
describe('Onboarding Flow', () => {
it('should complete full onboarding', async () => {
const t = convexTest(schema);
// 1. Analyze website
const result = await t.mutation(api.mutations.onboarding.analyzeWebsite, {
name: 'Test User',
organizationName: 'Test Org',
websiteUrl: 'https://test.com',
email: 'test@test.com'
});
expect(result.success).toBe(true);
expect(result.data.installationSlug).toBe('test-org');
// 2. Verify ontology generated
expect(result.data.ontology.document.ontology.groups).toBeDefined();
expect(result.data.ontology.document.ontology.things.length).toBeGreaterThan(0);
// 3. Create group
const groupResult = await t.mutation(
api.mutations.onboarding.createOnboardingGroup,
{
name: 'Test Org',
slug: result.data.installationSlug,
ownerEmail: 'test@test.com'
}
);
expect(groupResult.success).toBe(true);
});
});
```
## Performance Tips
### 1. Parallel Extraction
The website analyzer already runs extraction in parallel:
```typescript
const [colors, logo, fonts, voice, ...] = yield* _(Effect.all([
extractColors(html),
extractLogo(html),
extractFonts(html),
// ... all run concurrently
]));
```
### 2. Caching
For repeated analyses of the same website:
```typescript
// Cache analysis results
const cacheKey = `analysis:${websiteUrl}`;
const cached = await redis.get(cacheKey);
if (cached && !forceRefresh) {
return JSON.parse(cached);
}
const analysis = await runWebsiteAnalysis(websiteUrl);
await redis.setex(cacheKey, 3600, JSON.stringify(analysis));
```
### 3. Batching
For multiple organizations:
```typescript
const analyses = await Promise.all(
organizations.map(org =>
runWebsiteAnalysis(org.websiteUrl)
)
);
```
## Customization
### Custom Business Model Detection
```typescript
// In ontologyGenerator.ts
const generateBusinessDescription = (analysis: WebsiteAnalysis): string => {
// Add custom logic
if (analysis.features.contentTypes.includes('courses') &&
analysis.features.monetization.includes('subscriptions')) {
return 'Educational SaaS platform';
}
// ... existing logic
};
```
### Custom Feature Recommendations
```typescript
// In featureRecommender.ts
if (detected.contentTypes.includes('podcast')) {
recommendations.push({
feature: FEATURES['podcast-platform'],
reason: 'Detected podcast content',
priority: 'high'
});
}
```
### Custom Ontology Mapping
```typescript
// In ontologyGenerator.ts
const mapContentToThings = (contentTypes: string[]): string[] => {
const thingMapping: Record<string, string[]> = {
// Add custom mappings
'courses': ['course', 'lesson', 'certificate', 'quiz'],
'webinars': ['livestream', 'recording', 'replay'],
// ... existing mappings
};
};
```
## Troubleshooting
### Issue: Analysis Returns Mock Data
**Cause:** WebFetch integration not complete
**Solution:** The services are structured to accept real data. Integrate WebFetch tool:
```typescript
const fetchWebsite = (url: URL): Effect.Effect<string, WebsiteNotAccessible> =>
Effect.tryPromise({
try: () => webFetch.fetch(url.toString()),
catch: (error) => new WebsiteNotAccessible(url.toString(), String(error))
});
```
### Issue: Slug Generation Conflicts
**Cause:** Multiple orgs with similar names
**Solution:** Always check availability and append counter:
```typescript
let slug = baseSlug;
let counter = 2;
while (!(await checkSlugAvailability(slug)).available) {
slug = `${baseSlug}-${counter}`;
counter++;
}
```
### Issue: Brand Colors Not Detected
**Cause:** Website uses inline styles or complex CSS
**Solution:** Enhance color extraction:
```typescript
const extractColors = (html: string): Effect.Effect<BrandIdentity['colors'], never> => {
// Parse <style> tags
// Parse inline styles
// Parse CSS files
// Use OpenAI Vision on screenshots
};
```
## See Also
- **Agent Definition:** `/.claude/agents/agent-onboard.md`
- **Example Output:** `/.claude/agents/agent-onboard-example-output.md`
- **Implementation Summary:** `/one/events/agent-onboard-implementation-summary.md`
- **Ontology Spec:** `/one/knowledge/ontology.md`
- **Installation Folders:** `/one/knowledge/installation-folders.md`
**Ready to onboard users intelligently!** 🚀