diff --git a/apps/arc-web/app/lib/time.ts b/apps/arc-web/app/lib/time.ts
index abe6a6a98..cddcd4b16 100644
--- a/apps/arc-web/app/lib/time.ts
+++ b/apps/arc-web/app/lib/time.ts
@@ -11,3 +11,47 @@ export function timeAgo(iso: string): string {
const days = Math.floor(hours / 24);
return `${days}d ago`;
}
+
+/**
+ * Return a human-readable date label for grouping (e.g. "Today", "Yesterday", "Previous 7 days").
+ */
+function dateLabel(iso: string): string {
+ const now = new Date();
+ const date = new Date(iso);
+ const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate());
+ const startOfYesterday = new Date(startOfToday.getTime() - 86_400_000);
+ const startOf7DaysAgo = new Date(startOfToday.getTime() - 7 * 86_400_000);
+
+ if (date >= startOfToday) return "Today";
+ if (date >= startOfYesterday) return "Yesterday";
+ if (date >= startOf7DaysAgo) return "Previous 7 days";
+ return "Older";
+}
+
+interface SessionItem {
+ id: string;
+ title: string;
+ created_at: string;
+}
+
+interface SessionGroup {
+ label: string;
+ sessions: SessionItem[];
+}
+
+/**
+ * Group a flat list of sessions (already sorted newest-first) into date-labeled groups.
+ */
+export function groupSessionsByDate(sessions: SessionItem[]): SessionGroup[] {
+ const groups: SessionGroup[] = [];
+ let current: SessionGroup | undefined;
+ for (const s of sessions) {
+ const label = dateLabel(s.created_at);
+ if (!current || current.label !== label) {
+ current = { label, sessions: [] };
+ groups.push(current);
+ }
+ current.sessions.push(s);
+ }
+ return groups;
+}
diff --git a/apps/arc-web/app/routes/run-stages.tsx b/apps/arc-web/app/routes/run-stages.tsx
index dd33e23c8..0f36c4ff9 100644
--- a/apps/arc-web/app/routes/run-stages.tsx
+++ b/apps/arc-web/app/routes/run-stages.tsx
@@ -47,9 +47,12 @@ const statusConfig: Record
{tool.toolName}
- {tool.args}
+ {tool.durationMs != null && {tool.durationMs}ms}
+ {tool.input}
{open && (
-
Args
-
{tool.args}
+
Input
+
{tool.input}
Result
-
{tool.result}
+
{tool.result}
)}
@@ -137,9 +141,12 @@ export default function RunStages({ loaderData }: Route.ComponentProps) {
return {
kind: "tool" as const,
tools: t.tools.map((tu) => ({
+ id: tu.id,
toolName: tu.tool_name,
- args: tu.args,
+ input: tu.input,
result: tu.result,
+ isError: tu.is_error,
+ durationMs: tu.duration_ms,
})),
};
}
diff --git a/apps/arc-web/app/routes/session-detail.tsx b/apps/arc-web/app/routes/session-detail.tsx
index 5a078fd42..440e86527 100644
--- a/apps/arc-web/app/routes/session-detail.tsx
+++ b/apps/arc-web/app/routes/session-detail.tsx
@@ -9,9 +9,9 @@ import {
UserIcon,
WrenchScrewdriverIcon,
} from "@heroicons/react/24/outline";
-import { timeAgo } from "../lib/time";
+import { timeAgo, groupSessionsByDate } from "../lib/time";
import { apiJson } from "../api-client";
-import type { SessionDetail as ApiSessionDetail, PaginatedSessionGroupList } from "@qltysh/arc-api-client";
+import type { SessionDetail as ApiSessionDetail, PaginatedSessionList } from "@qltysh/arc-api-client";
import type { Route } from "./+types/session-detail";
export const handle = { hideHeader: true, wide: true };
@@ -21,9 +21,9 @@ export function meta({}: Route.MetaArgs) {
}
export async function loader({ request, params }: Route.LoaderArgs) {
- const [apiSession, { data: apiGroups }] = await Promise.all([
+ const [apiSession, { data: apiSessions }] = await Promise.all([
apiJson(`/sessions/${params.sessionId}`, { request }),
- apiJson("/sessions", { request }),
+ apiJson("/sessions", { request }),
]);
const session: Session = {
id: apiSession.id,
@@ -36,30 +36,31 @@ export async function loader({ request, params }: Route.LoaderArgs) {
return {
kind: "tool" as const,
tools: t.tools.map((tu) => ({
+ id: tu.id,
toolName: tu.tool_name,
- args: tu.args,
+ input: tu.input,
result: tu.result,
+ isError: tu.is_error,
+ durationMs: tu.duration_ms,
})),
};
}
return { kind: t.kind as "user" | "assistant", content: t.content ?? "", created_at: t.created_at };
}),
};
- const sessionGroups = apiGroups.map((g) => ({
- label: g.label,
- sessions: g.sessions.map((s) => ({
- id: s.id,
- title: s.title,
- created_at: s.created_at,
- })),
- }));
+ const sessionGroups = groupSessionsByDate(
+ apiSessions.map((s) => ({ id: s.id, title: s.title, created_at: s.created_at }))
+ );
return { session, sessionGroups };
}
interface ToolUse {
+ id: string;
toolName: string;
- args: string;
+ input: string;
result: string;
+ isError: boolean;
+ durationMs?: number;
}
type Turn =
@@ -98,19 +99,28 @@ const sessions: Record = {
kind: "tool",
tools: [
{
+ id: "toolu_s1_01",
toolName: "read_file",
- args: `{ "path": "src/routes/auth.ts" }`,
+ input: `{ "path": "src/routes/auth.ts" }`,
result: `import { Router } from "express";\nimport { loginHandler } from "../handlers/auth";\nimport { registerHandler } from "../handlers/auth";\n\nconst router = Router();\nrouter.post("/login", loginHandler);\nrouter.post("/register", registerHandler);\n\nexport default router;`,
+ isError: false,
+ durationMs: 45,
},
{
+ id: "toolu_s1_02",
toolName: "read_file",
- args: `{ "path": "src/middleware/index.ts" }`,
+ input: `{ "path": "src/middleware/index.ts" }`,
result: `export { authMiddleware } from "./auth";\nexport { corsMiddleware } from "./cors";\nexport { loggingMiddleware } from "./logging";`,
+ isError: false,
+ durationMs: 38,
},
{
+ id: "toolu_s1_03",
toolName: "search_files",
- args: `{ "pattern": "redis", "path": "src/" }`,
+ input: `{ "pattern": "redis", "path": "src/" }`,
result: `src/lib/redis.ts:1: import Redis from "ioredis";\nsrc/lib/redis.ts:3: export const redis = new Redis(process.env.REDIS_URL);`,
+ isError: false,
+ durationMs: 210,
},
],
},
@@ -122,19 +132,28 @@ const sessions: Record = {
kind: "tool",
tools: [
{
+ id: "toolu_s1_04",
toolName: "write_file",
- args: `{ "path": "src/middleware/rate-limit.ts" }`,
+ input: `{ "path": "src/middleware/rate-limit.ts" }`,
result: `File written: src/middleware/rate-limit.ts (47 lines)`,
+ isError: false,
+ durationMs: 65,
},
{
+ id: "toolu_s1_05",
toolName: "edit_file",
- args: `{ "path": "src/routes/auth.ts", "operations": [{ "type": "insert", "line": 3 }] }`,
+ input: `{ "path": "src/routes/auth.ts", "operations": [{ "type": "insert", "line": 3 }] }`,
result: `Applied 1 edit to src/routes/auth.ts`,
+ isError: false,
+ durationMs: 42,
},
{
+ id: "toolu_s1_06",
toolName: "edit_file",
- args: `{ "path": "src/middleware/index.ts", "operations": [{ "type": "append" }] }`,
+ input: `{ "path": "src/middleware/index.ts", "operations": [{ "type": "append" }] }`,
result: `Applied 1 edit to src/middleware/index.ts`,
+ isError: false,
+ durationMs: 55,
},
],
},
@@ -164,9 +183,12 @@ const sessions: Record = {
kind: "tool",
tools: [
{
+ id: "toolu_s2_01",
toolName: "read_file",
- args: `{ "path": "src/config/parser.ts" }`,
+ input: `{ "path": "src/config/parser.ts" }`,
result: `export function parseConfig(raw: string): Record {\n const result: Record = {};\n for (const line of raw.split("\\n")) {\n const match = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\n if (match) result[match[1]] = match[2].trim();\n }\n return result;\n}`,
+ isError: false,
+ durationMs: 52,
},
],
},
@@ -178,14 +200,20 @@ const sessions: Record = {
kind: "tool",
tools: [
{
+ id: "toolu_s2_02",
toolName: "write_file",
- args: `{ "path": "src/config/parser.ts" }`,
+ input: `{ "path": "src/config/parser.ts" }`,
result: `File written: src/config/parser.ts (62 lines)`,
+ isError: false,
+ durationMs: 78,
},
{
+ id: "toolu_s2_03",
toolName: "run_command",
- args: `{ "command": "npm test -- --grep 'config parser'" }`,
+ input: `{ "command": "npm test -- --grep 'config parser'" }`,
result: `PASS src/config/__tests__/parser.test.ts\n config parser\n ✓ parses flat keys (2ms)\n ✓ parses section headers (1ms)\n ✓ parses dotted keys (1ms)\n ✓ handles nested sections (1ms)\n\nTest Suites: 1 passed\nTests: 4 passed`,
+ isError: false,
+ durationMs: 2150,
},
],
},
@@ -207,8 +235,8 @@ const sessions: Record = {
{
kind: "tool",
tools: [
- { toolName: "search_files", args: `{ "pattern": "createBrowserRouter" }`, result: `src/main.tsx:5: import { createBrowserRouter } from "react-router-dom";\nsrc/main.tsx:8: const router = createBrowserRouter([` },
- { toolName: "read_file", args: `{ "path": "package.json" }`, result: `"react-router-dom": "^6.22.0"` },
+ { id: "toolu_s3_01", toolName: "search_files", input: `{ "pattern": "createBrowserRouter" }`, result: `src/main.tsx:5: import { createBrowserRouter } from "react-router-dom";\nsrc/main.tsx:8: const router = createBrowserRouter([`, isError: false, durationMs: 180 },
+ { id: "toolu_s3_02", toolName: "read_file", input: `{ "path": "package.json" }`, result: `"react-router-dom": "^6.22.0"`, isError: false, durationMs: 35 },
],
},
{ kind: "assistant", content: "You're on React Router 6.22. The migration to v7 involves:\n\n1. Replace `react-router-dom` with `react-router` (single package)\n2. Update `createBrowserRouter` import path\n3. Migrate data loaders to the new `Route.LoaderArgs` type\n4. Update any `useLoaderData` calls to be type-safe\n\nLet me make these changes." },
@@ -275,17 +303,18 @@ function ToolRow({ tool }: { tool: ToolUse }) {
{tool.toolName}
- {tool.args}
+ {tool.durationMs != null && {tool.durationMs}ms}
+ {tool.input}
{open && (
-
Args
-
{tool.args}
+
Input
+
{tool.input}
Result
-
{tool.result}
+
{tool.result}
)}
diff --git a/apps/arc-web/app/routes/start.tsx b/apps/arc-web/app/routes/start.tsx
index 7acd20c15..7c8bae253 100644
--- a/apps/arc-web/app/routes/start.tsx
+++ b/apps/arc-web/app/routes/start.tsx
@@ -20,10 +20,10 @@ import {
XMarkIcon,
} from "@heroicons/react/24/outline";
import { Link } from "react-router";
-import { timeAgo } from "../lib/time";
+import { timeAgo, groupSessionsByDate } from "../lib/time";
import { apiJson } from "../api-client";
import { getAppConfig } from "../lib/config.server";
-import type { PaginatedProjectList, PaginatedSessionGroupList } from "@qltysh/arc-api-client";
+import type { PaginatedProjectList, PaginatedSessionList } from "@qltysh/arc-api-client";
import type { Route } from "./+types/start";
export const handle = { hideHeader: true, wide: true };
@@ -36,17 +36,12 @@ export async function loader({ request }: Route.LoaderArgs) {
const { feature_flags } = getAppConfig();
const [{ data: apiProjects }, { data: apiSessions }] = await Promise.all([
apiJson("/projects", { request }),
- apiJson("/sessions", { request }),
+ apiJson("/sessions", { request }),
]);
const projects = apiProjects.map((p) => ({ id: p.id, name: p.name }));
- const sessionGroups = apiSessions.map((g) => ({
- label: g.label,
- sessions: g.sessions.map((s) => ({
- id: s.id,
- title: s.title,
- created_at: s.created_at,
- })),
- }));
+ const sessionGroups = groupSessionsByDate(
+ apiSessions.map((s) => ({ id: s.id, title: s.title, created_at: s.created_at }))
+ );
return { projects, sessionGroups, feature_flags };
}
diff --git a/crates/arc-api/src/demo/mod.rs b/crates/arc-api/src/demo/mod.rs
index 52022ad80..a0f8ee553 100644
--- a/crates/arc-api/src/demo/mod.rs
+++ b/crates/arc-api/src/demo/mod.rs
@@ -494,7 +494,7 @@ pub async fn list_sessions(
State(_state): State>,
Query(pagination): Query,
) -> Response {
- paginated_response(sessions::groups(), &pagination)
+ paginated_response(sessions::list_items(), &pagination)
}
pub async fn create_session_stub(
@@ -1033,8 +1033,8 @@ mod runs {
StageTurn {
kind: StageTurnKind::Tool, content: None,
tools: vec![
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "environments/production/config.toml" }"#.into(), result: "[redis]\nhost = \"redis-prod.internal\"\nport = 6379".into() },
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "environments/staging/config.toml" }"#.into(), result: "[redis]\nhost = \"redis-staging.internal\"\nport = 6379".into() },
+ ToolUse { id: "toolu_01".into(), tool_name: "read_file".into(), input: r#"{ "path": "environments/production/config.toml" }"#.into(), result: "[redis]\nhost = \"redis-prod.internal\"\nport = 6379".into(), is_error: false, duration_ms: Some(45) },
+ ToolUse { id: "toolu_02".into(), tool_name: "read_file".into(), input: r#"{ "path": "environments/staging/config.toml" }"#.into(), result: "[redis]\nhost = \"redis-staging.internal\"\nport = 6379".into(), is_error: false, duration_ms: Some(38) },
],
},
StageTurn { kind: StageTurnKind::Assistant, content: Some("I've detected drift in 3 resources between production and staging:\n\n1. **redis.max_connections** — production has 200, staging has 100\n2. **redis.tls** — enabled in production, disabled in staging\n3. **iam.session_duration** — production uses 3600s, staging uses 1800s".into()), tools: vec![] },
@@ -2367,62 +2367,47 @@ mod retros {
mod sessions {
use arc_types::*;
- pub fn groups() -> Vec {
+ pub fn list_items() -> Vec {
vec![
- SessionGroup {
- label: "Today".into(),
- sessions: vec![
- SessionListItem {
- id: "s1".into(),
- title: "Add rate limiting to auth endpoints".into(),
- created_at: "2026-03-06T14:30:00Z".into(),
- },
- SessionListItem {
- id: "s2".into(),
- title: "Fix config parsing for nested values".into(),
- created_at: "2026-03-06T12:30:00Z".into(),
- },
- ],
+ SessionListItem {
+ id: "s1".into(),
+ title: "Add rate limiting to auth endpoints".into(),
+ created_at: "2026-03-06T14:30:00Z".into(),
},
- SessionGroup {
- label: "Yesterday".into(),
- sessions: vec![
- SessionListItem {
- id: "s3".into(),
- title: "Migrate to React Router v7".into(),
- created_at: "2026-03-05T10:00:00Z".into(),
- },
- SessionListItem {
- id: "s4".into(),
- title: "Add dark mode toggle".into(),
- created_at: "2026-03-05T09:00:00Z".into(),
- },
- SessionListItem {
- id: "s5".into(),
- title: "Update OpenAPI spec for v3".into(),
- created_at: "2026-03-05T08:00:00Z".into(),
- },
- ],
+ SessionListItem {
+ id: "s2".into(),
+ title: "Fix config parsing for nested values".into(),
+ created_at: "2026-03-06T12:30:00Z".into(),
},
- SessionGroup {
- label: "Previous 7 days".into(),
- sessions: vec![
- SessionListItem {
- id: "s6".into(),
- title: "Terraform module for Redis cluster".into(),
- created_at: "2026-03-03T15:00:00Z".into(),
- },
- SessionListItem {
- id: "s7".into(),
- title: "Add pipeline event types".into(),
- created_at: "2026-03-01T11:00:00Z".into(),
- },
- SessionListItem {
- id: "s8".into(),
- title: "Implement webhook retry logic".into(),
- created_at: "2026-02-28T09:00:00Z".into(),
- },
- ],
+ SessionListItem {
+ id: "s3".into(),
+ title: "Migrate to React Router v7".into(),
+ created_at: "2026-03-05T10:00:00Z".into(),
+ },
+ SessionListItem {
+ id: "s4".into(),
+ title: "Add dark mode toggle".into(),
+ created_at: "2026-03-05T09:00:00Z".into(),
+ },
+ SessionListItem {
+ id: "s5".into(),
+ title: "Update OpenAPI spec for v3".into(),
+ created_at: "2026-03-05T08:00:00Z".into(),
+ },
+ SessionListItem {
+ id: "s6".into(),
+ title: "Terraform module for Redis cluster".into(),
+ created_at: "2026-03-03T15:00:00Z".into(),
+ },
+ SessionListItem {
+ id: "s7".into(),
+ title: "Add pipeline event types".into(),
+ created_at: "2026-03-01T11:00:00Z".into(),
+ },
+ SessionListItem {
+ id: "s8".into(),
+ title: "Implement webhook retry logic".into(),
+ created_at: "2026-02-28T09:00:00Z".into(),
},
]
}
@@ -2435,15 +2420,15 @@ mod sessions {
SessionTurn { kind: SessionTurnKind::User, content: Some("Add rate limiting to the auth endpoints. We're getting hit with brute force attempts on /api/auth/login and /api/auth/register. Use a sliding window approach with Redis, 10 requests per minute per IP.".into()), created_at: Some("2026-02-28T10:00:00Z".into()), tools: vec![] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("I'll implement sliding window rate limiting using Redis. Let me first look at the existing auth routes and middleware setup.".into()), created_at: None, tools: vec![] },
SessionTurn { kind: SessionTurnKind::Tool, content: None, created_at: None, tools: vec![
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "src/routes/auth.ts" }"#.into(), result: "import { Router } from \"express\";\nimport { loginHandler } from \"../handlers/auth\";\nimport { registerHandler } from \"../handlers/auth\";\n\nconst router = Router();\nrouter.post(\"/login\", loginHandler);\nrouter.post(\"/register\", registerHandler);\n\nexport default router;".into() },
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "src/middleware/index.ts" }"#.into(), result: "export { authMiddleware } from \"./auth\";\nexport { corsMiddleware } from \"./cors\";\nexport { loggingMiddleware } from \"./logging\";".into() },
- ToolUse { tool_name: "search_files".into(), args: r#"{ "pattern": "redis", "path": "src/" }"#.into(), result: "src/lib/redis.ts:1: import Redis from \"ioredis\";\nsrc/lib/redis.ts:3: export const redis = new Redis(process.env.REDIS_URL);".into() },
+ ToolUse { id: "toolu_03".into(), tool_name: "read_file".into(), input: r#"{ "path": "src/routes/auth.ts" }"#.into(), result: "import { Router } from \"express\";\nimport { loginHandler } from \"../handlers/auth\";\nimport { registerHandler } from \"../handlers/auth\";\n\nconst router = Router();\nrouter.post(\"/login\", loginHandler);\nrouter.post(\"/register\", registerHandler);\n\nexport default router;".into(), is_error: false, duration_ms: Some(52) },
+ ToolUse { id: "toolu_04".into(), tool_name: "read_file".into(), input: r#"{ "path": "src/middleware/index.ts" }"#.into(), result: "export { authMiddleware } from \"./auth\";\nexport { corsMiddleware } from \"./cors\";\nexport { loggingMiddleware } from \"./logging\";".into(), is_error: false, duration_ms: Some(35) },
+ ToolUse { id: "toolu_05".into(), tool_name: "search_files".into(), input: r#"{ "pattern": "redis", "path": "src/" }"#.into(), result: "src/lib/redis.ts:1: import Redis from \"ioredis\";\nsrc/lib/redis.ts:3: export const redis = new Redis(process.env.REDIS_URL);".into(), is_error: false, duration_ms: Some(180) },
] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("Good \u{2014} there's already a Redis client at `src/lib/redis.ts`. I'll create a rate limiting middleware using the sliding window algorithm and apply it to the auth routes.\n\nHere's the plan:\n1. Create `src/middleware/rate-limit.ts` with sliding window logic\n2. Apply it to `/login` and `/register` routes\n3. Return `429 Too Many Requests` when the limit is exceeded".into()), created_at: None, tools: vec![] },
SessionTurn { kind: SessionTurnKind::Tool, content: None, created_at: None, tools: vec![
- ToolUse { tool_name: "write_file".into(), args: r#"{ "path": "src/middleware/rate-limit.ts" }"#.into(), result: "File written: src/middleware/rate-limit.ts (47 lines)".into() },
- ToolUse { tool_name: "edit_file".into(), args: r#"{ "path": "src/routes/auth.ts", "operations": [{ "type": "insert", "line": 3 }] }"#.into(), result: "Applied 1 edit to src/routes/auth.ts".into() },
- ToolUse { tool_name: "edit_file".into(), args: r#"{ "path": "src/middleware/index.ts", "operations": [{ "type": "append" }] }"#.into(), result: "Applied 1 edit to src/middleware/index.ts".into() },
+ ToolUse { id: "toolu_06".into(), tool_name: "write_file".into(), input: r#"{ "path": "src/middleware/rate-limit.ts" }"#.into(), result: "File written: src/middleware/rate-limit.ts (47 lines)".into(), is_error: false, duration_ms: Some(62) },
+ ToolUse { id: "toolu_07".into(), tool_name: "edit_file".into(), input: r#"{ "path": "src/routes/auth.ts", "operations": [{ "type": "insert", "line": 3 }] }"#.into(), result: "Applied 1 edit to src/routes/auth.ts".into(), is_error: false, duration_ms: Some(41) },
+ ToolUse { id: "toolu_08".into(), tool_name: "edit_file".into(), input: r#"{ "path": "src/middleware/index.ts", "operations": [{ "type": "append" }] }"#.into(), result: "Applied 1 edit to src/middleware/index.ts".into(), is_error: false, duration_ms: Some(55) },
] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("Done. I've created the rate limiter and wired it up:\n\n- **`src/middleware/rate-limit.ts`** \u{2014} Sliding window rate limiter using Redis sorted sets. Each request adds a timestamped entry, expired entries are pruned, and the count is checked against the limit.\n- **`src/routes/auth.ts`** \u{2014} Applied `rateLimit({ windowMs: 60_000, max: 10 })` to both `/login` and `/register`.\n- **`src/middleware/index.ts`** \u{2014} Re-exported the new middleware.\n\nWhen the limit is exceeded, clients get a `429` response with a `Retry-After` header indicating seconds until the window resets.".into()), created_at: None, tools: vec![] },
],
@@ -2454,12 +2439,12 @@ mod sessions {
SessionTurn { kind: SessionTurnKind::User, content: Some("The CLI crashes when parsing nested TOML config values like [database.connection]. Can you debug and fix this?".into()), created_at: Some("2026-02-28T10:00:00Z".into()), tools: vec![] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("Let me look at the config parser to understand how nested keys are handled.".into()), created_at: None, tools: vec![] },
SessionTurn { kind: SessionTurnKind::Tool, content: None, created_at: None, tools: vec![
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "src/config/parser.ts" }"#.into(), result: "export function parseConfig(raw: string): Record {\n const result: Record = {};\n for (const line of raw.split(\"\\n\")) {\n const match = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\n if (match) result[match[1]] = match[2].trim();\n }\n return result;\n}".into() },
+ ToolUse { id: "toolu_09".into(), tool_name: "read_file".into(), input: r#"{ "path": "src/config/parser.ts" }"#.into(), result: "export function parseConfig(raw: string): Record {\n const result: Record = {};\n for (const line of raw.split(\"\\n\")) {\n const match = line.match(/^(\\w+)\\s*=\\s*(.+)$/);\n if (match) result[match[1]] = match[2].trim();\n }\n return result;\n}".into(), is_error: false, duration_ms: Some(67) },
] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("Found the issue. The parser uses a flat `Record` and the regex `^(\\w+)` only matches simple keys \u{2014} it can't handle TOML section headers like `[database.connection]` or dotted keys like `database.host`.\n\nI'll rewrite the parser to support nested sections and dotted keys, producing a properly nested object.".into()), created_at: None, tools: vec![] },
SessionTurn { kind: SessionTurnKind::Tool, content: None, created_at: None, tools: vec![
- ToolUse { tool_name: "write_file".into(), args: r#"{ "path": "src/config/parser.ts" }"#.into(), result: "File written: src/config/parser.ts (62 lines)".into() },
- ToolUse { tool_name: "run_command".into(), args: r#"{ "command": "npm test -- --grep 'config parser'" }"#.into(), result: "PASS src/config/__tests__/parser.test.ts\n config parser\n \u{2713} parses flat keys (2ms)\n \u{2713} parses section headers (1ms)\n \u{2713} parses dotted keys (1ms)\n \u{2713} handles nested sections (1ms)\n\nTest Suites: 1 passed\nTests: 4 passed".into() },
+ ToolUse { id: "toolu_10".into(), tool_name: "write_file".into(), input: r#"{ "path": "src/config/parser.ts" }"#.into(), result: "File written: src/config/parser.ts (62 lines)".into(), is_error: false, duration_ms: Some(78) },
+ ToolUse { id: "toolu_11".into(), tool_name: "run_command".into(), input: r#"{ "command": "npm test -- --grep 'config parser'" }"#.into(), result: "PASS src/config/__tests__/parser.test.ts\n config parser\n \u{2713} parses flat keys (2ms)\n \u{2713} parses section headers (1ms)\n \u{2713} parses dotted keys (1ms)\n \u{2713} handles nested sections (1ms)\n\nTest Suites: 1 passed\nTests: 4 passed".into(), is_error: false, duration_ms: Some(2150) },
] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("Fixed. The parser now:\n\n1. Tracks the current section header (e.g. `[database.connection]`)\n2. Constructs nested objects from dotted paths\n3. Handles both `key = value` within sections and bare `dotted.key = value` syntax\n\nAll 4 tests pass, including the new nested section case.".into()), created_at: None, tools: vec![] },
],
@@ -2470,8 +2455,8 @@ mod sessions {
SessionTurn { kind: SessionTurnKind::User, content: Some("Help me migrate our app from React Router v6 to v7. We're using createBrowserRouter with data loaders.".into()), created_at: Some("2026-02-26T10:00:00Z".into()), tools: vec![] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("I'll audit your current router setup and identify what needs to change for v7. Let me scan the codebase.".into()), created_at: None, tools: vec![] },
SessionTurn { kind: SessionTurnKind::Tool, content: None, created_at: None, tools: vec![
- ToolUse { tool_name: "search_files".into(), args: r#"{ "pattern": "createBrowserRouter" }"#.into(), result: "src/main.tsx:5: import { createBrowserRouter } from \"react-router-dom\";\nsrc/main.tsx:8: const router = createBrowserRouter([".into() },
- ToolUse { tool_name: "read_file".into(), args: r#"{ "path": "package.json" }"#.into(), result: "\"react-router-dom\": \"^6.22.0\"".into() },
+ ToolUse { id: "toolu_12".into(), tool_name: "search_files".into(), input: r#"{ "pattern": "createBrowserRouter" }"#.into(), result: "src/main.tsx:5: import { createBrowserRouter } from \"react-router-dom\";\nsrc/main.tsx:8: const router = createBrowserRouter([".into(), is_error: false, duration_ms: Some(220) },
+ ToolUse { id: "toolu_13".into(), tool_name: "read_file".into(), input: r#"{ "path": "package.json" }"#.into(), result: "\"react-router-dom\": \"^6.22.0\"".into(), is_error: false, duration_ms: Some(30) },
] },
SessionTurn { kind: SessionTurnKind::Assistant, content: Some("You're on React Router 6.22. The migration to v7 involves:\n\n1. Replace `react-router-dom` with `react-router` (single package)\n2. Update `createBrowserRouter` import path\n3. Migrate data loaders to the new `Route.LoaderArgs` type\n4. Update any `useLoaderData` calls to be type-safe\n\nLet me make these changes.".into()), created_at: None, tools: vec![] },
],
diff --git a/docs/api-reference/arc-api.yaml b/docs/api-reference/arc-api.yaml
deleted file mode 100644
index e3c58c57b..000000000
--- a/docs/api-reference/arc-api.yaml
+++ /dev/null
@@ -1,2381 +0,0 @@
-openapi: "3.1.0"
-info:
- title: Arc Run API
- version: "0.1.0"
- description: HTTP API for managing Arc workflow run executions.
-
-tags:
- - name: Discovery
- description: API discovery and health
- - name: Runs
- description: Run management operations
- - name: Human-in-the-Loop
- description: Questions, answers, and steering for runs
- - name: Run Outputs
- description: Files and verifications produced by runs
- - name: Run Internals
- description: Internal run details (stages, turns, context, configuration)
- - name: Workflows
- description: Workflow definitions and execution
- - name: Verifications
- description: Verification categories and controls
- - name: Usage
- description: Token and cost usage
- - name: Insights
- description: SQL query editor and history
- - name: Sessions
- description: Interactive chat sessions
- - name: Retros
- description: Run retrospectives
- - name: Projects
- description: Project and branch management
- - name: Settings
- description: Platform configuration
-
-paths:
- # ── Discovery ────────────────────────────────────────────────────────
-
- /:
- get:
- operationId: getRoot
- tags: [Discovery]
- summary: API Discovery
- description: Returns discovery URLs for the API.
- responses:
- "200":
- description: Discovery URLs
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/RootResponse"
-
- /health:
- get:
- operationId: getHealth
- tags: [Discovery]
- summary: Health Check
- responses:
- "200":
- description: Service is healthy
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/HealthResponse"
-
- /openapi.json:
- get:
- operationId: getOpenApiSpec
- tags: [Discovery]
- summary: OpenAPI Specification
- description: Returns the OpenAPI spec as JSON.
- responses:
- "200":
- description: OpenAPI specification
- content:
- application/json:
- schema:
- type: object
-
- /user:
- get:
- operationId: getUser
- tags: [Discovery]
- summary: Current User
- description: Returns info about the authenticated user.
- responses:
- "200":
- description: User info
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/UserResponse"
- "401":
- description: Not authenticated
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- # ── Runs ──────────────────────────────────────────────────────────────
-
- /runs:
- get:
- operationId: listRuns
- tags: [Runs]
- summary: List Runs
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of runs for the board view
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedRunList"
- post:
- operationId: startRun
- tags: [Runs]
- summary: Start Run
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/StartRunRequest"
- responses:
- "201":
- description: Run created
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/StartRunResponse"
- "400":
- description: Invalid DOT source
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}:
- get:
- operationId: retrieveRun
- tags: [Runs]
- summary: Retrieve Run
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Run status
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/RunStatusResponse"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/cancel:
- post:
- operationId: cancelRun
- tags: [Runs]
- summary: Cancel Run
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Run cancelled
- content:
- application/json:
- schema:
- type: object
- properties:
- cancelled:
- type: boolean
- required:
- - cancelled
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- "409":
- description: Run is not running
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/graph:
- get:
- operationId: retrieveRunSvg
- tags: [Runs]
- summary: Render SVG
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: SVG image of the workflow graph
- content:
- image/svg+xml:
- schema:
- type: string
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- "502":
- description: Graphviz not available
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/checkpoint:
- get:
- operationId: retrieveRunCheckpoint
- tags: [Run Internals]
- summary: Retrieve Run Checkpoint
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Checkpoint data (null if not yet available)
- content:
- application/json:
- schema: {}
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/context:
- get:
- operationId: retrieveRunContext
- tags: [Run Internals]
- summary: Retrieve Run Context
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Context key-value map
- content:
- application/json:
- schema:
- type: object
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/events:
- get:
- operationId: streamRunEvents
- tags: [Runs]
- summary: Stream Run Events
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Server-sent event stream
- content:
- text/event-stream:
- schema:
- type: string
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- "410":
- description: Event stream closed
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/questions:
- get:
- operationId: listRunQuestions
- tags: [Human-in-the-Loop]
- summary: List Run Questions
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Array of pending questions
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedApiQuestionList"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/questions/{qid}/answer:
- post:
- operationId: submitRunAnswer
- tags: [Human-in-the-Loop]
- summary: Submit Run Answer
- parameters:
- - $ref: "#/components/parameters/RunId"
- - name: qid
- in: path
- required: true
- schema:
- type: string
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SubmitAnswerRequest"
- responses:
- "200":
- description: Answer accepted or rejected
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SubmitAnswerResponse"
- "400":
- description: Invalid option key
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/retro:
- get:
- operationId: retrieveRetro
- tags: [Retros]
- summary: Retrieve Retro
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Retro data (null if not yet available)
- content:
- application/json:
- schema: {}
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/stages:
- get:
- operationId: listRunStages
- tags: [Run Internals]
- summary: List Run Stages
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Array of run stages
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedRunStageList"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/stages/{stageId}/turns:
- get:
- operationId: listStageTurns
- tags: [Run Internals]
- summary: List Stage Turns
- parameters:
- - $ref: "#/components/parameters/RunId"
- - name: stageId
- in: path
- required: true
- schema:
- type: string
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of conversation turns
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedStageTurnList"
- "404":
- description: Run or stage not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/compare:
- get:
- operationId: listRunCompare
- tags: [Run Outputs]
- summary: List Run Compare
- parameters:
- - $ref: "#/components/parameters/RunId"
- - name: checkpoint
- in: query
- schema:
- type: string
- default: "all"
- responses:
- "200":
- description: File changes with checkpoint metadata
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/RunCompare"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/usage:
- get:
- operationId: retrieveRunUsage
- tags: [Run Outputs]
- summary: Retrieve Run Usage
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Usage data
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/RunUsage"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/verifications:
- get:
- operationId: listRunVerifications
- tags: [Run Outputs]
- summary: List Run Verifications
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Array of verification categories with controls
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedRunVerificationList"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/configuration:
- get:
- operationId: retrieveRunConfiguration
- tags: [Run Internals]
- summary: Retrieve Run Configuration
- parameters:
- - $ref: "#/components/parameters/RunId"
- responses:
- "200":
- description: Configuration content
- content:
- text/plain:
- schema:
- type: string
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/steer:
- post:
- operationId: steerRun
- tags: [Human-in-the-Loop]
- summary: Steer Run
- parameters:
- - $ref: "#/components/parameters/RunId"
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SteerRequest"
- responses:
- "200":
- description: Steering accepted
- content:
- application/json:
- schema:
- type: object
- properties:
- accepted:
- type: boolean
- required:
- - accepted
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /runs/{id}/preview:
- post:
- operationId: generatePreviewUrl
- tags: [Human-in-the-Loop]
- summary: Preview URL
- parameters:
- - $ref: "#/components/parameters/RunId"
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PreviewUrlRequest"
- responses:
- "200":
- description: Preview URL generated
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PreviewUrlResponse"
- "404":
- description: Run not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- # ── Workflows ─────────────────────────────────────────────────────────
-
- /workflows:
- get:
- operationId: listWorkflows
- tags: [Workflows]
- summary: List Workflows
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of workflows
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedWorkflowList"
-
- /workflows/{name}:
- get:
- operationId: retrieveWorkflow
- tags: [Workflows]
- summary: Retrieve Workflow
- parameters:
- - name: name
- in: path
- required: true
- schema:
- type: string
- responses:
- "200":
- description: Workflow detail
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/WorkflowDetail"
- "404":
- description: Workflow not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /workflows/{name}/runs:
- get:
- operationId: listWorkflowRuns
- tags: [Workflows]
- summary: List Workflow Runs
- parameters:
- - name: name
- in: path
- required: true
- schema:
- type: string
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of runs
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedRunList"
- "404":
- description: Workflow not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- post:
- operationId: startWorkflowRun
- tags: [Workflows]
- summary: Start Workflow Run
- parameters:
- - name: name
- in: path
- required: true
- schema:
- type: string
- responses:
- "201":
- description: Run created
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/StartRunResponse"
- "404":
- description: Workflow not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- # ── Verifications ─────────────────────────────────────────────────────
-
- /verifications:
- get:
- operationId: listVerifications
- tags: [Verifications]
- summary: List Verifications
- responses:
- "200":
- description: Array of verification categories
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedVerificationCategoryList"
-
- /verifications/{slug}:
- get:
- operationId: retrieveVerification
- tags: [Verifications]
- summary: Retrieve Verification
- parameters:
- - name: slug
- in: path
- required: true
- schema:
- type: string
- responses:
- "200":
- description: Verification control detail
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/VerificationDetailResponse"
- "404":
- description: Control not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- # ── Retros ────────────────────────────────────────────────────────────
-
- /retros:
- get:
- operationId: listRetros
- tags: [Retros]
- summary: List Retros
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of retros
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedRetroList"
-
- # ── Sessions ──────────────────────────────────────────────────────────
-
- /sessions:
- get:
- operationId: listSessions
- tags: [Sessions]
- summary: List Sessions
- description: Returns sessions grouped by recency (e.g. "Today", "Yesterday"). Each group contains a flat list of session summaries.
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of session groups
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedSessionGroupList"
- post:
- operationId: createSession
- tags: [Sessions]
- summary: Create Session
- description: Start a new interactive chat session. The initial user prompt is required; a model may optionally be specified.
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/CreateSessionRequest"
- responses:
- "201":
- description: Session created
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/CreateSessionResponse"
-
- /sessions/{id}:
- get:
- operationId: retrieveSession
- tags: [Sessions]
- summary: Retrieve Session
- description: Returns the full session detail including all conversation turns.
- parameters:
- - name: id
- in: path
- required: true
- description: Unique session identifier.
- schema:
- type: string
- example: s1
- responses:
- "200":
- description: Session detail
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SessionDetail"
- "404":
- description: Session not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /sessions/{id}/messages:
- post:
- operationId: sendSessionMessage
- tags: [Sessions]
- summary: Send Session Message
- description: Append a user message to an existing session. The server will process it and produce assistant and tool turns asynchronously via the event stream.
- parameters:
- - name: id
- in: path
- required: true
- description: Unique session identifier.
- schema:
- type: string
- example: s1
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SendMessageRequest"
- responses:
- "200":
- description: Message accepted
- content:
- application/json:
- schema:
- type: object
- properties:
- accepted:
- type: boolean
- description: Whether the message was accepted for processing.
- example: true
- required:
- - accepted
- "404":
- description: Session not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /sessions/{id}/events:
- get:
- operationId: streamSessionEvents
- tags: [Sessions]
- summary: Stream Session Events
- description: Opens a server-sent event (SSE) stream for real-time session updates. Events include new assistant turns, tool invocations, and completion signals.
- parameters:
- - name: id
- in: path
- required: true
- description: Unique session identifier.
- schema:
- type: string
- example: s1
- responses:
- "200":
- description: Server-sent event stream
- content:
- text/event-stream:
- schema:
- type: string
- "404":
- description: Session not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- # ── Insights ──────────────────────────────────────────────────────────
-
- /insights/queries:
- get:
- operationId: listSavedQueries
- tags: [Insights]
- summary: List Saved Queries
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of saved queries
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedSavedQueryList"
- post:
- operationId: createSavedQuery
- tags: [Insights]
- summary: Create Saved Query
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SaveQueryRequest"
- responses:
- "201":
- description: Query saved
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SavedQuery"
-
- /insights/queries/{id}:
- put:
- operationId: updateSavedQuery
- tags: [Insights]
- summary: Update Saved Query
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SaveQueryRequest"
- responses:
- "200":
- description: Query updated
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/SavedQuery"
- "404":
- description: Query not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
- delete:
- operationId: deleteSavedQuery
- tags: [Insights]
- summary: Delete Saved Query
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- responses:
- "204":
- description: Query deleted
- "404":
- description: Query not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
- /insights/execute:
- post:
- operationId: executeQuery
- tags: [Insights]
- summary: Execute Query
- requestBody:
- required: true
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ExecuteQueryRequest"
- responses:
- "200":
- description: Query results
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ExecuteQueryResponse"
-
- /insights/history:
- get:
- operationId: listQueryHistory
- tags: [Insights]
- summary: List Query History
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of history entries
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedHistoryEntryList"
-
- # ── Usage ────────────────────────────────────────────────────────────
-
- /usage:
- get:
- operationId: getAggregateUsage
- tags: [Usage]
- summary: Aggregate Usage
- description: Returns aggregate token/cost usage across all completed runs since server start.
- responses:
- "200":
- description: Aggregate usage data
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/AggregateUsage"
-
- # ── Settings ──────────────────────────────────────────────────────────
-
- /settings:
- get:
- operationId: retrieveServerSettings
- tags: [Settings]
- summary: Retrieve Server Settings
- responses:
- "200":
- description: Array of setting groups
- content:
- application/json:
- schema:
- type: array
- items:
- $ref: "#/components/schemas/SettingGroup"
-
- # ── Projects ──────────────────────────────────────────────────────────
-
- /projects:
- get:
- operationId: listProjects
- tags: [Projects]
- summary: List Projects
- parameters:
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of projects
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedProjectList"
-
- /projects/{id}/branches:
- get:
- operationId: listBranches
- tags: [Projects]
- summary: List Branches
- parameters:
- - name: id
- in: path
- required: true
- schema:
- type: string
- - $ref: "#/components/parameters/PageLimit"
- - $ref: "#/components/parameters/PageOffset"
- responses:
- "200":
- description: Paginated list of branches
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/PaginatedBranchList"
- "404":
- description: Project not found
- content:
- application/json:
- schema:
- $ref: "#/components/schemas/ErrorResponse"
-
-components:
- parameters:
- RunId:
- name: id
- in: path
- required: true
- schema:
- type: string
-
- PageLimit:
- name: page[limit]
- in: query
- required: false
- schema:
- type: integer
- minimum: 1
- maximum: 100
- default: 20
-
- PageOffset:
- name: page[offset]
- in: query
- required: false
- schema:
- type: integer
- minimum: 0
- default: 0
-
- schemas:
- PaginationMeta:
- type: object
- required:
- - has_more
- properties:
- has_more:
- type: boolean
-
- PaginatedRunList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/RunListItem"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedWorkflowList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/WorkflowListItem"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedRetroList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/RetroListItem"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedSessionGroupList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/SessionGroup"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedProjectList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/Project"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedBranchList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/Branch"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedSavedQueryList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/SavedQuery"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedHistoryEntryList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/HistoryEntry"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedStageTurnList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/StageTurn"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedApiQuestionList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/ApiQuestion"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedRunStageList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/RunStage"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedRunVerificationList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/RunVerification"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- PaginatedVerificationCategoryList:
- type: object
- required:
- - data
- - meta
- properties:
- data:
- type: array
- items:
- $ref: "#/components/schemas/VerificationCategory"
- meta:
- $ref: "#/components/schemas/PaginationMeta"
-
- # ── Existing Run Schemas ────────────────────────────────────────────
-
- RunStatus:
- type: string
- enum:
- - queued
- - starting
- - running
- - completed
- - failed
- - cancelled
-
- StartRunRequest:
- type: object
- required:
- - dot_source
- properties:
- dot_source:
- type: string
-
- StartRunResponse:
- type: object
- required:
- - id
- properties:
- id:
- type: string
-
- RunStatusResponse:
- type: object
- required:
- - id
- - status
- properties:
- id:
- type: string
- status:
- $ref: "#/components/schemas/RunStatus"
- error:
- type: string
- queue_position:
- type: integer
-
- ApiQuestionOption:
- type: object
- required:
- - key
- - label
- properties:
- key:
- type: string
- label:
- type: string
-
- ApiQuestion:
- type: object
- required:
- - id
- - text
- - question_type
- - options
- - allow_freeform
- properties:
- id:
- type: string
- text:
- type: string
- question_type:
- $ref: "#/components/schemas/QuestionType"
- options:
- type: array
- items:
- $ref: "#/components/schemas/ApiQuestionOption"
- allow_freeform:
- type: boolean
-
- QuestionType:
- type: string
- enum:
- - yes_no
- - multiple_choice
- - multi_select
- - freeform
- - confirmation
-
- SubmitAnswerRequest:
- type: object
- required:
- - value
- properties:
- value:
- type: string
- selected_option_key:
- type: string
-
- SubmitAnswerResponse:
- type: object
- required:
- - accepted
- properties:
- accepted:
- type: boolean
-
- ErrorResponseEntry:
- type: object
- required:
- - status
- - title
- - detail
- properties:
- status:
- type: string
- title:
- type: string
- detail:
- type: string
-
- ErrorResponse:
- type: object
- required:
- - errors
- properties:
- errors:
- type: array
- items:
- $ref: "#/components/schemas/ErrorResponseEntry"
-
- # ── New Run Schemas ─────────────────────────────────────────────────
-
- RunListItemStatus:
- type: string
- enum:
- - working
- - pending
- - review
- - merge
-
- CheckRunStatus:
- type: string
- enum:
- - success
- - failure
- - skipped
- - pending
- - queued
-
- CheckRun:
- type: object
- required:
- - name
- - status
- properties:
- name:
- type: string
- status:
- $ref: "#/components/schemas/CheckRunStatus"
- duration_secs:
- type: number
-
- RunListItem:
- type: object
- required:
- - id
- - repo
- - title
- - workflow
- - status
- properties:
- id:
- type: string
- repo:
- type: string
- title:
- type: string
- workflow:
- type: string
- status:
- $ref: "#/components/schemas/RunListItemStatus"
- number:
- type: integer
- additions:
- type: integer
- deletions:
- type: integer
- checks:
- type: array
- items:
- $ref: "#/components/schemas/CheckRun"
- elapsed_secs:
- type: number
- elapsed_warning:
- type: boolean
- resources:
- type: string
- comments:
- type: integer
- question:
- type: string
- sandbox_id:
- type: string
-
- StageStatus:
- type: string
- enum:
- - completed
- - running
- - pending
- - failed
-
- RunStage:
- type: object
- required:
- - id
- - name
- - status
- properties:
- id:
- type: string
- name:
- type: string
- status:
- $ref: "#/components/schemas/StageStatus"
- duration_secs:
- type: number
- dot_id:
- type: string
-
- ToolUse:
- description: A single tool invocation with its arguments and result.
- type: object
- required:
- - tool_name
- - args
- - result
- properties:
- tool_name:
- type: string
- description: Name of the tool that was invoked.
- example: read_file
- args:
- type: string
- description: JSON-encoded arguments passed to the tool.
- example: '{ "path": "src/routes/auth.ts" }'
- result:
- type: string
- description: Output returned by the tool.
- example: 'import { Router } from "express";'
-
- StageTurn:
- type: object
- required:
- - kind
- properties:
- kind:
- type: string
- enum:
- - system
- - assistant
- - tool
- content:
- type: string
- tools:
- type: array
- items:
- $ref: "#/components/schemas/ToolUse"
-
- FileCheckpoint:
- type: object
- required:
- - id
- - label
- properties:
- id:
- type: string
- label:
- type: string
-
- DiffFile:
- type: object
- required:
- - name
- - contents
- properties:
- name:
- type: string
- contents:
- type: string
-
- FileDiff:
- type: object
- required:
- - old_file
- - new_file
- properties:
- old_file:
- $ref: "#/components/schemas/DiffFile"
- new_file:
- $ref: "#/components/schemas/DiffFile"
-
- DiffStats:
- type: object
- required:
- - additions
- - deletions
- properties:
- additions:
- type: integer
- deletions:
- type: integer
-
- RunCompare:
- type: object
- required:
- - checkpoints
- - files
- - stats
- properties:
- checkpoints:
- type: array
- items:
- $ref: "#/components/schemas/FileCheckpoint"
- files:
- type: array
- items:
- $ref: "#/components/schemas/FileDiff"
- stats:
- $ref: "#/components/schemas/DiffStats"
-
- UsageStage:
- type: object
- required:
- - stage
- - model
- - input_tokens
- - output_tokens
- - runtime_secs
- - cost
- properties:
- stage:
- type: string
- model:
- type: string
- input_tokens:
- type: integer
- output_tokens:
- type: integer
- runtime_secs:
- type: number
- cost:
- type: number
-
- UsageTotals:
- type: object
- required:
- - runtime_secs
- - input_tokens
- - output_tokens
- - cost
- properties:
- runtime_secs:
- type: number
- input_tokens:
- type: integer
- output_tokens:
- type: integer
- cost:
- type: number
-
- UsageByModel:
- type: object
- required:
- - model
- - stages
- - input_tokens
- - output_tokens
- - cost
- properties:
- model:
- type: string
- stages:
- type: integer
- input_tokens:
- type: integer
- output_tokens:
- type: integer
- cost:
- type: number
-
- RunUsage:
- type: object
- required:
- - stages
- - totals
- - by_model
- properties:
- stages:
- type: array
- items:
- $ref: "#/components/schemas/UsageStage"
- totals:
- $ref: "#/components/schemas/UsageTotals"
- by_model:
- type: array
- items:
- $ref: "#/components/schemas/UsageByModel"
-
- AggregateUsage:
- type: object
- required:
- - total_runs
- - total_input_tokens
- - total_output_tokens
- - total_cost
- - total_runtime_secs
- - by_model
- properties:
- total_runs:
- type: integer
- total_input_tokens:
- type: integer
- total_output_tokens:
- type: integer
- total_cost:
- type: number
- total_runtime_secs:
- type: number
- by_model:
- type: array
- items:
- $ref: "#/components/schemas/UsageByModel"
-
- VerificationStatus:
- type: string
- enum:
- - pass
- - fail
- - na
-
- VerificationType:
- type: string
- enum:
- - ai
- - automated
- - analysis
- - ai-analysis
-
- RunVerificationControl:
- type: object
- required:
- - name
- - description
- - status
- properties:
- name:
- type: string
- description:
- type: string
- type:
- $ref: "#/components/schemas/VerificationType"
- status:
- $ref: "#/components/schemas/VerificationStatus"
-
- RunVerification:
- type: object
- required:
- - name
- - question
- - status
- - controls
- properties:
- name:
- type: string
- question:
- type: string
- status:
- $ref: "#/components/schemas/VerificationStatus"
- controls:
- type: array
- items:
- $ref: "#/components/schemas/RunVerificationControl"
-
- SteerRequest:
- type: object
- required:
- - file
- - line
- - guidance
- properties:
- file:
- type: string
- line:
- type: integer
- guidance:
- type: string
-
- PreviewUrlRequest:
- type: object
- required:
- - port
- - expires_in_secs
- properties:
- port:
- type: integer
- expires_in_secs:
- type: integer
-
- PreviewUrlResponse:
- type: object
- required:
- - url
- properties:
- url:
- type: string
-
- # ── Workflow Schemas ─────────────────────────────────────────────────
-
- WorkflowListItem:
- type: object
- required:
- - name
- - slug
- - filename
- properties:
- name:
- type: string
- slug:
- type: string
- filename:
- type: string
- last_run:
- type: string
- schedule:
- type: string
- next_run:
- type: string
-
- WorkflowDetail:
- type: object
- required:
- - title
- - slug
- - filename
- - description
- - config
- - graph
- properties:
- title:
- type: string
- slug:
- type: string
- filename:
- type: string
- description:
- type: string
- config:
- type: string
- graph:
- type: string
-
- # ── Verification Schemas ────────────────────────────────────────────
-
- EvaluationResult:
- type: string
- enum:
- - pass
- - fail
- - skip
-
- VerificationMode:
- type: string
- enum:
- - active
- - evaluate
- - disabled
-
- VerificationControl:
- type: object
- required:
- - name
- - slug
- - description
- properties:
- name:
- type: string
- slug:
- type: string
- description:
- type: string
- type:
- $ref: "#/components/schemas/VerificationType"
- mode:
- $ref: "#/components/schemas/VerificationMode"
- f1:
- type: number
- pass_at_1:
- type: number
- evaluations:
- type: array
- items:
- $ref: "#/components/schemas/EvaluationResult"
-
- VerificationCategory:
- type: object
- required:
- - name
- - question
- - controls
- properties:
- name:
- type: string
- question:
- type: string
- controls:
- type: array
- items:
- $ref: "#/components/schemas/VerificationControl"
-
- ControlInfo:
- type: object
- required:
- - name
- - slug
- - description
- - category
- properties:
- name:
- type: string
- slug:
- type: string
- description:
- type: string
- type:
- $ref: "#/components/schemas/VerificationType"
- category:
- type: string
-
- ControlPerformance:
- type: object
- required:
- - mode
- - evaluations
- properties:
- mode:
- $ref: "#/components/schemas/VerificationMode"
- f1:
- type: number
- pass_at_1:
- type: number
- evaluations:
- type: array
- items:
- $ref: "#/components/schemas/EvaluationResult"
-
- ControlDetail:
- type: object
- required:
- - description
- - checks
- - pass_example
- - fail_example
- properties:
- description:
- type: string
- checks:
- type: array
- items:
- type: string
- pass_example:
- type: string
- fail_example:
- type: string
-
- RecentControlResult:
- type: object
- required:
- - run_id
- - run_title
- - workflow
- - result
- - timestamp
- properties:
- run_id:
- type: string
- run_title:
- type: string
- workflow:
- type: string
- result:
- $ref: "#/components/schemas/VerificationStatus"
- timestamp:
- type: string
-
- SiblingControl:
- type: object
- required:
- - name
- - slug
- properties:
- name:
- type: string
- slug:
- type: string
- type:
- $ref: "#/components/schemas/VerificationType"
- mode:
- $ref: "#/components/schemas/VerificationMode"
-
- VerificationDetailResponse:
- type: object
- required:
- - control
- - performance
- - control_detail
- - recent_results
- - siblings
- properties:
- control:
- $ref: "#/components/schemas/ControlInfo"
- performance:
- $ref: "#/components/schemas/ControlPerformance"
- control_detail:
- $ref: "#/components/schemas/ControlDetail"
- recent_results:
- type: array
- items:
- $ref: "#/components/schemas/RecentControlResult"
- siblings:
- type: array
- items:
- $ref: "#/components/schemas/SiblingControl"
-
- # ── Retro Schemas ───────────────────────────────────────────────────
-
- SmoothnessRating:
- type: string
- enum:
- - effortless
- - smooth
- - bumpy
- - struggled
- - failed
-
- RetroStats:
- type: object
- required:
- - total_duration_ms
- - total_retries
- - files_touched
- - stages_completed
- - stages_failed
- properties:
- total_duration_ms:
- type: integer
- total_cost:
- type: number
- total_retries:
- type: integer
- files_touched:
- type: array
- items:
- type: string
- stages_completed:
- type: integer
- stages_failed:
- type: integer
-
- RetroListItem:
- type: object
- required:
- - run_id
- - workflow_name
- - goal
- - timestamp
- - stats
- - friction_point_count
- properties:
- run_id:
- type: string
- workflow_name:
- type: string
- goal:
- type: string
- timestamp:
- type: string
- smoothness:
- $ref: "#/components/schemas/SmoothnessRating"
- stats:
- $ref: "#/components/schemas/RetroStats"
- friction_point_count:
- type: integer
-
- # ── Session Schemas ─────────────────────────────────────────────────
-
- SessionListItem:
- description: Summary of a session shown in list views.
- type: object
- required:
- - id
- - title
- - created_at
- properties:
- id:
- type: string
- description: Unique session identifier.
- example: s1
- title:
- type: string
- description: Short title summarizing the session topic.
- example: Add rate limiting to auth endpoints
- created_at:
- type: string
- description: ISO 8601 timestamp when the session was created.
- example: "2026-03-06T14:30:00Z"
-
- SessionGroup:
- description: A group of sessions sharing a time-based label (e.g. "Today", "Yesterday").
- type: object
- required:
- - label
- - sessions
- properties:
- label:
- type: string
- description: Human-readable group heading.
- example: Today
- sessions:
- type: array
- description: Sessions belonging to this group, ordered by recency.
- items:
- $ref: "#/components/schemas/SessionListItem"
-
- SessionTurn:
- description: A single turn in a session conversation — a user message, assistant response, or tool invocation block.
- type: object
- required:
- - kind
- properties:
- kind:
- type: string
- description: The type of turn.
- enum:
- - user
- - assistant
- - tool
- example: user
- content:
- type: string
- description: Text content of the turn. Present for user and assistant turns, absent for tool turns.
- example: Add rate limiting to the auth endpoints using a sliding window approach with Redis.
- created_at:
- type: string
- description: ISO 8601 timestamp when the turn was created. Typically present for user turns.
- example: "2026-02-28T10:00:00Z"
- tools:
- type: array
- description: Tool invocations for this turn. Present only when kind is "tool".
- items:
- $ref: "#/components/schemas/ToolUse"
-
- SessionDetail:
- description: Full session record including metadata and the complete conversation history.
- type: object
- required:
- - id
- - title
- - model
- - created_at
- - updated_at
- - turns
- properties:
- id:
- type: string
- description: Unique session identifier.
- example: s1
- title:
- type: string
- description: Short title summarizing the session topic.
- example: Add rate limiting to auth endpoints
- model:
- type: string
- description: The LLM model used for this session.
- example: Opus 4.6
- created_at:
- type: string
- description: ISO 8601 timestamp when the session was created.
- example: "2026-03-06T14:30:00Z"
- updated_at:
- type: string
- description: ISO 8601 timestamp when the session was last updated (e.g. new turn added).
- example: "2026-03-06T15:45:00Z"
- turns:
- type: array
- description: Ordered list of conversation turns.
- items:
- $ref: "#/components/schemas/SessionTurn"
-
- CreateSessionRequest:
- description: Request body for starting a new session.
- type: object
- required:
- - prompt
- properties:
- prompt:
- type: string
- description: The initial user message to start the session.
- example: Add rate limiting to the auth endpoints using a sliding window approach with Redis, 10 requests per minute per IP.
- model:
- type: string
- description: LLM model to use. If omitted, the server default is used.
- example: Opus 4.6
-
- CreateSessionResponse:
- description: Response returned after successfully creating a session.
- type: object
- required:
- - id
- - created_at
- properties:
- id:
- type: string
- description: Unique identifier for the newly created session.
- example: s42
- created_at:
- type: string
- description: ISO 8601 timestamp when the session was created.
- example: "2026-03-06T16:00:00Z"
-
- SendMessageRequest:
- description: Request body for sending a follow-up message in an existing session.
- type: object
- required:
- - content
- properties:
- content:
- type: string
- description: The user message text.
- example: Can you also add a bypass for internal health-check IPs?
-
- # ── Insights Schemas ────────────────────────────────────────────────
-
- SavedQuery:
- type: object
- required:
- - id
- - name
- - sql
- properties:
- id:
- type: string
- name:
- type: string
- sql:
- type: string
-
- SaveQueryRequest:
- type: object
- required:
- - name
- - sql
- properties:
- name:
- type: string
- sql:
- type: string
-
- ExecuteQueryRequest:
- type: object
- required:
- - sql
- properties:
- sql:
- type: string
-
- ExecuteQueryResponse:
- type: object
- required:
- - columns
- - rows
- - elapsed
- - row_count
- properties:
- columns:
- type: array
- items:
- type: string
- rows:
- type: array
- items:
- type: array
- items: {}
- elapsed:
- type: number
- row_count:
- type: integer
-
- HistoryEntry:
- type: object
- required:
- - id
- - sql
- - timestamp
- - elapsed
- - row_count
- properties:
- id:
- type: string
- sql:
- type: string
- timestamp:
- type: string
- elapsed:
- type: number
- row_count:
- type: integer
-
- # ── Settings Schemas ────────────────────────────────────────────────
-
- SettingFieldType:
- type: string
- enum:
- - text
- - select
- - toggle
-
- SettingField:
- type: object
- required:
- - key
- - label
- - value
- - type
- properties:
- key:
- type: string
- label:
- type: string
- value:
- type: string
- type:
- $ref: "#/components/schemas/SettingFieldType"
- options:
- type: array
- items:
- type: string
- description:
- type: string
-
- SettingGroup:
- type: object
- required:
- - id
- - name
- - description
- - fields
- properties:
- id:
- type: string
- name:
- type: string
- description:
- type: string
- fields:
- type: array
- items:
- $ref: "#/components/schemas/SettingField"
-
- # ── Project Schemas ─────────────────────────────────────────────────
-
- Project:
- type: object
- required:
- - id
- - name
- properties:
- id:
- type: string
- name:
- type: string
-
- Branch:
- type: object
- required:
- - id
- - name
- properties:
- id:
- type: string
- name:
- type: string
-
- # ── Discovery Schemas ──────────────────────────────────────────────
-
- RootResponseUrls:
- type: object
- required:
- - openapi_url
- - current_user_url
- - health_url
- properties:
- openapi_url:
- type: string
- current_user_url:
- type: string
- health_url:
- type: string
-
- RootResponse:
- type: object
- required:
- - urls
- properties:
- urls:
- $ref: "#/components/schemas/RootResponseUrls"
-
- HealthResponse:
- type: object
- required:
- - status
- properties:
- status:
- type: string
-
- UserResponse:
- type: object
- required:
- - login
- properties:
- login:
- type: string
diff --git a/docs/api-reference/arc-api.yaml b/docs/api-reference/arc-api.yaml
new file mode 120000
index 000000000..3f32abfbd
--- /dev/null
+++ b/docs/api-reference/arc-api.yaml
@@ -0,0 +1 @@
+../../openapi/arc-api.yaml
\ No newline at end of file
diff --git a/openapi/arc-api.yaml b/openapi/arc-api.yaml
index e3c58c57b..2fed54edf 100644
--- a/openapi/arc-api.yaml
+++ b/openapi/arc-api.yaml
@@ -719,17 +719,17 @@ paths:
operationId: listSessions
tags: [Sessions]
summary: List Sessions
- description: Returns sessions grouped by recency (e.g. "Today", "Yesterday"). Each group contains a flat list of session summaries.
+ description: Returns sessions ordered by recency (newest first).
parameters:
- $ref: "#/components/parameters/PageLimit"
- $ref: "#/components/parameters/PageOffset"
responses:
"200":
- description: Paginated list of session groups
+ description: Paginated list of sessions
content:
application/json:
schema:
- $ref: "#/components/schemas/PaginatedSessionGroupList"
+ $ref: "#/components/schemas/PaginatedSessionList"
post:
operationId: createSession
tags: [Sessions]
@@ -1120,7 +1120,7 @@ components:
meta:
$ref: "#/components/schemas/PaginationMeta"
- PaginatedSessionGroupList:
+ PaginatedSessionList:
type: object
required:
- data
@@ -1129,7 +1129,7 @@ components:
data:
type: array
items:
- $ref: "#/components/schemas/SessionGroup"
+ $ref: "#/components/schemas/SessionListItem"
meta:
$ref: "#/components/schemas/PaginationMeta"
@@ -1478,25 +1478,39 @@ components:
type: string
ToolUse:
- description: A single tool invocation with its arguments and result.
+ description: A single tool invocation with its input, result, and execution metadata.
type: object
required:
+ - id
- tool_name
- - args
+ - input
- result
+ - is_error
properties:
+ id:
+ type: string
+ description: Unique identifier for this tool invocation. Enables correlation in parallel tool use.
+ example: toolu_01A09q90qw90lq917835lq9
tool_name:
type: string
description: Name of the tool that was invoked.
example: read_file
- args:
+ input:
type: string
- description: JSON-encoded arguments passed to the tool.
+ description: JSON-encoded input passed to the tool.
example: '{ "path": "src/routes/auth.ts" }'
result:
type: string
- description: Output returned by the tool.
+ description: Output returned by the tool. Contains the error message when is_error is true.
example: 'import { Router } from "express";'
+ is_error:
+ type: boolean
+ description: Whether the tool invocation failed. When true, the result field contains the error message.
+ example: false
+ duration_ms:
+ type: integer
+ description: Wall-clock execution time of the tool invocation in milliseconds.
+ example: 142
StageTurn:
type: object
@@ -2064,22 +2078,6 @@ components:
description: ISO 8601 timestamp when the session was created.
example: "2026-03-06T14:30:00Z"
- SessionGroup:
- description: A group of sessions sharing a time-based label (e.g. "Today", "Yesterday").
- type: object
- required:
- - label
- - sessions
- properties:
- label:
- type: string
- description: Human-readable group heading.
- example: Today
- sessions:
- type: array
- description: Sessions belonging to this group, ordered by recency.
- items:
- $ref: "#/components/schemas/SessionListItem"
SessionTurn:
description: A single turn in a session conversation — a user message, assistant response, or tool invocation block.
diff --git a/packages/arc-api-client/src/.openapi-generator/FILES b/packages/arc-api-client/src/.openapi-generator/FILES
index 7f6e4c830..79c109885 100644
--- a/packages/arc-api-client/src/.openapi-generator/FILES
+++ b/packages/arc-api-client/src/.openapi-generator/FILES
@@ -49,7 +49,7 @@ models/paginated-run-list.ts
models/paginated-run-stage-list.ts
models/paginated-run-verification-list.ts
models/paginated-saved-query-list.ts
-models/paginated-session-group-list.ts
+models/paginated-session-list.ts
models/paginated-stage-turn-list.ts
models/paginated-verification-category-list.ts
models/paginated-workflow-list.ts
@@ -75,8 +75,8 @@ models/run-verification.ts
models/save-query-request.ts
models/saved-query.ts
models/send-message-request.ts
+models/send-session-message200-response.ts
models/session-detail.ts
-models/session-group.ts
models/session-list-item.ts
models/session-turn.ts
models/setting-field-type.ts
diff --git a/packages/arc-api-client/src/api/sessions-api.ts b/packages/arc-api-client/src/api/sessions-api.ts
index 08623201f..1fbd95fad 100644
--- a/packages/arc-api-client/src/api/sessions-api.ts
+++ b/packages/arc-api-client/src/api/sessions-api.ts
@@ -28,20 +28,20 @@ import type { CreateSessionResponse } from '../models';
// @ts-ignore
import type { ErrorResponse } from '../models';
// @ts-ignore
-import type { PaginatedSessionGroupList } from '../models';
+import type { PaginatedSessionList } from '../models';
// @ts-ignore
import type { SendMessageRequest } from '../models';
// @ts-ignore
-import type { SessionDetail } from '../models';
+import type { SendSessionMessage200Response } from '../models';
// @ts-ignore
-import type { SteerRun200Response } from '../models';
+import type { SessionDetail } from '../models';
/**
* SessionsApi - axios parameter creator
*/
export const SessionsApiAxiosParamCreator = function (configuration?: Configuration) {
return {
/**
- *
+ * Start a new interactive chat session. The initial user prompt is required; a model may optionally be specified.
* @summary Create Session
* @param {CreateSessionRequest} createSessionRequest
* @param {*} [options] Override http request option.
@@ -76,7 +76,7 @@ export const SessionsApiAxiosParamCreator = function (configuration?: Configurat
};
},
/**
- *
+ * Returns sessions ordered by recency (newest first).
* @summary List Sessions
* @param {number} [pageLimit]
* @param {number} [pageOffset]
@@ -116,9 +116,9 @@ export const SessionsApiAxiosParamCreator = function (configuration?: Configurat
};
},
/**
- *
+ * Returns the full session detail including all conversation turns.
* @summary Retrieve Session
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -150,9 +150,9 @@ export const SessionsApiAxiosParamCreator = function (configuration?: Configurat
};
},
/**
- *
+ * Append a user message to an existing session. The server will process it and produce assistant and tool turns asynchronously via the event stream.
* @summary Send Session Message
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {SendMessageRequest} sendMessageRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
@@ -189,9 +189,9 @@ export const SessionsApiAxiosParamCreator = function (configuration?: Configurat
};
},
/**
- *
+ * Opens a server-sent event (SSE) stream for real-time session updates. Events include new assistant turns, tool invocations, and completion signals.
* @summary Stream Session Events
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -232,7 +232,7 @@ export const SessionsApiFp = function(configuration?: Configuration) {
const localVarAxiosParamCreator = SessionsApiAxiosParamCreator(configuration)
return {
/**
- *
+ * Start a new interactive chat session. The initial user prompt is required; a model may optionally be specified.
* @summary Create Session
* @param {CreateSessionRequest} createSessionRequest
* @param {*} [options] Override http request option.
@@ -245,23 +245,23 @@ export const SessionsApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- *
+ * Returns sessions ordered by recency (newest first).
* @summary List Sessions
* @param {number} [pageLimit]
* @param {number} [pageOffset]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async listSessions(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ async listSessions(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
const localVarAxiosArgs = await localVarAxiosParamCreator.listSessions(pageLimit, pageOffset, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['SessionsApi.listSessions']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- *
+ * Returns the full session detail including all conversation turns.
* @summary Retrieve Session
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -272,23 +272,23 @@ export const SessionsApiFp = function(configuration?: Configuration) {
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- *
+ * Append a user message to an existing session. The server will process it and produce assistant and tool turns asynchronously via the event stream.
* @summary Send Session Message
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {SendMessageRequest} sendMessageRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- async sendSessionMessage(id: string, sendMessageRequest: SendMessageRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
+ async sendSessionMessage(id: string, sendMessageRequest: SendMessageRequest, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> {
const localVarAxiosArgs = await localVarAxiosParamCreator.sendSessionMessage(id, sendMessageRequest, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['SessionsApi.sendSessionMessage']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
- *
+ * Opens a server-sent event (SSE) stream for real-time session updates. Events include new assistant turns, tool invocations, and completion signals.
* @summary Stream Session Events
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -308,7 +308,7 @@ export const SessionsApiFactory = function (configuration?: Configuration, baseP
const localVarFp = SessionsApiFp(configuration)
return {
/**
- *
+ * Start a new interactive chat session. The initial user prompt is required; a model may optionally be specified.
* @summary Create Session
* @param {CreateSessionRequest} createSessionRequest
* @param {*} [options] Override http request option.
@@ -318,20 +318,20 @@ export const SessionsApiFactory = function (configuration?: Configuration, baseP
return localVarFp.createSession(createSessionRequest, options).then((request) => request(axios, basePath));
},
/**
- *
+ * Returns sessions ordered by recency (newest first).
* @summary List Sessions
* @param {number} [pageLimit]
* @param {number} [pageOffset]
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- listSessions(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): AxiosPromise {
+ listSessions(pageLimit?: number, pageOffset?: number, options?: RawAxiosRequestConfig): AxiosPromise {
return localVarFp.listSessions(pageLimit, pageOffset, options).then((request) => request(axios, basePath));
},
/**
- *
+ * Returns the full session detail including all conversation turns.
* @summary Retrieve Session
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -339,20 +339,20 @@ export const SessionsApiFactory = function (configuration?: Configuration, baseP
return localVarFp.retrieveSession(id, options).then((request) => request(axios, basePath));
},
/**
- *
+ * Append a user message to an existing session. The server will process it and produce assistant and tool turns asynchronously via the event stream.
* @summary Send Session Message
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {SendMessageRequest} sendMessageRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
- sendSessionMessage(id: string, sendMessageRequest: SendMessageRequest, options?: RawAxiosRequestConfig): AxiosPromise {
+ sendSessionMessage(id: string, sendMessageRequest: SendMessageRequest, options?: RawAxiosRequestConfig): AxiosPromise {
return localVarFp.sendSessionMessage(id, sendMessageRequest, options).then((request) => request(axios, basePath));
},
/**
- *
+ * Opens a server-sent event (SSE) stream for real-time session updates. Events include new assistant turns, tool invocations, and completion signals.
* @summary Stream Session Events
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -367,7 +367,7 @@ export const SessionsApiFactory = function (configuration?: Configuration, baseP
*/
export class SessionsApi extends BaseAPI {
/**
- *
+ * Start a new interactive chat session. The initial user prompt is required; a model may optionally be specified.
* @summary Create Session
* @param {CreateSessionRequest} createSessionRequest
* @param {*} [options] Override http request option.
@@ -378,7 +378,7 @@ export class SessionsApi extends BaseAPI {
}
/**
- *
+ * Returns sessions ordered by recency (newest first).
* @summary List Sessions
* @param {number} [pageLimit]
* @param {number} [pageOffset]
@@ -390,9 +390,9 @@ export class SessionsApi extends BaseAPI {
}
/**
- *
+ * Returns the full session detail including all conversation turns.
* @summary Retrieve Session
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
@@ -401,9 +401,9 @@ export class SessionsApi extends BaseAPI {
}
/**
- *
+ * Append a user message to an existing session. The server will process it and produce assistant and tool turns asynchronously via the event stream.
* @summary Send Session Message
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {SendMessageRequest} sendMessageRequest
* @param {*} [options] Override http request option.
* @throws {RequiredError}
@@ -413,9 +413,9 @@ export class SessionsApi extends BaseAPI {
}
/**
- *
+ * Opens a server-sent event (SSE) stream for real-time session updates. Events include new assistant turns, tool invocations, and completion signals.
* @summary Stream Session Events
- * @param {string} id
+ * @param {string} id Unique session identifier.
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
diff --git a/packages/arc-api-client/src/models/create-session-request.ts b/packages/arc-api-client/src/models/create-session-request.ts
index ec352d207..2a1028542 100644
--- a/packages/arc-api-client/src/models/create-session-request.ts
+++ b/packages/arc-api-client/src/models/create-session-request.ts
@@ -14,8 +14,17 @@
+/**
+ * Request body for starting a new session.
+ */
export interface CreateSessionRequest {
+ /**
+ * The initial user message to start the session.
+ */
'prompt': string;
+ /**
+ * LLM model to use. If omitted, the server default is used.
+ */
'model'?: string;
}
diff --git a/packages/arc-api-client/src/models/create-session-response.ts b/packages/arc-api-client/src/models/create-session-response.ts
index 922847e54..1d0938e67 100644
--- a/packages/arc-api-client/src/models/create-session-response.ts
+++ b/packages/arc-api-client/src/models/create-session-response.ts
@@ -14,8 +14,17 @@
+/**
+ * Response returned after successfully creating a session.
+ */
export interface CreateSessionResponse {
+ /**
+ * Unique identifier for the newly created session.
+ */
'id': string;
+ /**
+ * ISO 8601 timestamp when the session was created.
+ */
'created_at': string;
}
diff --git a/packages/arc-api-client/src/models/index.ts b/packages/arc-api-client/src/models/index.ts
index 95c40a7bb..86c20dfc7 100644
--- a/packages/arc-api-client/src/models/index.ts
+++ b/packages/arc-api-client/src/models/index.ts
@@ -30,7 +30,7 @@ export * from './paginated-run-list';
export * from './paginated-run-stage-list';
export * from './paginated-run-verification-list';
export * from './paginated-saved-query-list';
-export * from './paginated-session-group-list';
+export * from './paginated-session-list';
export * from './paginated-stage-turn-list';
export * from './paginated-verification-category-list';
export * from './paginated-workflow-list';
@@ -56,8 +56,8 @@ export * from './run-verification-control';
export * from './save-query-request';
export * from './saved-query';
export * from './send-message-request';
+export * from './send-session-message200-response';
export * from './session-detail';
-export * from './session-group';
export * from './session-list-item';
export * from './session-turn';
export * from './setting-field';
diff --git a/packages/arc-api-client/src/models/paginated-session-list.ts b/packages/arc-api-client/src/models/paginated-session-list.ts
new file mode 100644
index 000000000..1997ccb14
--- /dev/null
+++ b/packages/arc-api-client/src/models/paginated-session-list.ts
@@ -0,0 +1,27 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Arc Run API
+ * HTTP API for managing Arc workflow run executions.
+ *
+ * The version of the OpenAPI document: 0.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+// May contain unused imports in some cases
+// @ts-ignore
+import type { PaginationMeta } from './pagination-meta';
+// May contain unused imports in some cases
+// @ts-ignore
+import type { SessionListItem } from './session-list-item';
+
+export interface PaginatedSessionList {
+ 'data': Array;
+ 'meta': PaginationMeta;
+}
+
diff --git a/packages/arc-api-client/src/models/send-message-request.ts b/packages/arc-api-client/src/models/send-message-request.ts
index 21dc454ad..e0769b24f 100644
--- a/packages/arc-api-client/src/models/send-message-request.ts
+++ b/packages/arc-api-client/src/models/send-message-request.ts
@@ -14,7 +14,13 @@
+/**
+ * Request body for sending a follow-up message in an existing session.
+ */
export interface SendMessageRequest {
+ /**
+ * The user message text.
+ */
'content': string;
}
diff --git a/packages/arc-api-client/src/models/send-session-message200-response.ts b/packages/arc-api-client/src/models/send-session-message200-response.ts
new file mode 100644
index 000000000..f59e634d4
--- /dev/null
+++ b/packages/arc-api-client/src/models/send-session-message200-response.ts
@@ -0,0 +1,23 @@
+/* tslint:disable */
+/* eslint-disable */
+/**
+ * Arc Run API
+ * HTTP API for managing Arc workflow run executions.
+ *
+ * The version of the OpenAPI document: 0.1.0
+ *
+ *
+ * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
+ * https://openapi-generator.tech
+ * Do not edit the class manually.
+ */
+
+
+
+export interface SendSessionMessage200Response {
+ /**
+ * Whether the message was accepted for processing.
+ */
+ 'accepted': boolean;
+}
+
diff --git a/packages/arc-api-client/src/models/session-detail.ts b/packages/arc-api-client/src/models/session-detail.ts
index 4b6c3fca2..66fbdd085 100644
--- a/packages/arc-api-client/src/models/session-detail.ts
+++ b/packages/arc-api-client/src/models/session-detail.ts
@@ -17,12 +17,33 @@
// @ts-ignore
import type { SessionTurn } from './session-turn';
+/**
+ * Full session record including metadata and the complete conversation history.
+ */
export interface SessionDetail {
+ /**
+ * Unique session identifier.
+ */
'id': string;
+ /**
+ * Short title summarizing the session topic.
+ */
'title': string;
+ /**
+ * The LLM model used for this session.
+ */
'model': string;
+ /**
+ * ISO 8601 timestamp when the session was created.
+ */
'created_at': string;
+ /**
+ * ISO 8601 timestamp when the session was last updated (e.g. new turn added).
+ */
'updated_at': string;
+ /**
+ * Ordered list of conversation turns.
+ */
'turns': Array;
}
diff --git a/packages/arc-api-client/src/models/session-group.ts b/packages/arc-api-client/src/models/session-group.ts
index c9f6a546f..967666b59 100644
--- a/packages/arc-api-client/src/models/session-group.ts
+++ b/packages/arc-api-client/src/models/session-group.ts
@@ -17,8 +17,17 @@
// @ts-ignore
import type { SessionListItem } from './session-list-item';
+/**
+ * A group of sessions sharing a time-based label (e.g. \"Today\", \"Yesterday\").
+ */
export interface SessionGroup {
+ /**
+ * Human-readable group heading.
+ */
'label': string;
+ /**
+ * Sessions belonging to this group, ordered by recency.
+ */
'sessions': Array;
}
diff --git a/packages/arc-api-client/src/models/session-list-item.ts b/packages/arc-api-client/src/models/session-list-item.ts
index aabe1169b..26dfcaa5f 100644
--- a/packages/arc-api-client/src/models/session-list-item.ts
+++ b/packages/arc-api-client/src/models/session-list-item.ts
@@ -14,9 +14,21 @@
+/**
+ * Summary of a session shown in list views.
+ */
export interface SessionListItem {
+ /**
+ * Unique session identifier.
+ */
'id': string;
+ /**
+ * Short title summarizing the session topic.
+ */
'title': string;
+ /**
+ * ISO 8601 timestamp when the session was created.
+ */
'created_at': string;
}
diff --git a/packages/arc-api-client/src/models/session-turn.ts b/packages/arc-api-client/src/models/session-turn.ts
index 207102692..20d21f64f 100644
--- a/packages/arc-api-client/src/models/session-turn.ts
+++ b/packages/arc-api-client/src/models/session-turn.ts
@@ -17,10 +17,25 @@
// @ts-ignore
import type { ToolUse } from './tool-use';
+/**
+ * A single turn in a session conversation — a user message, assistant response, or tool invocation block.
+ */
export interface SessionTurn {
+ /**
+ * The type of turn.
+ */
'kind': SessionTurnKindEnum;
+ /**
+ * Text content of the turn. Present for user and assistant turns, absent for tool turns.
+ */
'content'?: string;
+ /**
+ * ISO 8601 timestamp when the turn was created. Typically present for user turns.
+ */
'created_at'?: string;
+ /**
+ * Tool invocations for this turn. Present only when kind is \"tool\".
+ */
'tools'?: Array;
}
diff --git a/packages/arc-api-client/src/models/tool-use.ts b/packages/arc-api-client/src/models/tool-use.ts
index 33f697c54..28a878d1a 100644
--- a/packages/arc-api-client/src/models/tool-use.ts
+++ b/packages/arc-api-client/src/models/tool-use.ts
@@ -14,9 +14,33 @@
+/**
+ * A single tool invocation with its input, result, and execution metadata.
+ */
export interface ToolUse {
+ /**
+ * Unique identifier for this tool invocation. Enables correlation in parallel tool use.
+ */
+ 'id': string;
+ /**
+ * Name of the tool that was invoked.
+ */
'tool_name': string;
- 'args': string;
+ /**
+ * JSON-encoded input passed to the tool.
+ */
+ 'input': string;
+ /**
+ * Output returned by the tool. Contains the error message when is_error is true.
+ */
'result': string;
+ /**
+ * Whether the tool invocation failed. When true, the result field contains the error message.
+ */
+ 'is_error': boolean;
+ /**
+ * Wall-clock execution time of the tool invocation in milliseconds.
+ */
+ 'duration_ms'?: number;
}