Why Skills?
As TimOS grew, we faced a design challenge: how do you make AI capabilities modular, testable, and extensible? Hardcoding prompts throughout the codebase would create maintenance nightmares. We needed a system.
The Core Insight
A Skill is a reusable AI capability with a defined trigger, prompt template, required context, and expected output format. Skills can be system-provided or user-customized.
Skill Architecture
┌─────────────────────────────────────────────────────────┐
│ SKILL │
├─────────────────────────────────────────────────────────┤
│ │
│ name: "daily-reflection" │
│ description: "End-of-day synthesis and insights" │
│ │
│ TRIGGERS (what invokes this skill) │
│ ├── Natural: "reflect on today" │
│ ├── Command: "/reflect" │
│ └── Scheduled: "18:00 daily" │
│ │
│ CONTEXT REQUIREMENTS (what data it needs) │
│ ├── Daily entries from today │
│ ├── Morning pulse data │
│ ├── EOD reflection (if completed) │
│ └── Pillar scores │
│ │
│ PROMPT TEMPLATE │
│ "You are reviewing {{user_name}}'s day. Given: │
│ - Morning state: {{morning_pulse}} │
│ - Entries: {{daily_entries}} │
│ Provide insights on patterns and one actionable..." │
│ │
│ OUTPUT FORMAT │
│ { patterns: [], insights: [], action: string } │
│ │
└─────────────────────────────────────────────────────────┘
Database Schema
// api/src/prisma/vault.prisma
model Skill {
id String @id @default(uuid())
userId String? @map("user_id") // null = system skill
name String
slug String @unique
description String?
category String @default("general")
// Trigger configuration
triggers String @db.Text // JSON array
naturalTriggers String? @db.Text // Natural language patterns
// Prompt configuration
systemPrompt String @db.Text
userPromptTemplate String @db.Text
contextScope String @default("standard") // minimal, standard, comprehensive
// Parameters
parameters String? @db.Text // JSON schema for required params
outputFormat String? @db.Text // Expected response structure
// Metadata
isSystem Boolean @default(false)
isActive Boolean @default(true)
version Int @default(1)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
usageLogs SkillUsageLog[]
@@map("skills")
}
model SkillUsageLog {
id String @id @default(uuid())
skillId String @map("skill_id")
userId String @map("user_id")
trigger String // What triggered the skill
inputTokens Int @default(0)
outputTokens Int @default(0)
latencyMs Int @default(0)
success Boolean @default(true)
errorMessage String?
createdAt DateTime @default(now())
skill Skill @relation(fields: [skillId], references: [id])
@@map("skill_usage_logs")
}
Default Skills
TimOS ships with 5 default skills. Users can customize these or create their own:
Daily Reflection
/reflect
Synthesizes your day into patterns, insights, and one actionable takeaway.
Morning Intention
/intention
Based on your current state and yesterday's patterns, suggests focus areas for today.
Quick Capture
/capture
Quickly categorizes and stores a thought, assigning it to the appropriate pillar.
Task Brain Dump
/braindump
Takes an unstructured brain dump and organizes it into actionable tasks by pillar.
Weekly Patterns
/patterns
Analyzes the past week to identify recurring themes, energy patterns, and blind spots.
Skill Execution Flow
async function executeSkill(
skillSlug: string,
userId: string,
additionalContext?: any
): Promise<SkillResult> {
const startTime = Date.now();
// 1. Load the skill
const skill = await vaultDb.skill.findUnique({
where: { slug: skillSlug }
});
if (!skill || !skill.isActive) {
throw new Error(`Skill ${skillSlug} not found or inactive`);
}
// 2. Build context based on skill requirements
const context = await buildContext(userId, {
scope: skill.contextScope,
dateRange: getContextDateRange(skill),
});
// 3. Compile the prompt
const systemPrompt = skill.systemPrompt;
const userPrompt = compileTemplate(
skill.userPromptTemplate,
{ ...context, ...additionalContext }
);
// 4. Execute AI call
const response = await aiOrchestrator.chat({
userId,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt }
],
temperature: 0.7,
});
// 5. Parse and validate output
const output = parseSkillOutput(response, skill.outputFormat);
// 6. Log usage
await vaultDb.skillUsageLog.create({
data: {
skillId: skill.id,
userId,
trigger: additionalContext?.trigger || 'api',
inputTokens: response.usage?.promptTokens || 0,
outputTokens: response.usage?.completionTokens || 0,
latencyMs: Date.now() - startTime,
success: true,
}
});
return output;
}
Natural Language Triggers
Skills can be triggered naturally through conversation. The system uses pattern matching to detect intent:
// Skill trigger patterns
const TRIGGER_PATTERNS = {
'daily-reflection': [
/reflect on (my )?day/i,
/how (was|did) (my )?day go/i,
/summarize today/i,
/what happened today/i,
],
'morning-intention': [
/set (my )?intention/i,
/what should I focus on/i,
/plan (my )?day/i,
/morning briefing/i,
],
'quick-capture': [
/^capture[: ]/i,
/^note[: ]/i,
/^remember[: ]/i,
],
'task-brain-dump': [
/brain dump/i,
/dump (my )?tasks/i,
/organize (my )?thoughts/i,
],
'weekly-patterns': [
/patterns? (this|last) week/i,
/weekly (review|analysis)/i,
/what patterns/i,
],
};
function detectSkillTrigger(input: string): string | null {
for (const [skillSlug, patterns] of Object.entries(TRIGGER_PATTERNS)) {
for (const pattern of patterns) {
if (pattern.test(input)) {
return skillSlug;
}
}
}
return null;
}
Skill API Endpoints
// GET /api/skills - List available skills
// GET /api/skills/:slug - Get skill details
// POST /api/skills - Create custom skill
// PUT /api/skills/:id - Update skill
// DELETE /api/skills/:id - Delete custom skill (not system)
// POST /api/skills/:slug/execute - Execute a skill
// GET /api/skills/:slug/usage - Get usage stats
Privacy First
When building context for skills, all user data is decrypted just-in-time and never stored in plaintext. The AI provider receives only the compiled prompt - no raw database access.
Future: Scheduled Skills
The next phase will add scheduled skill execution:
// Example scheduled trigger configuration
{
"skill": "daily-reflection",
"schedule": {
"type": "daily",
"time": "18:00",
"timezone": "America/New_York",
"conditions": {
"requiresActivity": true, // Only if user was active today
"minEntries": 1
}
},
"delivery": {
"type": "push",
"fallback": "email"
}
}
Skills System Stats
Default skills: 5
Trigger types: 3 (command, natural, scheduled)
Context scopes: 3 (minimal, standard, comprehensive)
Implementation time: ~2 hours
Key Takeaways
- Skills make AI capabilities modular and testable
- Prompt templates with context variables enable personalization
- Usage logging enables cost tracking and optimization
- Natural language triggers make the system feel conversational
- Privacy-first context building is essential for sensitive data