Yebo Agent Framework
Personal AI agents for every African's economic life - at scale, cheaply.
Created: 2026-04-01
Author: Laslie Georges Jr. + AI Architecture Session
The Vision
Each Yebo user gets a personal AI agent that:
- Knows them - learns from every interaction
- Watches for them - triggers on relevant events
- Acts for them - uses MCP tools on their behalf
- Grows with them - compounds knowledge over time
Core Insight: Serverless Agents
Agents don't run constantly. They:
- Sleep 99% of the time
- Wake up on: user message, event trigger, cron schedule
- Work for seconds, then sleep again
This makes it cheap to scale to millions of users.
Architecture Overview
┌────────────────────────────────────────────────────────────┐
│ MCP PRODUCTS │
│ YeboShops | YeboJobs | YeboLink | YeboLearn | YeboSafe │
└─────────────────────────┬──────────────────────────────────┘
▼ (webhooks)
┌────────────────────────────────────────────────────────────┐
│ EVENT BUS │
│ (Redis Streams or Pub/Sub) │
└─────────────────────────┬──────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────┐
│ TRIGGER EVALUATOR │
│ (JSON rule matching, no AI) │
│ │
│ Postgres: triggers table │
│ For each event → find matching triggers → queue wake-ups │
└─────────────────────────┬──────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────┐
│ TASK QUEUE │
│ (Cloud Tasks / BullMQ) │
└─────────────────────────┬──────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────┐
│ AGENT RUNTIME (Hiyebo API) │
├────────────────────────────────────────────────────────────┤
│ 1. Load yeboid-{userId}.md from R2 │
│ 2. Load trigger context │
│ 3. AI reasons, uses MCP tools │
│ 4. Updates identity, creates/removes triggers │
│ 5. Sends message to Hiyebo app │
│ 6. Sleeps │
└─────────────────────────┬──────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────┐
│ HIYEBO APP (User's Interface) │
│ SSE for real-time, FCM for push │
└────────────────────────────────────────────────────────────┘Per-User Storage (R2)
Bucket: hiyebo-agents
/agents/{userId}/
├── yeboid-{userId}.md # WHO they are (identity + preferences)
├── memory.md # WHAT happened (interaction history)
├── triggers.json # WHAT they're watching for (cached)
└── context/
└── session.json # Current conversation stateCost: ~$0.015/GB/month = pennies for millions of users
The Identity File: yeboid-{userId}.md
This is the canonical source of truth about each user:
# YeboID: {userId}
## Identity
- **Name:** Tendai Moyo
- **Phone:** +263...
- **Location:** Harare, Zimbabwe
- **Language:** English, Shona
- **Timezone:** Africa/Harare (UTC+2)
- **Verified:** ✓ Phone, ✓ ID
## Profile
- **Occupation:** Software Developer
- **Skills:** React, Node.js, Python
- **Experience:** 4 years
- **Education:** BSc Computer Science, UZ
## Preferences
- **Communication:** Concise, technical
- **Notifications:** Immediate for jobs, batched for listings
- **Currency:** USD preferred, ZWL accepted
- **Price Sensitivity:** Medium (values quality)
## Economic Activity
### Selling
- Active seller on YeboShops (12 listings, 8 sold)
- Categories: Electronics, Phones
- Avg response time: 2 hours
- Rating: 4.7/5
### Buying
- Purchased: iPhone 13 (E8,500), MacBook Air (E15,000)
- Interests: Tech gadgets, refurbished electronics
- Price alerts: iPhone 15 < E10,000
### Employment
- Status: Employed, open to offers
- Looking for: Senior React roles, Remote OK
- Salary expectation: $3,000-5,000/month
- Last application: 2026-03-15 (Safaricom)
### Learning
- Enrolled: AWS Cloud Practitioner (YeboLearn)
- Completed: React Advanced Patterns
- Interests: Cloud architecture, System design
## Behavior Patterns
- Most active: Evenings (18:00-22:00)
- Responds quickly to job matches
- Prefers images when selling
- Negotiates 10-15% on purchases
## Agent Notes
- Likes direct communication, no fluff
- Mentioned budget constraints in March
- Interested in relocating to South Africa
- Birthday: March 15 (wished him last year)
## Trust Indicators
- Member since: 2025-06-01
- Transactions: 23 successful
- Disputes: 0
- Verification level: FullTriggers System
Database Schema
CREATE TABLE triggers (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
-- What fires this trigger
type TEXT NOT NULL, -- 'event', 'cron', 'reminder'
source TEXT, -- 'yeboshops', 'yebojobs', etc.
event TEXT, -- 'listing.created', 'job.posted', etc.
-- Conditions (JSONB for flexible matching)
conditions JSONB DEFAULT '{}',
-- When to fire (for cron/reminder)
schedule TEXT, -- Cron expression
fire_at TIMESTAMPTZ, -- One-time reminder
-- Context for agent when it wakes
context JSONB DEFAULT '{}',
-- State
active BOOLEAN DEFAULT true,
last_fired_at TIMESTAMPTZ,
fire_count INT DEFAULT 0,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX idx_triggers_event ON triggers(source, event) WHERE active = true;
CREATE INDEX idx_triggers_cron ON triggers(type) WHERE type = 'cron' AND active = true;
CREATE INDEX idx_triggers_reminder ON triggers(fire_at) WHERE type = 'reminder' AND active = true;Trigger Types
1. Event Triggers - React to product events
{
"type": "event",
"source": "yebojobs",
"event": "job.posted",
"conditions": { "skills": ["react"], "location": "nairobi" },
"context": { "reason": "User asked for React jobs in Nairobi" }
}2. Cron Triggers - Scheduled wake-ups
{
"type": "cron",
"schedule": "0 8 * * *",
"context": { "task": "morning_briefing" }
}3. Reminder Triggers - One-time future wake-up
{
"type": "reminder",
"fire_at": "2026-04-05T10:00:00Z",
"context": { "task": "follow_up_listing_123" }
}Event Ingestion
All MCP products emit events to a central endpoint:
// POST /events/ingest
eventsRouter.post('/ingest', async (req, res) => {
const { source, event, payload, timestamp } = req.body;
// Find matching triggers (JSON containment query)
const triggers = await db.query(`
SELECT * FROM triggers
WHERE source = $1
AND event = $2
AND active = true
AND conditions <@ $3
`, [source, event, payload]);
// Queue agent wake-ups
for (const trigger of triggers) {
await taskQueue.add('agent-wake', {
userId: trigger.user_id,
triggerId: trigger.id,
source,
event,
payload
});
}
res.json({ matched: triggers.length });
});Agent Wake-Up Flow
async function handleAgentWake(task: AgentTask) {
const { userId, triggerId, source, event, payload } = task;
// 1. Load agent memory
const identity = await loadIdentity(userId); // yeboid-{userId}.md
const memory = await loadMemory(userId); // memory.md
const trigger = await db.triggers.findById(triggerId);
// 2. Build agent context
const systemPrompt = `
You are this user's personal AI agent on Yebo.
${identity}
Your job is to:
1. Help them with whatever they need
2. Proactively find opportunities for them
3. Learn more about them with every interaction
4. Take actions on their behalf when appropriate
Be personal. Use their name. Remember past conversations.
`;
const userMessage = `
[TRIGGER FIRED]
Source: ${source}
Event: ${event}
Context: ${JSON.stringify(trigger.context)}
Payload:
${JSON.stringify(payload, null, 2)}
Decide:
1. Is this relevant to them?
2. How should you notify them?
3. Should you take any action via MCP tools?
4. Update your memory if you learn anything new.
`;
// 3. Run agent turn with MCP tools
const response = await runAgentTurn(userId, systemPrompt, userMessage);
// 4. Handle outputs
if (response.notification) {
await sendInAppNotification(userId, response.notification);
}
if (response.memoryUpdate) {
await saveMemory(userId, response.memoryUpdate);
}
if (response.newTriggers) {
await createTriggers(userId, response.newTriggers);
}
}Learning Pipeline
Every interaction updates the user's identity:
interface LearningEvent {
userId: string;
source: string; // 'yeboshops', 'yebojobs', 'chat', etc.
event: string; // 'listing.created', 'message.sent', etc.
payload: any;
}
async function learn(event: LearningEvent): Promise<void> {
const identity = await loadIdentity(event.userId);
// Extract insights based on event type
const insights = await extractInsights(event);
// Update identity file
const updatedIdentity = mergeInsights(identity, insights);
await saveIdentity(event.userId, updatedIdentity);
}AI-Powered Learning (for conversations)
async function learnFromConversation(userId: string, messages: Message[]) {
const currentIdentity = await loadIdentity(userId);
const prompt = `
You are updating a user's identity file based on a conversation.
CURRENT IDENTITY:
${currentIdentity}
CONVERSATION:
${formatMessages(messages)}
Extract any NEW information about the user:
- Preferences they expressed
- Goals or intentions
- Personal details shared
- Behavior patterns observed
Output as JSON patches:
{
"updates": [
{ "section": "Preferences", "key": "...", "value": "...", "reason": "..." }
]
}
`;
const response = await gemini.generate(prompt);
await applyPatches(userId, JSON.parse(response).updates);
}Agent Tools
The agent has tools to manage itself:
const agentTools = [
{
name: 'create_trigger',
description: 'Create a trigger to wake me up when something happens',
parameters: {
type: { enum: ['event', 'cron', 'reminder'] },
source: { type: 'string' },
event: { type: 'string' },
conditions: { type: 'object' },
schedule: { type: 'string' },
fire_at: { type: 'string' },
context: { type: 'object' }
}
},
{
name: 'list_triggers',
description: 'List my active triggers'
},
{
name: 'delete_trigger',
description: 'Remove a trigger',
parameters: { triggerId: { type: 'string' } }
},
{
name: 'update_memory',
description: 'Update my long-term memory about this user',
parameters: {
append: { type: 'string' },
replace: { type: 'string' }
}
}
];Plus all MCP tools from connected products (YeboShops, YeboJobs, etc.)
Example Flow
User: "Let me know if any React jobs in Nairobi come up"
Agent Turn 1:
- Loads yeboid-{userId}.md
- Understands user wants job alerts
- Calls
create_trigger:json{ "type": "event", "source": "yebojobs", "event": "job.posted", "conditions": { "skills": ["react"], "location": "nairobi" } } - Updates identity: "Looking for React developer jobs in Nairobi"
- Responds: "I'll watch for React jobs in Nairobi!"
...3 days later...
YeboJobs posts job → webhook → trigger matches → agent wakes
Agent Turn 2:
- Loads identity (knows user wants React jobs)
- Sees trigger context + job payload
- Responds: "🎯 Found a job! React Developer at Safaricom. Want me to apply?"
Framework Package Structure
@yebo/agent-framework/
├── identity/
│ ├── schema.ts # Identity file structure
│ ├── loader.ts # Load/save identity
│ └── validator.ts # Validate identity data
├── learning/
│ ├── pipeline.ts # Learning event processing
│ ├── extractors/ # Per-product insight extractors
│ ├── ai-learner.ts # AI-powered extraction
│ └── sync.ts # Cross-product sync
├── triggers/
│ ├── schema.ts # Trigger types
│ ├── evaluator.ts # Match events to triggers
│ └── scheduler.ts # Cron/reminder processing
├── runtime/
│ ├── context.ts # Build agent context
│ ├── executor.ts # Run agent turns
│ └── tools.ts # Agent tools
├── storage/
│ ├── r2.ts # R2 operations
│ └── postgres.ts # DB operations
└── index.ts # Framework entryCost Model
| Component | Cost |
|---|---|
| R2 Storage (100KB × 1M users) | ~$1.50/mo |
| Postgres (triggers, metadata) | ~$20/mo |
| Event Evaluator (Cloud Run) | ~$10/mo |
| Task Queue (Cloud Tasks) | ~$5/mo |
| AI Turns (variable) | ~$0.01/turn |
Per-user cost:
- Average: 5 turns/month = $0.05/user/month
- Power user: 50 turns/month = $0.50/user/month
Implementation Phases
Phase 1: Storage + Identity
- [ ] R2 bucket setup
- [ ] Identity file schema
- [ ] Load/save functions
Phase 2: Triggers
- [ ] Postgres triggers table
- [ ] Event ingestion endpoint
- [ ] Trigger evaluator
Phase 3: Agent Runtime
- [ ] Context builder
- [ ] Agent turn executor
- [ ] Agent tools (create_trigger, update_memory, etc.)
Phase 4: Learning
- [ ] Learning pipeline
- [ ] Per-product extractors
- [ ] AI-powered conversation learning
Phase 5: MCP Integration
- [ ] Wire YeboShops events
- [ ] Wire YeboJobs events
- [ ] Add more products
The Compound Effect
Day 1: User signs up → empty identity file
Day 7: Searches for jobs → learns skills, interests
Day 14: Lists an iPhone → learns seller behavior
Day 30: Agent knows preferences, patterns, goals
Day 90: Agent is their digital economic twin
Day 365: Agent has more context than any human assistantWhy This Wins
- Personalization at scale - Every user gets a personal agent
- Cross-product intelligence - Learning compounds across all Yebo products
- Proactive, not reactive - Agent finds opportunities, not just responds
- Cheap to operate - Serverless = pay per use
- Moat - User data is the moat. The longer someone uses Yebo, the more their agent knows
"The best founders build systems that compound. This compounds knowledge."
Advanced: Vector Memory + AI Synthesis
The Problem with Basic Design
- Captures explicit: "User listed an iPhone"
- Misses implicit: "User always prices 10% below market, responds faster to serious buyers"
Three Memory Layers
User Interaction
↓
┌──────┴──────────────┐
↓ ↓
Immediate Update Embed & Store
(structured data) (semantic vectors)
↓ ↓
yeboid.md Vector DB (pgvector)
↓ ↓
└──────┬──────────────┘
↓
Periodic AI Synthesis
(Gemini analyzes everything)
↓
Updated yeboid.md
(with discovered insights)Layer 1: Immediate (Real-time)
Direct updates from events:
listing.created→ increment seller_countjob.applied→ add to applications list
Layer 2: Semantic (Vectors)
Embed and store for pattern recognition:
- Conversation summaries
- Search queries
- Browsing behavior
- Listing descriptions they viewed
What vectors capture that rules can't:
- User searches "cheap reliable car" + views Toyota listings + skips BMWs → practical, budget-conscious
- User messages sellers at 10pm, responds within minutes → night owl, decisive
- User's job searches + items sold correlate → selling to fund career transition
Layer 3: Synthesis (Periodic AI)
Weekly/monthly, Gemini analyzes everything and discovers hidden patterns.
Vector Storage (pgvector)
CREATE EXTENSION vector;
CREATE TABLE user_embeddings (
id UUID PRIMARY KEY,
user_id UUID NOT NULL,
content_type TEXT, -- 'conversation', 'search', 'behavior'
content_summary TEXT,
embedding vector(768), -- Gemini embedding dimension
metadata JSONB,
created_at TIMESTAMPTZ DEFAULT now()
);
CREATE INDEX ON user_embeddings
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);Embedding Pipeline
async function embedAndStore(userId: string, content: string, type: string) {
const embedding = await gemini.embed(content);
await db.query(`
INSERT INTO user_embeddings (user_id, content_type, content_summary, embedding)
VALUES ($1, $2, $3, $4)
`, [userId, type, summarize(content), embedding]);
}
async function onConversationEnd(userId: string, messages: Message[]) {
const summary = await summarizeConversation(messages);
await embedAndStore(userId, summary, 'conversation');
}Periodic Synthesis
async function synthesizeUserInsights(userId: string) {
const identity = await loadIdentity(userId);
const clusters = await findSemanticClusters(userId);
const activity = await getRecentActivity(userId, 30);
const prompt = `
You are analyzing a Yebo user to discover hidden patterns.
CURRENT PROFILE:
${identity}
SEMANTIC PATTERNS (from embeddings):
${formatClusters(clusters)}
RECENT ACTIVITY:
${formatActivity(activity)}
Provide:
1. New personality insights
2. Hidden preferences discovered
3. Behavioral patterns
4. Predictions for next 30 days
5. Specific updates to their profile
`;
const insights = await gemini.generate(prompt);
await appendToIdentity(userId, '## AI Insights', insights);
}Example AI Synthesis Output
## Agent Notes (AI Synthesized - Apr 2026)
- Likely planning career move to fintech (job search + selling assets pattern)
- Price-sensitive on purchases but values quality (browses premium, waits for deals)
- Decision maker - average 2.3 hours from first view to purchase
- Trust builder - always asks for verification before high-value transactions
- Prediction: Will likely search for laptops soon (new job preparation pattern)Cost Estimate (1M users)
| Component | Cost |
|---|---|
| pgvector storage | ~$20/mo (part of existing Postgres) |
| Embedding API calls | ~$1,000/mo |
| Weekly synthesis (active users only) | ~$4,000/mo |
| Total | ~$5,000/mo |
Optimization
- Only synthesize users with >10 new events since last synthesis
- Use Gemini Flash for routine synthesis
- Use Gemini Pro only for high-value users
- Batch embeddings (cheaper than individual calls)