SakuraDocs

Sakura Data Models

Comprehensive reference for all TypeScript types, Zod schemas, and database table definitions across the Sakura monorepo.


Table of Contents

  1. Core CLI Types
  2. Provider & LLM Types
  3. Plan Types
  4. Session Types
  5. Configuration Schemas
  6. Tool System Types
  7. MCP Types
  8. Plugin Types
  9. Planning Types
  10. Scaffold Types
  11. Auth Types
  12. API Database Schemas
  13. Entity Relationship Diagram
  14. Validation Rules Summary

1. Core CLI Types

Sources: src/types.ts

Intent

Classifies the user's request into one of six routing categories.

type Intent = "AWS" | "CODE" | "SHELL" | "GIT" | "DOCKER" | "GENERAL";
ValueDescription
AWSAWS CLI operations (S3, EC2, IAM, Lambda, etc.)
CODECode editing, refactoring, diff application
SHELLGeneral shell/OS commands
GITGit operations
DOCKERDocker operations
GENERALConversational or unclassified requests

ProviderName

type ProviderName = "openai" | "anthropic";

RouteDecision

The output of the intent routing engine.

type RouteDecision = {
  intent: Intent;
  complexity?: "simple" | "complex";
  matchedRules: string[];
  recommendedProvider?: ProviderName;
};
FieldTypeDescription
intentIntentClassified intent
complexity"simple" | "complex"Inferred from prompt signals
matchedRulesstring[]Rule names that triggered the classification
recommendedProviderProviderName?Optional provider hint

Complexity signals (from src/routing.ts):

  • Complex: set up, create, configure, refactor, implement, migrate, debug, fix, deploy, build, rewrite, restructure, convert, replace X with, add X to, change X to, move X to, split, merge, integrate
  • Simple: list, show, get, describe, check, what, read, search, find, explain, tell me, how does, count, status
  • Fallback: prompts longer than 200 characters are classified as complex

2. Provider & LLM Types

Sources: src/providers/provider.ts

ChatMessage

type ChatMessage =
  | { role: "user" | "assistant"; content: string }
  | { role: "tool"; toolCallId: string; content: string };

Note: Tool-role messages are filtered out before sending to both OpenAI and Anthropic APIs, as they reference function call IDs not present in the simplified history format.

ProviderRequest

type ProviderRequest = {
  prompt: string;
  system?: string;
  model?: string;
  taskType?: string;
  temperature?: number;
  history?: ChatMessage[];
  image?: { base64: string; mimeType: string };
  tools?: { name: string; description: string; parameters: Record<string, unknown> }[];
  thinking?: boolean;
};
FieldTypeDescription
promptstringThe user's current message
systemstring?System prompt override
modelstring?Model identifier
taskTypestring?Hint for routing/logging (e.g. "aws_translate", "compact")
temperaturenumber?Sampling temperature (0–2)
historyChatMessage[]?Prior conversation turns
imageobject?Base64-encoded image attachment
toolsarray?Tool schemas to expose to the model
thinkingboolean?Enable extended thinking (Anthropic only)

ToolCall

type ToolCall = {
  id: string;
  name: string;
  arguments: Record<string, unknown>;
};

ProviderResponse

type ProviderResponse = {
  provider: ProviderName;
  model: string;
  text: string;
  toolCalls?: ToolCall[];
  thinking?: string;
  usage?: {
    inputTokens?: number;
    outputTokens?: number;
    creditsCharged?: number;
    creditsPrecise?: number;
    creditsRemaining?: number | string;
  };
};

LlmProvider Interface

interface LlmProvider {
  readonly name: ProviderName;
  complete(req: ProviderRequest): Promise<ProviderResponse>;
  stream?(req: ProviderRequest): AsyncIterable<string>;
}

Three concrete implementations:

ClassSourceDescription
OpenAIProvidersrc/providers/openai.tsDirect OpenAI API (Responses API)
AnthropicProvidersrc/providers/anthropic.tsDirect Anthropic API with prompt caching
ApiProvidersrc/providers/api.tsSakura API proxy (used when logged in)

Provider-specific defaults:

ProviderDefault ModelMax TokensThinking
OpenAIgpt-5.2No
Anthropicclaude-sonnet-4-202505144096 (16000 with thinking)Yes
ApiProviderDelegates to server

ApiProvider payload constraints (to avoid API Gateway 30s timeout):

  • History capped at last 10 messages
  • Individual messages truncated at 3,000 characters

3. Plan Types

Sources: src/types.ts, src/planning/store.ts

PlanRisk

type PlanRisk = "readonly" | "mutating";

PlanBase

type PlanBase = {
  id: string;
  createdAt: string;       // ISO 8601
  summary: string;
  risk: PlanRisk;
  provenance: {
    provider: ProviderName | "none";
    model: string;
    routingRules: string[];
  };
};

AwsPlan

type AwsPlan = PlanBase & {
  type: "aws";
  aws: {
    argv: string[];          // CLI arguments without "aws" prefix
  };
};

CodePlan

type CodePlan = PlanBase & {
  type: "code";
  code: {
    patchUnifiedDiff: string;  // Unified diff format
  };
};

Plan

type Plan = AwsPlan | CodePlan;

Zod Schemas (Runtime Validation)

Sources: src/planning/store.ts

const ProvenanceSchema = z.object({
  provider: z.union([z.enum(["openai", "anthropic"]), z.literal("none")]),
  model: z.string(),
  routingRules: z.array(z.string())
});

const PlanBaseSchema = z.object({
  id: z.string(),
  createdAt: z.string(),
  summary: z.string(),
  risk: z.enum(["readonly", "mutating"]),
  provenance: ProvenanceSchema
});

const PlanSchema = z.discriminatedUnion("type", [
  PlanBaseSchema.extend({
    type: z.literal("aws"),
    aws: z.object({ argv: z.array(z.string()) })
  }),
  PlanBaseSchema.extend({
    type: z.literal("code"),
    code: z.object({ patchUnifiedDiff: z.string() })
  })
]);

Storage: Plans are persisted to .sakura/plans/<id>.json and .sakura/plans/latest.json.


4. Session Types

Sources: src/sessions/store.ts

Session

// Zod schema
const SessionSchema = z.object({
  id: z.string(),
  cwd: z.string(),
  createdAt: z.string(),   // ISO 8601
  updatedAt: z.string(),   // ISO 8601
  messages: z.array(
    z.object({
      role: z.enum(["user", "assistant"]),
      content: z.string()
    })
  )
});

type Session = z.infer<typeof SessionSchema>;

Note: Session IDs are derived from a SHA-1 hash of process.cwd() combined with the directory basename, producing stable per-project session identifiers.

Storage: Sessions are persisted to .sakura/sessions/<id>.json.

ReplContext

Sources: src/repl/types.ts

The live runtime state of the interactive REPL.

type ReplContext = {
  rl: readline.Interface;
  provider: LlmProvider;
  claudeProvider?: LlmProvider;    // Optional secondary Claude provider for handoff
  sessions: SessionStore;
  activeSession: Session;
  history: ChatMessage[];
  activeModel: string | undefined;
  temperature: number;
  pendingImage: ImageData | null;
  plannerMode: boolean;
  lastEditedPath?: string;
  opts: ReplOptions;
  config: SakuraConfig;
  updatePrompt: () => void;
};

ReplOptions

type ReplOptions = {
  configPath?: string;
  profile?: string;
  provider?: "openai" | "anthropic";
  model?: string;
  temperature?: number;
  trace?: boolean;
  resume?: boolean;
};

5. Configuration Schemas

Sources: src/config.ts

ProfileSchema

const ProfileSchema = z.object({
  provider: z.enum(["openai", "anthropic"]).default("openai"),
  model: z.string().optional(),
  temperature: z.number().min(0).max(2).default(0.2),
  awsProfile: z.string().optional(),
  awsRegion: z.string().optional()
});

type SakuraProfile = z.infer<typeof ProfileSchema>;

PhaseSchema

Controls the /phase command behavior for multi-phase project builds.

const PhaseSchema = z.object({
  language: z.enum(["typescript", "python", "go", "rust"]).default("typescript"),
  buildCommand: z.string().default("pnpm build"),
  lintCommand: z.string().optional(),
  referenceFiles: z.array(z.string()).default([]),
  projectContext: z.string().default(""),
});

ConfigSchema

const ConfigSchema = z.object({
  version: z.literal(1),
  defaultProfile: z.string().default("default"),
  profiles: z.record(ProfileSchema).default({
    default: { provider: "openai", model: "gpt-5.2", temperature: 0.2 }
  }),
  maxPlanAgeHours: z.number().min(0).default(4),
  phase: PhaseSchema.default({}),
});

type SakuraConfig = z.infer<typeof ConfigSchema>;

Default config file (.sakura/config.toml):

version = 1
defaultProfile = "default"

[profiles.default]
provider = "openai"
model = "gpt-5.2"
temperature = 0.2

[profiles.coding-claude]
provider = "anthropic"
model = "claude-sonnet-4-20250514"
temperature = 0.2

Settings

Sources: src/util/settings.ts

Runtime-adjustable settings stored in JSON (global: ~/.sakura-cli/settings.json, local: .sakura/settings.json).

type Settings = {
  model?: string;
  provider?: string;
  temperature?: number;
  theme?: boolean;
  autoCompactThreshold?: number;
  maxOutputChars?: number;
  trustMode?: "ask" | "trust-session";
};

6. Tool System Types

Sources: src/tools/registry.ts, src/tools/executor.ts

TrustLevel

type TrustLevel =
  | "trusted"           // Always executes without prompt
  | "trust_read_only"   // Auto-approves reads; prompts for writes/mutations
  | "trust_working_dir" // Auto-approves paths within cwd; prompts for outside
  | "not_trusted";      // Always prompts

ToolDefinition

type ToolDefinition = {
  name: string;
  description: string;
  trustLevel: TrustLevel;
  parameters: Record<string, unknown>;   // JSON Schema object
  execute: (args: Record<string, unknown>) => Promise<ToolResult>;
};

ToolResult

type ToolResult = {
  success: boolean;
  output: string;
  error?: string;
};

ToolCall

type ToolCall = {
  id: string;
  name: string;
  arguments: Record<string, unknown>;
};

Registered Tools

Sources: src/tools/index.ts, src/tools/implementations/

Tool NameTrust LevelDescription
readtrust_working_dirRead file or list directory
create_filetrustedCreate a new file (fails if exists)
edittrustedSurgically edit existing file (find_replace, insert_after, replace, delete)
shelltrustedRun shell command (skips approval in tool loop)
globtrust_working_dirFind files matching glob pattern
greptrust_working_dirRegex search across project files
codetrust_read_onlyAnalyze code structure (symbols, search, structure)
awstrust_read_onlyRun AWS CLI command
introspecttrustedQuery Sakura's own capabilities
sessionnot_trustedSession info
reportnot_trustedSignal report generation intent
subagentnot_trustedParallel subtask delegation
fetchtrustedHTTP fetch with HTML→text conversion
batch_createtrusted