Lifecycle Tracking
How skill executions are persisted, tracked, and queried -- the skill_execution table, log_skill_execution MCP tool, tRPC admin router, and metadata conventions.
Every research skill invocation is tracked from start to completion in the skill_execution table. This page covers the database schema, the MCP tool that writes records, the tRPC router that reads them, and the metadata conventions that make the data useful.
Database Schema
The skill_execution table is defined in packages/db/src/schema/research.ts:
export const skillExecution = pgTable(
"skill_execution",
{
id: text("id").primaryKey(),
organizationId: text("organization_id").notNull(),
userId: text("user_id")
.notNull()
.references(() => user.id),
skillName: text("skill_name").notNull(),
status: skillExecutionStatusEnum("status").notNull().default("started"),
planId: text("plan_id").references(() => researchPlan.id, { onDelete: "set null" }),
metadata: jsonb("metadata").$type<Record<string, unknown>>(),
errorMessage: text("error_message"),
claudeCodeSessionId: text("claude_code_session_id"),
startedAt: timestamp("started_at", { withTimezone: true }).defaultNow().notNull(),
completedAt: timestamp("completed_at", { withTimezone: true }),
durationMs: integer("duration_ms"),
createdAt: timestamp("created_at", { withTimezone: true }).defaultNow().notNull(),
updatedAt: timestamp("updated_at", { withTimezone: true }).defaultNow().notNull(),
},
// Indexes on organizationId, skillName, status, planId, createdAt
// RLS via tenantPolicies("skill_execution", "organization_id")
);
Status Enum
Four statuses track the execution lifecycle:
| Status | Meaning | Terminal? |
|---|---|---|
started | Skill invoked, interview/routing in progress | No |
executing | Plan created, step execution in progress | No |
completed | All steps finished and output delivered | Yes |
failed | Execution failed (step failure, user rejection, or error) | Yes |
Relationships
researchPlan-- one-to-one viaplanId. Set automatically bycreate_research_planwhen the server auto-links the skill execution.user-- many-to-one viauserId.mcpToolCallLog-- one-to-many. Each MCP tool call made during this execution is logged with a back-reference to the skill execution ID.
MCP Tool: log_skill_execution
Source: packages/mcp/src/tools/log-skill-execution.ts
This tool has dual behavior based on whether executionId is provided:
Create Mode (no executionId)
Called at the start of a skill invocation to create a new tracking record. Returns the generated executionId.
log_skill_execution({
skillName: "research", // "research" | "research-scan" | "research-deep"
status: "started",
metadata: { ... }, // interview data, routing rationale
sessionId: "..." // Claude Code session ID
})
// Returns: { executionId: "abc-123", skillName: "research", status: "started", stored: true }
Update Mode (with executionId)
Called to update status, link a plan, add metadata, or record completion/failure.
log_skill_execution({
executionId: "abc-123",
skillName: "research",
status: "completed",
metadata: { stepsCompleted: 3, artifactsStored: 2 }
})
Key Implementation Details
- Metadata merging: Updates shallow-merge new metadata with existing metadata. Existing keys are overwritten by new values; keys not included in the update are preserved.
- Duration calculation: When status transitions to
completedorfailed, the server calculatesdurationMsfromstartedAtto the current time and setscompletedAt. - Tenant isolation: All operations go through
withTenantContext(organizationId, userId, ...)for RLS enforcement. - Organization resolution: The user's active organization is resolved via
resolveOrganizationId(auth.userId).
Auto-Linking via create_research_plan
The log_skill_execution update that links a plan to a skill execution is handled automatically by the create_research_plan tool. When create_research_plan receives a sessionId:
- Queries
skill_executionfor the most recentstartedrow matching that session - If found: updates
planId, setsstatus = "executing", mergesplanDesignRationaleinto metadata - If not found: no-op
This design eliminates a tool call that the AI platform might forget, ensuring plan linkage is guaranteed.
tRPC Admin Router
Source: packages/api/src/routers/skill-execution.ts
Three procedures provide read access for the admin UI, all gated by ctx.ability.cannot("read", "ResearchPlan"):
skillExecution.list
Paginated list with optional filters.
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | number | 20 | Page size (1-100) |
offset | number | 0 | Pagination offset |
skillName | string | -- | Filter by skill name |
status | enum | -- | Filter by status |
Returns { executions, total }. Each execution includes a left join to research_plan for planName and planStatus.
skillExecution.detail
Full detail for a single execution.
| Parameter | Type | Description |
|---|---|---|
executionId | string | The execution ID |
Returns { execution, plan, auditLog }:
execution-- the full skill execution rowplan-- the linked research plan (ifplanIdis set)auditLog-- plan audit log entries filtered by bothplanIdandclaudeCodeSessionId
skillExecution.summary
Aggregate KPIs for the dashboard.
Returns:
totalExecutions-- total countbyStatus-- counts grouped by status ({ started: 2, executing: 1, completed: 8, failed: 1 })bySkill-- counts grouped by skill name ({ research: 5, "research-scan": 4, "research-deep": 3 })avgDurationMs-- average duration of completed executionsrecentFailures-- count of failures in the last 24 hours
Metadata Conventions
The metadata JSONB field stores all non-structural data about the skill invocation. Conventions are enforced by skill prompts, not by schema.
Phase 1 Interview Data
Stored on creation (log_skill_execution create call):
| Key | Type | Description |
|---|---|---|
topic | string | Core research subject |
researchType | string | general_topic, competitive_analysis, or decision_support |
scope | string | Breadth and depth boundaries |
depthSignals | string | Words indicating desired depth |
decisionContext | string or null | What decision this research informs |
knownContext | string or null | What the user already knows |
outputMediaType | string | conversation, markdown, html, word, excel, powerpoint |
outputFormattingInstructions | string or null | Styling/layout requirements |
originalQuery | string | User's original message (up to 5000 chars) |
Clarification Data
One of these is always present:
| Key | Type | Description |
|---|---|---|
clarifyingQuestions | [{ question, answer }] | Questions asked and user responses |
skipQuestionsReason | string | Why questions were not needed |
Routing Data
| Key | Type | Description |
|---|---|---|
delegatedTo | "scan" or "deep" | Which mode was chosen |
routingRationale | string | Full explanation of the routing decision |
Prior Research Check
Stored via update after search_sources:
| Key | Type | Description |
|---|---|---|
priorResearchCheck.found | number | Count of artifacts returned |
priorResearchCheck.artifactIds | string[] | IDs of artifacts shown to user |
priorResearchCheck.userConversation | string | Summary of the user's response |
priorResearchCheck.userDecision | string | use_existing, refresh, or unique |
priorResearchCheck.refreshContext | string or null | Additional context for refresh |
priorResearchCheck.closedReason | string or null | Reason session ended early |
Completion Data
Stored via update when the skill completes:
| Key | Type | Description |
|---|---|---|
stepsCompleted | number | Count of completed plan steps |
artifactsStored | number | Count of stored research artifacts |
mode | string | "scan" or "deep" |
checkpointFeedback | string or null | Summary of checkpoint feedback (deep only) |
Plan Design
Merged into metadata by the create_research_plan auto-link:
| Key | Type | Description |
|---|---|---|
planDesignRationale | string | Why the plan was structured this way |
Related Tables
Skill execution data connects to several other tables in the research schema:
| Table | Relationship | Purpose |
|---|---|---|
research_plan | FK via planId | The plan this skill execution created and drove |
plan_step | Via plan | Individual steps within the plan |
plan_audit_log | Via plan + session | Chronological event log filtered by session |
mcp_tool_call_log | FK via skill_execution_id | Every MCP tool call made during this execution |
research_artifact | Via plan | Stored research outputs |
research_output | Via plan | Final deliverable |
research_feedback | Via plan | User satisfaction feedback |
Related Pages
- Skill Executions View -- the admin UI that displays this data
- Execution Flow -- when each metadata field is written during the lifecycle
- Plan Orchestration -- the plan state machine and audit log
- Tool Protocol -- MCP tool call logging middleware
Routing Logic
How the router skill classifies research requests as quick scan or deep dive -- criteria, depth signals, default behavior, and routing rationale.
Plan Orchestration Overview
How Trovella coordinates multi-step research plans through state machines, branching, stall detection, and a pull-based execution loop.