Rowboat Feature Adoption Plan
Document Version: 1.0 Created: February 2026 Source Repository: github.com/rowboatlabs/rowboat Status: Proposed
Executive Summary
This document outlines strategic feature adoptions from the Rowboat AI assistant platform that would significantly enhance Consul Agent's value proposition. After comprehensive analysis of both codebases, we've identified 10 high-impact opportunities that leverage Consul's existing infrastructure while addressing current gaps in intelligence amplification.
The recommended adoptions focus on making Consul smarter about user context rather than adding new integrations. The existing tool ecosystem (100+ tools), workflow infrastructure, and three-tier memory system provide a strong foundation—the opportunity is using data we already capture more intelligently.
Key Themes:
- Transform passive data collection into active relationship intelligence
- Surface the "why" behind agent decisions to build user trust
- Enable cross-conversation learning that compounds over time
- Prepare users for meetings with contextual briefings
Table of Contents
- Analysis Methodology
- Current State Assessment
- Feature Recommendations
- Implementation Roadmap
- Technical Dependencies
- Success Metrics
- Risk Assessment
- Appendix: Rowboat Architecture Overview
Analysis Methodology
Repositories Analyzed
| Repository | Description | Key Strengths |
|---|---|---|
| rowboat | Desktop AI coworker with persistent memory | Knowledge graph, entity extraction, event-sourced execution |
| consul-agent | Executive AI assistant with Google Workspace integration | Mature tool ecosystem, multi-channel delivery, workflow automation |
Evaluation Criteria
Each feature was evaluated on:
- User Value — Direct impact on user productivity/experience
- Technical Fit — Compatibility with existing architecture
- Implementation Effort — Engineering resources required
- Strategic Alignment — Fit with Consul's product vision
Current State Assessment
Consul Agent Strengths
| Category | Status | Details |
|---|---|---|
| Tool Ecosystem | ✅ Strong | 100+ tools across Gmail, Calendar, Drive, Docs, Slack, Contacts |
| Workflow Automation | ✅ Strong | Email triage, daily briefs, scheduling, sales processing |
| Multi-Channel | ✅ Strong | Web chat, iMessage/SMS, Email (AgentMail) |
| Memory System | ✅ Strong | Working + Semantic + Observational memory tiers |
| Safety Controls | ✅ Strong | 14-stage processor pipeline, human-in-the-loop confirmation |
Identified Gaps
| Gap | Current State | Impact |
|---|---|---|
| Entity Extraction | Manual relationship entry only | Users must explicitly tell Consul about contacts |
| Meeting Preparation | Daily brief lists meetings, no attendee context | Missed opportunity for high-value briefings |
| Decision Transparency | Shows what action, not why | Reduces user trust and adoption |
| Relationship Utilization | relationships table exists but unused in tools | Drafts lack personalization context |
| Cross-Tool Learning | Tools operate independently | Preferences not shared across tool executions |
| Skill Analytics | On/off toggle only | No visibility into automation effectiveness |
Feature Recommendations
Tier 1: Highest Impact
These features address critical gaps with immediate, visible user value.
1. Knowledge Graph & Entity Extraction
Priority: P0 — Critical Effort: Medium (3-4 weeks) User Value: High
What Rowboat Has
Rowboat automatically extracts entities (people, organizations, projects, topics) from:
- Emails and attachments
- Meeting transcripts
- Voice memos
- Notes
Entities are linked in a knowledge graph with relationship types and interaction history.
Current Gap in Consul
The relationships table exists but requires manual population. The agent processes thousands of emails but doesn't learn who matters from communication patterns.
Proposed Implementation
1┌─────────────────────────────────────────────────────────────┐
2│ Entity Extraction Pipeline │
3├─────────────────────────────────────────────────────────────┤
4│ │
5│ emailTriageWorkflow ──► extractEntitiesStep ──► Supabase │
6│ │ │
7│ dailyBriefWorkflow ──► extractEntitiesStep ──► Supabase │
8│ │ │
9│ (future) meetingNotes ──► extractEntitiesStep ──► Supabase│
10│ │
11└─────────────────────────────────────────────────────────────┘New Database Tables:
1-- Extracted entities from communications
2CREATE TABLE entities (
3 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
4 user_id UUID NOT NULL REFERENCES profiles(id),
5 entity_type TEXT NOT NULL, -- 'person', 'organization', 'project', 'topic'
6 name TEXT NOT NULL,
7 aliases TEXT[], -- Alternative names/spellings
8 email TEXT, -- For person entities
9 metadata JSONB DEFAULT '{}',
10 first_seen TIMESTAMPTZ DEFAULT now(),
11 last_seen TIMESTAMPTZ DEFAULT now(),
12 mention_count INTEGER DEFAULT 1,
13 UNIQUE(user_id, entity_type, name)
14);
15
16-- Relationships between entities
17CREATE TABLE entity_relationships (
18 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
19 user_id UUID NOT NULL REFERENCES profiles(id),
20 source_entity_id UUID NOT NULL REFERENCES entities(id),
21 target_entity_id UUID NOT NULL REFERENCES entities(id),
22 relationship_type TEXT NOT NULL, -- 'works_with', 'reports_to', 'collaborates_on'
23 strength REAL DEFAULT 0.5, -- 0-1 based on interaction frequency
24 last_interaction TIMESTAMPTZ,
25 context TEXT -- e.g., "Frequently CC'd together on legal emails"
26);
27
28-- Entity mentions in communications
29CREATE TABLE entity_mentions (
30 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
31 entity_id UUID NOT NULL REFERENCES entities(id),
32 source_type TEXT NOT NULL, -- 'email', 'calendar', 'note'
33 source_id TEXT NOT NULL, -- Gmail message ID, calendar event ID, etc.
34 mentioned_at TIMESTAMPTZ DEFAULT now(),
35 context_snippet TEXT -- Surrounding text for context
36);New Workflow Step:
1// apps/agents/src/mastra/workflows/steps/extract-entities.ts
2export const extractEntitiesStep = createStep({
3 id: "extract-entities",
4 inputSchema: z.object({
5 content: z.string(),
6 sourceType: z.enum(["email", "calendar", "note"]),
7 sourceId: z.string(),
8 userId: z.string(),
9 }),
10 outputSchema: z.object({
11 entities: z.array(z.object({
12 type: z.enum(["person", "organization", "project", "topic"]),
13 name: z.string(),
14 email: z.string().optional(),
15 confidence: z.number(),
16 })),
17 }),
18 execute: async ({ inputData, mastra }) => {
19 const model = mastra.getModel("openai/gpt-4.1-mini");
20
21 const result = await model.generate({
22 messages: [{
23 role: "system",
24 content: ENTITY_EXTRACTION_PROMPT,
25 }, {
26 role: "user",
27 content: inputData.content,
28 }],
29 response_format: { type: "json_object" },
30 });
31
32 // Upsert entities to Supabase
33 // Link to source via entity_mentions
34 // Update relationship strengths based on co-occurrence
35
36 return { entities: result.entities };
37 },
38});Success Metrics
- Entities extracted per user per week
- Relationship accuracy (user corrections)
- Entity utilization rate in drafting/scheduling
2. Meeting Prep Agent
Priority: P0 — Critical Effort: Medium (2-3 weeks) User Value: Very High
What Rowboat Has
Pre-meeting briefings that include:
- Attendee backgrounds and roles
- Recent interaction history
- Open threads/action items with each attendee
- Suggested talking points
- Relevant documents/emails
Current Gap in Consul
Daily brief lists upcoming meetings but provides no attendee context. Users enter meetings without knowing what was last discussed or what's pending with each participant.
Proposed Implementation
Option A: Extend Daily Brief
Add a meetingPrepSection to dailyBriefWorkflow that generates per-meeting briefings.
Option B: Standalone Workflow (Recommended)
Create meetingPrepWorkflow that runs 30 minutes before each meeting, delivering briefing via preferred channel.
1┌─────────────────────────────────────────────────────────────┐
2│ Meeting Prep Workflow │
3├─────────────────────────────────────────────────────────────┤
4│ │
5│ 1. fetchUpcomingMeetings (next 2 hours) │
6│ │ │
7│ ▼ │
8│ 2. For each meeting: │
9│ ├─ resolveAttendees (→ entities table) │
10│ ├─ fetchRecentEmails (with each attendee) │
11│ ├─ fetchPastMeetings (with same attendees) │
12│ ├─ fetchOpenReminders (related to attendees) │
13│ └─ fetchRelatedDocs (shared recently) │
14│ │ │
15│ ▼ │
16│ 3. generateBriefing (structured summary) │
17│ │ │
18│ ▼ │
19│ 4. deliverBriefing (iMessage/email/web notification) │
20│ │
21└─────────────────────────────────────────────────────────────┘Briefing Output Schema:
1const meetingBriefingSchema = z.object({
2 meetingTitle: z.string(),
3 startTime: z.string(),
4 attendees: z.array(z.object({
5 name: z.string(),
6 email: z.string(),
7 role: z.string().optional(),
8 relationship: z.string().optional(), // From relationships table
9 lastInteraction: z.object({
10 date: z.string(),
11 summary: z.string(),
12 }).optional(),
13 openItems: z.array(z.string()), // Pending actions/reminders
14 })),
15 suggestedAgenda: z.array(z.string()),
16 relevantContext: z.array(z.object({
17 type: z.enum(["email", "document", "reminder"]),
18 title: z.string(),
19 summary: z.string(),
20 link: z.string().optional(),
21 })),
22 talkingPoints: z.array(z.string()),
23});Success Metrics
- Meeting prep delivery rate (% of meetings with briefing)
- User engagement (opened, actioned)
- Feedback rating (thumbs up/down on briefings)
3. Decision Reasoning Transparency
Priority: P0 — Critical Effort: Low (1-2 weeks) User Value: High
What Rowboat Has
Event-sourced execution with full audit trail. Users can see the chain of reasoning that led to any action.
Current Gap in Consul
The suspend/resume pattern shows what action the agent wants to take but not why it chose that action over alternatives.
Proposed Implementation
Schema Changes:
1-- Add reasoning to pending_approvals
2ALTER TABLE pending_approvals
3ADD COLUMN reasoning TEXT,
4ADD COLUMN alternatives_considered JSONB DEFAULT '[]',
5ADD COLUMN confidence REAL;Tool Output Enhancement:
1// Extend tool output schema pattern
2const toolOutputWithReasoning = baseOutputSchema.extend({
3 _reasoning: z.object({
4 rationale: z.string(),
5 alternativesConsidered: z.array(z.object({
6 action: z.string(),
7 whyNotChosen: z.string(),
8 })).optional(),
9 confidence: z.number().min(0).max(1),
10 dataSourcesUsed: z.array(z.string()),
11 }).optional(),
12});Processor Enhancement:
Create ReasoningCaptureProcessor that extracts reasoning from tool calls and stores it:
1export class ReasoningCaptureProcessor extends InputProcessor {
2 async process(messages: Message[]): Promise<Message[]> {
3 // After tool execution, capture reasoning from assistant message
4 // Store in pending_approvals.reasoning for suspended tools
5 // Log to decision_audit_log for all tools
6 return messages;
7 }
8}UI Enhancement:
Update confirmation modal to display:
- "Why this action?" expandable section
- Alternatives considered (if any)
- Confidence indicator
- Data sources referenced
Success Metrics
- Confirmation acceptance rate (should increase with transparency)
- Time-to-decision (should decrease as users trust reasoning)
- User feedback on reasoning quality
Tier 2: High Impact
Significant value with moderate architectural work.
4. Cross-Conversation Learning
Priority: P1 — High Effort: Medium (2-3 weeks) User Value: High
What Rowboat Has
Knowledge index that refreshes between processing batches. Entities and patterns learned in one context are available in all future contexts.
Current Gap in Consul
ObservationalMemory exists but tools don't actively share learnings. Each tool operates with local context only.
Proposed Implementation
Observation Emission Pattern:
1// After successful tool execution, emit observation
2export async function emitObservation(
3 context: ToolContext,
4 observation: {
5 type: 'preference' | 'pattern' | 'correction' | 'feedback';
6 category: string; // e.g., 'scheduling', 'email_tone', 'meeting_duration'
7 content: string;
8 confidence: number;
9 source: string; // Tool ID that generated observation
10 }
11) {
12 const userId = context.requestContext?.get("userId");
13 if (!userId) return;
14
15 // Store in observations table
16 await supabase.from("user_observations").insert({
17 user_id: userId,
18 ...observation,
19 observed_at: new Date().toISOString(),
20 });
21
22 // Update working memory with high-confidence observations
23 if (observation.confidence > 0.8) {
24 // Merge into working memory schema
25 }
26}Example Observations:
| Tool | Observation Type | Example |
|---|---|---|
scheduleMeeting | preference | "User prefers 30-minute meetings over 1-hour" |
composeEmail | pattern | "User always includes greeting before business content" |
triageEmail | pattern | "User archives all marketing emails from @promotions.com" |
confirmSendEmail | correction | "User edited draft to add CC — remember to include Jane on legal emails" |
Observation Retrieval:
Tools query relevant observations before execution:
1const relevantObservations = await getObservations({
2 userId,
3 categories: ["email_tone", "recipient_preferences"],
4 minConfidence: 0.7,
5 limit: 5,
6});
7
8// Include in tool context for LLMSuccess Metrics
- Observations generated per user per week
- Observation accuracy (validated by user corrections)
- Reduced user edits to agent-generated content
5. Relationship-Aware Drafting
Priority: P1 — High Effort: Low (1 week) User Value: High
What Rowboat Has
Wiki-style links to people entities. Drafting tools pull relationship context automatically.
Current Gap in Consul
The relationships table exists with contact tags and notes, but composeEmail and triage draft tools don't query it.
Proposed Implementation
Enhance composeEmail and Related Tools:
1// In composeEmail execute function
2const recipientContext = await getRelationshipContext(userId, recipientEmail);
3
4// recipientContext includes:
5// - relationship tags (e.g., "client", "team member", "executive")
6// - last interaction date and summary
7// - communication style notes
8// - preferred formality level
9// - any user notes about the relationship
10
11// Include in LLM prompt
12const systemPrompt = `
13You are drafting an email to ${recipientContext.name}.
14
15Relationship context:
16- Type: ${recipientContext.tags.join(", ")}
17- Last interaction: ${recipientContext.lastInteraction}
18- Communication style: ${recipientContext.communicationStyle}
19- User notes: ${recipientContext.notes}
20
21Adjust tone and content appropriately.
22`;Relationship Context Query:
1async function getRelationshipContext(
2 userId: string,
3 email: string
4): Promise<RelationshipContext | null> {
5 // Check relationships table
6 const relationship = await supabase
7 .from("relationships")
8 .select("*")
9 .eq("user_id", userId)
10 .eq("email", email)
11 .single();
12
13 if (relationship) {
14 return {
15 name: relationship.name,
16 tags: relationship.tags,
17 notes: relationship.notes,
18 lastInteraction: relationship.last_interaction_at,
19 communicationStyle: relationship.communication_style,
20 };
21 }
22
23 // Fall back to entities table if no explicit relationship
24 const entity = await supabase
25 .from("entities")
26 .select("*")
27 .eq("user_id", userId)
28 .eq("email", email)
29 .single();
30
31 return entity ? mapEntityToContext(entity) : null;
32}Success Metrics
- Draft acceptance rate (should increase)
- User edits per draft (should decrease)
- Relationship data utilization rate
6. Skill Performance Analytics
Priority: P1 — High Effort: Medium (2-3 weeks) User Value: Medium-High
What Rowboat Has
PostHog integration with detailed event tracking. Users can see which features work well.
Current Gap in Consul
Skills (triage, drafting, scheduling, etc.) have on/off toggles but no metrics on effectiveness.
Proposed Implementation
New Analytics Tables:
1CREATE TABLE skill_events (
2 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
3 user_id UUID NOT NULL REFERENCES profiles(id),
4 skill_id TEXT NOT NULL, -- 'triage', 'drafting', 'scheduling', etc.
5 event_type TEXT NOT NULL, -- 'invoked', 'completed', 'failed', 'approved', 'rejected', 'edited'
6 metadata JSONB DEFAULT '{}',
7 created_at TIMESTAMPTZ DEFAULT now()
8);
9
10CREATE TABLE skill_metrics (
11 user_id UUID NOT NULL REFERENCES profiles(id),
12 skill_id TEXT NOT NULL,
13 period_start DATE NOT NULL,
14 invocation_count INTEGER DEFAULT 0,
15 success_count INTEGER DEFAULT 0,
16 failure_count INTEGER DEFAULT 0,
17 approval_rate REAL, -- For skills with confirmation
18 avg_time_to_completion INTERVAL,
19 user_edit_rate REAL, -- How often user modified output
20 PRIMARY KEY (user_id, skill_id, period_start)
21);Dashboard Component:
1// apps/web/app/(authenticated)/skills/[skillId]/analytics/page.tsx
2export default function SkillAnalyticsPage({ params }: { params: { skillId: string } }) {
3 return (
4 <div className="space-y-6">
5 <SkillMetricsSummary skillId={params.skillId} />
6 <SkillTrendChart skillId={params.skillId} period="30d" />
7 <SkillEventLog skillId={params.skillId} limit={50} />
8 <SkillRecommendations skillId={params.skillId} />
9 </div>
10 );
11}Metrics Displayed:
- Invocations per day/week
- Success rate trend
- Approval vs. rejection rate (for confirmable actions)
- Average time to user decision
- Common failure reasons
- Recommendations for improvement
Success Metrics
- User engagement with analytics pages
- Skill configuration changes after viewing analytics
- Overall skill effectiveness improvements
Tier 3: Medium Impact
Valuable features with higher implementation effort.
7. Voice Memos with Transcription
Priority: P2 — Medium Effort: Medium-High (3-4 weeks) User Value: Medium-High
What Rowboat Has
Voice recording with Deepgram transcription. Voice notes become searchable knowledge.
Proposed Implementation
Frontend (Web):
1// apps/web/components/chat/voice-input.tsx
2export function VoiceInput({ onTranscription }: { onTranscription: (text: string) => void }) {
3 const [isRecording, setIsRecording] = useState(false);
4 const mediaRecorder = useRef<MediaRecorder | null>(null);
5
6 const startRecording = async () => {
7 const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
8 mediaRecorder.current = new MediaRecorder(stream);
9 // ... capture audio chunks
10 };
11
12 const stopAndTranscribe = async () => {
13 const audioBlob = new Blob(chunks, { type: "audio/webm" });
14 const formData = new FormData();
15 formData.append("audio", audioBlob);
16
17 const response = await fetch("/api/transcribe", {
18 method: "POST",
19 body: formData,
20 });
21
22 const { text } = await response.json();
23 onTranscription(text);
24 };
25
26 return (
27 <Button
28 variant={isRecording ? "destructive" : "outline"}
29 onClick={isRecording ? stopAndTranscribe : startRecording}
30 >
31 <Mic className="h-4 w-4" />
32 </Button>
33 );
34}Backend Transcription:
1// apps/web/app/api/transcribe/route.ts
2export async function POST(request: Request) {
3 const formData = await request.formData();
4 const audioFile = formData.get("audio") as File;
5
6 const transcription = await openai.audio.transcriptions.create({
7 file: audioFile,
8 model: "whisper-1",
9 });
10
11 return NextResponse.json({ text: transcription.text });
12}Success Metrics
- Voice input usage rate
- Transcription accuracy (user corrections)
- Task completion rate via voice vs. text
8. Wiki-Style Knowledge Base
Priority: P2 — Medium Effort: High (4-6 weeks) User Value: Medium
What Rowboat Has
Local markdown files with [[wiki links]]. Graph visualization of knowledge relationships.
Proposed Implementation
Database Schema:
1CREATE TABLE notes (
2 id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
3 user_id UUID NOT NULL REFERENCES profiles(id),
4 title TEXT NOT NULL,
5 content TEXT NOT NULL, -- Markdown with [[wiki links]]
6 tags TEXT[] DEFAULT '{}',
7 linked_entities UUID[] DEFAULT '{}', -- References to entities table
8 created_at TIMESTAMPTZ DEFAULT now(),
9 updated_at TIMESTAMPTZ DEFAULT now()
10);
11
12CREATE TABLE note_links (
13 source_note_id UUID NOT NULL REFERENCES notes(id),
14 target_note_id UUID NOT NULL REFERENCES notes(id),
15 link_text TEXT, -- The [[text]] used
16 PRIMARY KEY (source_note_id, target_note_id)
17);New Tools:
createNote— Create new knowledge noteupdateNote— Edit existing notesearchNotes— Full-text search across noteslinkNote— Create wiki-style link between notes
UI Components:
- Note editor with wiki-link autocomplete
- Knowledge graph visualization
- Note search and browse interface
Success Metrics
- Notes created per user
- Wiki links created
- Note retrieval in agent conversations
9. MCP (Model Context Protocol) Integration
Priority: P2 — Medium Effort: High (4-6 weeks) User Value: Medium (power users)
What Rowboat Has
Extensible tool system via MCP servers. Users can add custom tool providers.
Proposed Implementation
MCP Client in Agents:
1// apps/agents/src/mastra/mcp/client.ts
2import { Client } from "@modelcontextprotocol/sdk/client";
3
4export class MCPToolProvider {
5 private clients: Map<string, Client> = new Map();
6
7 async connectServer(config: MCPServerConfig): Promise<void> {
8 const client = new Client({
9 name: "consul-agent",
10 version: "1.0.0",
11 });
12
13 await client.connect({
14 command: config.command,
15 args: config.args,
16 });
17
18 this.clients.set(config.id, client);
19 }
20
21 async getTools(serverId: string): Promise<Tool[]> {
22 const client = this.clients.get(serverId);
23 if (!client) throw new Error(`MCP server ${serverId} not connected`);
24
25 const { tools } = await client.listTools();
26 return tools.map(mcpToolToMastraTool);
27 }
28
29 async invokeTool(serverId: string, toolName: string, args: unknown): Promise<unknown> {
30 const client = this.clients.get(serverId);
31 return client.callTool({ name: toolName, arguments: args });
32 }
33}User Configuration UI:
- MCP server management page
- Add/remove server configurations
- Test connection functionality
- Per-server tool visibility settings
Success Metrics
- MCP servers configured per user
- MCP tool invocations
- Custom integration adoption
Tier 4: Lower Priority
Interesting capabilities for future consideration.
10. Composio Integration
Priority: P3 — Low Effort: Medium (2-3 weeks) User Value: Low-Medium
What Rowboat Has
Pre-built connections to 100+ apps via Composio platform.
Proposed Implementation
Integrate Composio SDK for simplified OAuth and third-party tool access. Useful for quickly adding integrations without building custom OAuth flows.
Considerations
- Adds external dependency for auth management
- May conflict with existing custom OAuth implementations
- Best suited if rapidly expanding integration count
Implementation Roadmap
Phase 1: Quick Wins (Weeks 1-4)
| Feature | Effort | Dependencies |
|---|---|---|
| Decision Reasoning Transparency (#3) | 1-2 weeks | None |
| Relationship-Aware Drafting (#5) | 1 week | None |
| Basic Entity Extraction (#1 partial) | 1-2 weeks | None |
Deliverables:
- Reasoning displayed in confirmation modals
composeEmailqueries relationships table- Entity extraction step added to
emailTriageWorkflow
Phase 2: Core Intelligence (Weeks 5-12)
| Feature | Effort | Dependencies |
|---|---|---|
| Meeting Prep Workflow (#2) | 2-3 weeks | Entity extraction |
| Full Knowledge Graph (#1 complete) | 2-3 weeks | Phase 1 entity work |
| Cross-Conversation Learning (#4) | 2-3 weeks | None |
Deliverables:
meetingPrepWorkflowdelivering briefings before meetings- Entities table fully populated from all communication sources
- Observations system capturing and applying learnings
Phase 3: Polish & Analytics (Weeks 13-18)
| Feature | Effort | Dependencies |
|---|---|---|
| Skill Performance Analytics (#6) | 2-3 weeks | None |
| Voice Memos (#7) | 3-4 weeks | None |
Deliverables:
- Analytics dashboard for each skill
- Voice input in web chat
Phase 4: Expansion (Future)
| Feature | Effort | Dependencies |
|---|---|---|
| Wiki-Style Knowledge Base (#8) | 4-6 weeks | Entity extraction |
| MCP Integration (#9) | 4-6 weeks | None |
| Composio Integration (#10) | 2-3 weeks | None |
Technical Dependencies
New Packages Required
1{
2 "@modelcontextprotocol/sdk": "^1.0.0", // For MCP integration (Phase 4)
3 "deepgram-sdk": "^3.0.0" // Alternative to OpenAI Whisper (Phase 3)
4}Database Migrations Required
| Phase | Tables | Description |
|---|---|---|
| 1 | pending_approvals (alter) | Add reasoning columns |
| 1-2 | entities, entity_relationships, entity_mentions | Knowledge graph |
| 2 | user_observations | Cross-conversation learning |
| 3 | skill_events, skill_metrics | Analytics |
| 4 | notes, note_links | Wiki knowledge base |
Infrastructure Considerations
- No new services required for Phases 1-3
- Vector database updates may be needed for semantic entity search
- Background job capacity — Meeting prep workflow adds scheduled jobs
Success Metrics
User-Facing Metrics
| Metric | Baseline | Target | Measurement |
|---|---|---|---|
| Confirmation acceptance rate | 65% | 85% | pending_approvals accept/reject ratio |
| Draft edit rate | 40% | 20% | User modifications to agent drafts |
| Meeting prep engagement | N/A | 70% open rate | Briefing delivery and opens |
| Time to first action | 45s | 25s | User decision time on confirmations |
System Metrics
| Metric | Target | Measurement |
|---|---|---|
| Entities extracted/user/week | 50+ | entities table growth |
| Observations generated/user/week | 20+ | user_observations table |
| Cross-tool learning accuracy | 80%+ | Observation validation rate |
Risk Assessment
Technical Risks
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Entity extraction accuracy | Medium | Medium | Use confidence thresholds; allow user corrections |
| Meeting prep timing failures | Low | High | Fallback delivery windows; retry logic |
| Observation noise | Medium | Low | Confidence filtering; periodic cleanup |
Product Risks
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Information overload (meeting prep) | Medium | Medium | Configurable briefing depth |
| Privacy concerns (entity tracking) | Low | High | Clear data policies; user controls |
| Feature complexity | Medium | Medium | Phased rollout; feature flags |
Appendix: Rowboat Architecture Overview
Key Architectural Patterns
1. Event-Sourced Agent Execution
Rowboat reconstructs agent state from immutable event logs, enabling:
- Resumable runs across sessions
- Full audit trail
- Time-travel debugging
2. Knowledge Graph Structure
1┌─────────────────────────────────────────────────────────────┐
2│ Knowledge Graph │
3├─────────────────────────────────────────────────────────────┤
4│ │
5│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
6│ │ Person │────────▶│ Project │◀────────│ Topic │ │
7│ └──────────┘ └──────────┘ └──────────┘ │
8│ │ │ │ │
9│ │ ┌───────────────┼───────────────┐ │ │
10│ │ │ │ │ │ │
11│ ▼ ▼ ▼ ▼ ▼ │
12│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
13│ │ Org │ │ Email │ │ Meeting │ │
14│ └──────────┘ └──────────┘ └──────────┘ │
15│ │
16└─────────────────────────────────────────────────────────────┘3. Tiered Note Creation
Rowboat uses complexity-based processing:
- High complexity: Full multi-agent analysis
- Medium complexity: Single-agent with context
- Low complexity: Direct extraction
4. MCP Tool Architecture
1┌─────────────────────────────────────────────────────────────┐
2│ Tool System │
3├─────────────────────────────────────────────────────────────┤
4│ │
5│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
6│ │ Built-in │ │ MCP │ │ Sub-Agent │ │
7│ │ Tools │ │ Tools │ │ Tools │ │
8│ └──────┬──────┘ └──────┬──────┘ └──────┬──────┘ │
9│ │ │ │ │
10│ └────────────────┼────────────────┘ │
11│ │ │
12│ ▼ │
13│ ┌──────────────┐ │
14│ │ Agent Runtime │ │
15│ └──────────────┘ │
16│ │
17└─────────────────────────────────────────────────────────────┘Document History
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | Feb 2026 | Claude Code | Initial analysis and recommendations |
This document should be reviewed and updated as implementation progresses and priorities shift.