@stackbilt/aegis-core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/package.json +96 -0
  2. package/schema.sql +586 -0
  3. package/src/adapters/voice/cloudflare-agent.ts +34 -0
  4. package/src/auth.ts +124 -0
  5. package/src/bluesky.ts +464 -0
  6. package/src/claude-tools/content.ts +188 -0
  7. package/src/claude-tools/email.ts +69 -0
  8. package/src/claude-tools/github.ts +440 -0
  9. package/src/claude-tools/goals.ts +116 -0
  10. package/src/claude-tools/index.ts +353 -0
  11. package/src/claude-tools/web.ts +59 -0
  12. package/src/claude.ts +406 -0
  13. package/src/codebeast.ts +200 -0
  14. package/src/composite.ts +715 -0
  15. package/src/content/column.ts +80 -0
  16. package/src/content/hero-image.ts +47 -0
  17. package/src/content/index.ts +27 -0
  18. package/src/content/journal.ts +91 -0
  19. package/src/content/roundtable.ts +163 -0
  20. package/src/core.ts +309 -0
  21. package/src/dashboard.ts +620 -0
  22. package/src/decision-docs.ts +284 -0
  23. package/src/dispatch.ts +13 -0
  24. package/src/edge-env.ts +58 -0
  25. package/src/email.ts +850 -0
  26. package/src/exports.ts +156 -0
  27. package/src/github-projects.ts +312 -0
  28. package/src/github.ts +670 -0
  29. package/src/groq.ts +247 -0
  30. package/src/health-page.ts +578 -0
  31. package/src/index.ts +89 -0
  32. package/src/kernel/argus-actions.ts +397 -0
  33. package/src/kernel/argus-correlation.ts +639 -0
  34. package/src/kernel/board.ts +91 -0
  35. package/src/kernel/briefing.ts +177 -0
  36. package/src/kernel/classify-memory-topic.ts +166 -0
  37. package/src/kernel/cognition.ts +377 -0
  38. package/src/kernel/court-cards.ts +163 -0
  39. package/src/kernel/dispatch.ts +587 -0
  40. package/src/kernel/domain.ts +50 -0
  41. package/src/kernel/dynamic-tools.ts +322 -0
  42. package/src/kernel/executor-port.ts +45 -0
  43. package/src/kernel/executors/claude.ts +73 -0
  44. package/src/kernel/executors/direct.ts +237 -0
  45. package/src/kernel/executors/groq.ts +18 -0
  46. package/src/kernel/executors/index.ts +87 -0
  47. package/src/kernel/executors/tarotscript.ts +104 -0
  48. package/src/kernel/executors/workers-ai.ts +54 -0
  49. package/src/kernel/insight-cache.ts +76 -0
  50. package/src/kernel/memory/agenda.ts +200 -0
  51. package/src/kernel/memory/blocks.ts +188 -0
  52. package/src/kernel/memory/consolidation.ts +194 -0
  53. package/src/kernel/memory/episodic.ts +241 -0
  54. package/src/kernel/memory/goals.ts +156 -0
  55. package/src/kernel/memory/graph.ts +290 -0
  56. package/src/kernel/memory/index.ts +11 -0
  57. package/src/kernel/memory/insights.ts +316 -0
  58. package/src/kernel/memory/procedural.ts +467 -0
  59. package/src/kernel/memory/pruning.ts +67 -0
  60. package/src/kernel/memory/recall.ts +367 -0
  61. package/src/kernel/memory/semantic.ts +315 -0
  62. package/src/kernel/memory/synthesis.ts +161 -0
  63. package/src/kernel/memory-adapter.ts +369 -0
  64. package/src/kernel/memory-guardrails.ts +76 -0
  65. package/src/kernel/port.ts +23 -0
  66. package/src/kernel/resilience.ts +322 -0
  67. package/src/kernel/router.ts +471 -0
  68. package/src/kernel/scheduled/agent-dispatch.ts +252 -0
  69. package/src/kernel/scheduled/argus-analytics.ts +247 -0
  70. package/src/kernel/scheduled/argus-heartbeat.ts +320 -0
  71. package/src/kernel/scheduled/argus-notify.ts +348 -0
  72. package/src/kernel/scheduled/board-sync.ts +110 -0
  73. package/src/kernel/scheduled/ci-watcher.ts +125 -0
  74. package/src/kernel/scheduled/cognitive-metrics.ts +377 -0
  75. package/src/kernel/scheduled/consolidation.ts +229 -0
  76. package/src/kernel/scheduled/content-drip.ts +47 -0
  77. package/src/kernel/scheduled/content.ts +6 -0
  78. package/src/kernel/scheduled/conversation-facts.ts +204 -0
  79. package/src/kernel/scheduled/cost-report.ts +84 -0
  80. package/src/kernel/scheduled/curiosity.ts +219 -0
  81. package/src/kernel/scheduled/dev-activity.ts +44 -0
  82. package/src/kernel/scheduled/digest.ts +317 -0
  83. package/src/kernel/scheduled/dreaming/agenda-triage.ts +115 -0
  84. package/src/kernel/scheduled/dreaming/facts.ts +239 -0
  85. package/src/kernel/scheduled/dreaming/index.ts +8 -0
  86. package/src/kernel/scheduled/dreaming/llm.ts +33 -0
  87. package/src/kernel/scheduled/dreaming/pattern-synthesis.ts +124 -0
  88. package/src/kernel/scheduled/dreaming/persona.ts +75 -0
  89. package/src/kernel/scheduled/dreaming/symbolic.ts +31 -0
  90. package/src/kernel/scheduled/dreaming/task-proposals.ts +80 -0
  91. package/src/kernel/scheduled/dreaming.ts +66 -0
  92. package/src/kernel/scheduled/entropy.ts +149 -0
  93. package/src/kernel/scheduled/escalation.ts +192 -0
  94. package/src/kernel/scheduled/feed-watcher.ts +206 -0
  95. package/src/kernel/scheduled/goals.ts +214 -0
  96. package/src/kernel/scheduled/governance.ts +41 -0
  97. package/src/kernel/scheduled/heartbeat.ts +220 -0
  98. package/src/kernel/scheduled/inbox-processor.ts +174 -0
  99. package/src/kernel/scheduled/index.ts +245 -0
  100. package/src/kernel/scheduled/issue-proposer.ts +478 -0
  101. package/src/kernel/scheduled/issue-watcher.ts +128 -0
  102. package/src/kernel/scheduled/pr-automerge.ts +213 -0
  103. package/src/kernel/scheduled/product-health.ts +107 -0
  104. package/src/kernel/scheduled/reflection.ts +373 -0
  105. package/src/kernel/scheduled/self-improvement.ts +114 -0
  106. package/src/kernel/scheduled/social-engage.ts +175 -0
  107. package/src/kernel/scheduled/task-audit.ts +60 -0
  108. package/src/kernel/symbolic.ts +156 -0
  109. package/src/kernel/types.ts +145 -0
  110. package/src/landing.ts +1190 -0
  111. package/src/lib/audit-chain/chain.ts +28 -0
  112. package/src/lib/audit-chain/types.ts +12 -0
  113. package/src/lib/observability/errors.ts +55 -0
  114. package/src/markdown.ts +164 -0
  115. package/src/mcp/handlers.ts +647 -0
  116. package/src/mcp/server.ts +184 -0
  117. package/src/mcp/tools.ts +316 -0
  118. package/src/mcp-client.ts +275 -0
  119. package/src/mcp-server.ts +2 -0
  120. package/src/operator/config.example.ts +60 -0
  121. package/src/operator/config.ts +60 -0
  122. package/src/operator/index.ts +46 -0
  123. package/src/operator/persona.example.ts +34 -0
  124. package/src/operator/persona.ts +34 -0
  125. package/src/operator/prompt-builder.ts +190 -0
  126. package/src/operator/types.ts +43 -0
  127. package/src/pulse.ts +1179 -0
  128. package/src/routes/bluesky.ts +116 -0
  129. package/src/routes/cc-tasks.ts +328 -0
  130. package/src/routes/codebeast.ts +1 -0
  131. package/src/routes/content.ts +194 -0
  132. package/src/routes/conversations.ts +25 -0
  133. package/src/routes/dynamic-tools.ts +111 -0
  134. package/src/routes/feedback.ts +192 -0
  135. package/src/routes/health.ts +147 -0
  136. package/src/routes/messages.ts +228 -0
  137. package/src/routes/observability.ts +82 -0
  138. package/src/routes/operator-logs.ts +42 -0
  139. package/src/routes/pages.ts +96 -0
  140. package/src/routes/sessions.ts +54 -0
  141. package/src/sanitize.ts +73 -0
  142. package/src/schema-enums.ts +155 -0
  143. package/src/search.ts +112 -0
  144. package/src/task-intelligence.ts +497 -0
  145. package/src/types.ts +194 -0
  146. package/src/ui.ts +5 -0
  147. package/src/version.ts +3 -0
  148. package/src/workers-ai-chat.ts +333 -0
package/package.json ADDED
@@ -0,0 +1,96 @@
1
+ {
2
+ "name": "@stackbilt/aegis-core",
3
+ "version": "0.1.0",
4
+ "description": "Persistent AI agent framework for Cloudflare Workers. Multi-tier memory, autonomous goals, dreaming cycles, MCP native.",
5
+ "license": "Apache-2.0",
6
+ "publishConfig": {
7
+ "access": "public"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/Stackbilt-dev/aegis-oss.git",
12
+ "directory": "web"
13
+ },
14
+ "type": "module",
15
+ "main": "src/exports.ts",
16
+ "types": "src/exports.ts",
17
+ "exports": {
18
+ ".": "./src/exports.ts",
19
+ "./core": "./src/core.ts",
20
+ "./types": "./src/types.ts",
21
+ "./edge-env": "./src/edge-env.ts",
22
+ "./auth": "./src/auth.ts",
23
+ "./version": "./src/version.ts",
24
+ "./kernel/dispatch": "./src/kernel/dispatch.ts",
25
+ "./kernel/router": "./src/kernel/router.ts",
26
+ "./kernel/types": "./src/kernel/types.ts",
27
+ "./kernel/memory": "./src/kernel/memory/index.ts",
28
+ "./kernel/memory-adapter": "./src/kernel/memory-adapter.ts",
29
+ "./kernel/resilience": "./src/kernel/resilience.ts",
30
+ "./kernel/classify-memory-topic": "./src/kernel/classify-memory-topic.ts",
31
+ "./kernel/briefing": "./src/kernel/briefing.ts",
32
+ "./kernel/dynamic-tools": "./src/kernel/dynamic-tools.ts",
33
+ "./kernel/argus-correlation": "./src/kernel/argus-correlation.ts",
34
+ "./kernel/port": "./src/kernel/port.ts",
35
+ "./kernel/executor-port": "./src/kernel/executor-port.ts",
36
+ "./kernel/executors": "./src/kernel/executors/index.ts",
37
+ "./kernel/scheduled": "./src/kernel/scheduled/index.ts",
38
+ "./kernel/scheduled/dreaming": "./src/kernel/scheduled/dreaming.ts",
39
+ "./kernel/scheduled/issue-watcher": "./src/kernel/scheduled/issue-watcher.ts",
40
+ "./operator": "./src/operator/index.ts",
41
+ "./operator/types": "./src/operator/types.ts",
42
+ "./operator/prompt-builder": "./src/operator/prompt-builder.ts",
43
+ "./mcp/server": "./src/mcp/server.ts",
44
+ "./mcp/tools": "./src/mcp/tools.ts",
45
+ "./mcp/handlers": "./src/mcp/handlers.ts",
46
+ "./lib/observability": "./src/lib/observability/errors.ts",
47
+ "./lib/audit-chain": "./src/lib/audit-chain/chain.ts",
48
+ "./routes/health": "./src/routes/health.ts",
49
+ "./routes/sessions": "./src/routes/sessions.ts",
50
+ "./routes/messages": "./src/routes/messages.ts",
51
+ "./routes/conversations": "./src/routes/conversations.ts",
52
+ "./routes/feedback": "./src/routes/feedback.ts",
53
+ "./routes/observability": "./src/routes/observability.ts",
54
+ "./routes/cc-tasks": "./src/routes/cc-tasks.ts",
55
+ "./routes/pages": "./src/routes/pages.ts",
56
+ "./routes/dynamic-tools": "./src/routes/dynamic-tools.ts",
57
+ "./adapters/voice": "./src/adapters/voice/cloudflare-agent.ts"
58
+ },
59
+ "scripts": {
60
+ "dev": "wrangler dev",
61
+ "deploy": "wrangler deploy",
62
+ "d1:create": "wrangler d1 create aegis-web",
63
+ "d1:migrate": "wrangler d1 execute aegis-web --file=schema.sql",
64
+ "d1:migrate:local": "wrangler d1 execute aegis-web --file=schema.sql --local",
65
+ "typecheck": "tsc --noEmit",
66
+ "test": "vitest run",
67
+ "test:watch": "vitest"
68
+ },
69
+ "dependencies": {
70
+ "@cloudflare/voice": "^0.1.3",
71
+ "@cloudflare/workers-oauth-provider": "^0.2.4",
72
+ "@stackbilt/llm-providers": "^1.6.0",
73
+ "agents": "^0.12.3",
74
+ "hono": "^4.12.12"
75
+ },
76
+ "devDependencies": {
77
+ "@cloudflare/workers-types": "^4.20241218.0",
78
+ "typescript": "^5.7.3",
79
+ "vite": "^8.0.5",
80
+ "vitest": "^4.0.18",
81
+ "wrangler": "^4.76.0"
82
+ },
83
+ "files": [
84
+ "src/**/*.ts",
85
+ "schema.sql"
86
+ ],
87
+ "keywords": [
88
+ "cloudflare-workers",
89
+ "ai-agent",
90
+ "mcp",
91
+ "autonomous-agent",
92
+ "memory",
93
+ "dreaming-cycle",
94
+ "hono"
95
+ ]
96
+ }
package/schema.sql ADDED
@@ -0,0 +1,586 @@
1
+ -- AEGIS Web — D1 Schema
2
+ -- Run: wrangler d1 execute aegis-web --file=schema.sql
3
+
4
+ -- ─── Chat ──────────────────────────────────────────────────────
5
+
6
+ CREATE TABLE IF NOT EXISTS conversations (
7
+ id TEXT PRIMARY KEY,
8
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
9
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
10
+ title TEXT
11
+ );
12
+
13
+ CREATE TABLE IF NOT EXISTS messages (
14
+ id TEXT PRIMARY KEY,
15
+ conversation_id TEXT NOT NULL,
16
+ role TEXT NOT NULL CHECK (role IN ('user', 'assistant')),
17
+ content TEXT NOT NULL,
18
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
19
+ metadata TEXT,
20
+ FOREIGN KEY (conversation_id) REFERENCES conversations(id)
21
+ );
22
+
23
+
24
+ CREATE TABLE IF NOT EXISTS web_events (
25
+ event_id TEXT PRIMARY KEY,
26
+ received_at TEXT NOT NULL DEFAULT (datetime('now'))
27
+ );
28
+
29
+ -- ─── ARGUS Phase 1: Webhook Event Ingestion ──────────────────
30
+
31
+
32
+ -- ─── Kernel Memory ─────────────────────────────────────────────
33
+
34
+ CREATE TABLE IF NOT EXISTS memory_entries (
35
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
36
+ topic TEXT NOT NULL,
37
+ fact TEXT NOT NULL,
38
+ fact_hash TEXT NOT NULL DEFAULT '',
39
+ confidence REAL NOT NULL DEFAULT 0.8,
40
+ source TEXT NOT NULL,
41
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
42
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
43
+ expires_at TEXT,
44
+ valid_until TEXT, -- NULL = current/active; set to invalidate
45
+ superseded_by INTEGER, -- FK to replacing entry's id
46
+ strength INTEGER NOT NULL DEFAULT 1, -- recall frequency (for decay)
47
+ last_recalled_at TEXT, -- last retrieval time
48
+ -- CRIX Phase 2a: validation pipeline
49
+ validation_stage TEXT DEFAULT 'candidate'
50
+ CHECK (validation_stage IN ('candidate', 'validated', 'expert', 'canonical', 'refuted')),
51
+ validators TEXT -- JSON array: [{ repo, confirmed, date }]
52
+ );
53
+
54
+ CREATE TABLE IF NOT EXISTS episodic_memory (
55
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
56
+ intent_class TEXT NOT NULL,
57
+ channel TEXT NOT NULL,
58
+ summary TEXT NOT NULL,
59
+ outcome TEXT NOT NULL DEFAULT 'success'
60
+ CHECK (outcome IN ('success', 'failure')),
61
+ cost REAL NOT NULL DEFAULT 0,
62
+ latency_ms INTEGER NOT NULL DEFAULT 0,
63
+ near_miss TEXT,
64
+ classifier_confidence REAL,
65
+ reclassified INTEGER NOT NULL DEFAULT 0,
66
+ thread_id TEXT, -- conversation thread for dreaming cycle
67
+ executor TEXT, -- which executor handled this
68
+ complexity_tier TEXT, -- aegis#563: procedureKey complement (low|mid|high); NULL for non-dispatcher producers
69
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
70
+ );
71
+
72
+ -- aegis#564 Phase 2: shadow-read drift log for cached-vs-derived stats on
73
+ -- procedural_memory. Populated by getProcedureWithDerivedStats /
74
+ -- getAllProceduresWithDerivedStats. Phase 3 gate: drift row p95 within
75
+ -- tolerance across a 7-day window before dropping the cached aggregate
76
+ -- columns from procedural_memory.
77
+ CREATE TABLE IF NOT EXISTS shadow_read_drift (
78
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
79
+ reader TEXT NOT NULL,
80
+ task_pattern TEXT NOT NULL,
81
+ cached_count INTEGER NOT NULL,
82
+ cached_success_count INTEGER NOT NULL,
83
+ cached_fail_count INTEGER NOT NULL,
84
+ cached_avg_latency_ms REAL NOT NULL,
85
+ cached_avg_cost REAL NOT NULL,
86
+ cached_last_used TEXT,
87
+ derived_count INTEGER NOT NULL,
88
+ derived_success_count INTEGER NOT NULL,
89
+ derived_fail_count INTEGER NOT NULL,
90
+ derived_avg_latency_ms REAL NOT NULL,
91
+ derived_avg_cost REAL NOT NULL,
92
+ derived_last_used TEXT,
93
+ pre_tier_count INTEGER NOT NULL DEFAULT 0,
94
+ sampled_at TEXT NOT NULL DEFAULT (datetime('now'))
95
+ );
96
+ CREATE INDEX IF NOT EXISTS idx_shadow_read_drift_reader_sampled
97
+ ON shadow_read_drift(reader, sampled_at);
98
+
99
+ CREATE TABLE IF NOT EXISTS procedural_memory (
100
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
101
+ task_pattern TEXT NOT NULL UNIQUE,
102
+ executor TEXT NOT NULL,
103
+ executor_config TEXT NOT NULL DEFAULT '{}',
104
+ success_count INTEGER NOT NULL DEFAULT 0,
105
+ fail_count INTEGER NOT NULL DEFAULT 0,
106
+ avg_latency_ms REAL NOT NULL DEFAULT 0,
107
+ avg_cost REAL NOT NULL DEFAULT 0,
108
+ status TEXT NOT NULL DEFAULT 'learning',
109
+ consecutive_failures INTEGER NOT NULL DEFAULT 0,
110
+ refinements TEXT NOT NULL DEFAULT '[]',
111
+ last_used TEXT,
112
+ candidate_executor TEXT, -- probation: untrusted executor being tested
113
+ candidate_successes INTEGER NOT NULL DEFAULT 0, -- consecutive successes of candidate
114
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
115
+ );
116
+
117
+ CREATE TABLE IF NOT EXISTS heartbeat_results (
118
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
119
+ actionable BOOLEAN NOT NULL,
120
+ severity TEXT NOT NULL,
121
+ summary TEXT NOT NULL,
122
+ checks_json TEXT NOT NULL,
123
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
124
+ );
125
+
126
+ CREATE TABLE IF NOT EXISTS agent_agenda (
127
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
128
+ item TEXT NOT NULL,
129
+ context TEXT,
130
+ priority TEXT NOT NULL DEFAULT 'medium' CHECK (priority IN ('low', 'medium', 'high')),
131
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'done', 'dismissed')),
132
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
133
+ resolved_at TEXT,
134
+ business_unit TEXT NOT NULL DEFAULT 'stackbilt' -- partition key for multi-BU operators
135
+ );
136
+
137
+ -- ─── Autonomous Goals (#14) ────────────────────────────────────
138
+
139
+ CREATE TABLE IF NOT EXISTS agent_goals (
140
+ id TEXT PRIMARY KEY,
141
+ title TEXT NOT NULL,
142
+ description TEXT,
143
+ status TEXT NOT NULL DEFAULT 'active' CHECK (status IN ('active', 'paused', 'completed', 'failed')),
144
+ authority_level TEXT NOT NULL DEFAULT 'propose' CHECK (authority_level IN ('propose', 'auto_low', 'auto_high')),
145
+ schedule_hours INTEGER NOT NULL DEFAULT 6,
146
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
147
+ last_run_at TEXT,
148
+ next_run_at TEXT,
149
+ completed_at TEXT,
150
+ run_count INTEGER NOT NULL DEFAULT 0,
151
+ context_json TEXT,
152
+ business_unit TEXT NOT NULL DEFAULT 'stackbilt' -- partition key for multi-BU operators
153
+ );
154
+
155
+ CREATE TABLE IF NOT EXISTS agent_actions (
156
+ id TEXT PRIMARY KEY,
157
+ goal_id TEXT,
158
+ action_type TEXT NOT NULL CHECK (action_type IN ('proposed', 'executed', 'skipped')),
159
+ description TEXT NOT NULL,
160
+ tool_called TEXT,
161
+ tool_args_json TEXT,
162
+ tool_result_json TEXT,
163
+ outcome TEXT CHECK (outcome IN ('success', 'failure', 'pending')),
164
+ auto_executed INTEGER NOT NULL DEFAULT 0,
165
+ authority_level TEXT NOT NULL DEFAULT 'propose',
166
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
167
+ );
168
+
169
+ -- ─── Reflections (#introspection) ─────────────────────────────
170
+
171
+ CREATE TABLE IF NOT EXISTS reflections (
172
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
173
+ content TEXT NOT NULL,
174
+ memory_count INTEGER NOT NULL DEFAULT 0,
175
+ topics_covered TEXT, -- JSON array of topic strings
176
+ cost REAL NOT NULL DEFAULT 0,
177
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
178
+ );
179
+
180
+ -- ─── Operator Log (#introspection) ────────────────────────────
181
+
182
+ CREATE TABLE IF NOT EXISTS operator_log (
183
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
184
+ content TEXT NOT NULL,
185
+ episodes_count INTEGER NOT NULL DEFAULT 0,
186
+ goals_run INTEGER NOT NULL DEFAULT 0,
187
+ tasks_completed INTEGER NOT NULL DEFAULT 0,
188
+ tasks_failed INTEGER NOT NULL DEFAULT 0,
189
+ prs_created INTEGER NOT NULL DEFAULT 0,
190
+ total_cost REAL NOT NULL DEFAULT 0,
191
+ cost REAL NOT NULL DEFAULT 0, -- cost of generating this log entry
192
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
193
+ );
194
+
195
+ -- ─── Indexes ───────────────────────────────────────────────────
196
+
197
+ CREATE INDEX IF NOT EXISTS idx_messages_conversation ON messages(conversation_id);
198
+ CREATE INDEX IF NOT EXISTS idx_messages_created ON messages(created_at);
199
+ CREATE INDEX IF NOT EXISTS idx_memory_topic ON memory_entries(topic);
200
+ CREATE INDEX IF NOT EXISTS idx_memory_dedup ON memory_entries(topic, fact_hash);
201
+ CREATE INDEX IF NOT EXISTS idx_memory_expires ON memory_entries(expires_at);
202
+ CREATE INDEX IF NOT EXISTS idx_memory_valid ON memory_entries(valid_until);
203
+ CREATE INDEX IF NOT EXISTS idx_memory_validation_stage ON memory_entries(validation_stage);
204
+ CREATE INDEX IF NOT EXISTS idx_episodic_class ON episodic_memory(intent_class);
205
+ CREATE INDEX IF NOT EXISTS idx_episodic_created ON episodic_memory(created_at);
206
+ CREATE INDEX IF NOT EXISTS idx_episodic_thread ON episodic_memory(thread_id);
207
+ CREATE INDEX IF NOT EXISTS idx_procedural_pattern ON procedural_memory(task_pattern);
208
+ CREATE INDEX IF NOT EXISTS idx_procedural_status ON procedural_memory(status);
209
+ CREATE INDEX IF NOT EXISTS idx_heartbeat_created ON heartbeat_results(created_at);
210
+ CREATE INDEX IF NOT EXISTS idx_agenda_status ON agent_agenda(status);
211
+ CREATE INDEX IF NOT EXISTS idx_agenda_priority ON agent_agenda(priority);
212
+ CREATE INDEX IF NOT EXISTS idx_agenda_bu ON agent_agenda(business_unit, status);
213
+ CREATE INDEX IF NOT EXISTS idx_goals_status ON agent_goals(status);
214
+ CREATE INDEX IF NOT EXISTS idx_goals_next_run ON agent_goals(next_run_at);
215
+ CREATE INDEX IF NOT EXISTS idx_goals_bu ON agent_goals(business_unit, status);
216
+ CREATE INDEX IF NOT EXISTS idx_actions_goal ON agent_actions(goal_id);
217
+ CREATE INDEX IF NOT EXISTS idx_actions_created ON agent_actions(created_at);
218
+
219
+ -- ─── Task Observability ─────────────────────────────────────
220
+
221
+ CREATE TABLE IF NOT EXISTS task_runs (
222
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
223
+ task_name TEXT NOT NULL,
224
+ status TEXT NOT NULL CHECK (status IN ('ok', 'error', 'skipped')),
225
+ duration_ms INTEGER,
226
+ error_message TEXT,
227
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
228
+ );
229
+
230
+ CREATE INDEX IF NOT EXISTS idx_task_runs_name ON task_runs(task_name, created_at);
231
+ CREATE INDEX IF NOT EXISTS idx_task_runs_status ON task_runs(status, created_at);
232
+
233
+ -- ─── Shadow Mode: Dual-Write Tracking ───────────────────────
234
+
235
+ CREATE TABLE IF NOT EXISTS shadow_writes (
236
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
237
+ topic TEXT NOT NULL,
238
+ fact_hash TEXT NOT NULL,
239
+ worker_ok INTEGER NOT NULL DEFAULT 0,
240
+ d1_ok INTEGER NOT NULL DEFAULT 0,
241
+ worker_ms INTEGER,
242
+ d1_ms INTEGER,
243
+ error_source TEXT,
244
+ error_message TEXT,
245
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
246
+ );
247
+
248
+ CREATE INDEX IF NOT EXISTS idx_shadow_writes_created ON shadow_writes(created_at);
249
+ CREATE INDEX IF NOT EXISTS idx_shadow_writes_errors ON shadow_writes(error_source, created_at);
250
+
251
+ -- ─── Claude Code Session Ingestion ──────────────────────────
252
+
253
+ CREATE TABLE IF NOT EXISTS cc_sessions (
254
+ id TEXT PRIMARY KEY,
255
+ session_date TEXT NOT NULL,
256
+ summary TEXT NOT NULL,
257
+ commits TEXT,
258
+ files_changed TEXT,
259
+ issues_opened TEXT,
260
+ issues_closed TEXT,
261
+ decisions TEXT,
262
+ repos TEXT,
263
+ duration_minutes INTEGER,
264
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
265
+ );
266
+
267
+ CREATE INDEX IF NOT EXISTS idx_cc_sessions_date ON cc_sessions(session_date);
268
+
269
+ -- ─── Shadow Mode: Dual-Read Comparison ──────────────────────
270
+
271
+ CREATE TABLE IF NOT EXISTS shadow_reads (
272
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
273
+ call_site TEXT NOT NULL,
274
+ query_text TEXT,
275
+ worker_count INTEGER NOT NULL DEFAULT 0,
276
+ d1_count INTEGER NOT NULL DEFAULT 0,
277
+ overlap_count INTEGER NOT NULL DEFAULT 0,
278
+ worker_only_count INTEGER NOT NULL DEFAULT 0,
279
+ d1_only_count INTEGER NOT NULL DEFAULT 0,
280
+ rank_drift REAL,
281
+ worker_ms INTEGER,
282
+ d1_ms INTEGER,
283
+ error_source TEXT,
284
+ error_message TEXT,
285
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
286
+ );
287
+
288
+ CREATE INDEX IF NOT EXISTS idx_shadow_reads_created ON shadow_reads(created_at);
289
+ CREATE INDEX IF NOT EXISTS idx_shadow_reads_site ON shadow_reads(call_site, created_at);
290
+
291
+ -- ─── Claude Code Task Queue ──────────────────────────────────
292
+
293
+ CREATE TABLE IF NOT EXISTS cc_tasks (
294
+ id TEXT PRIMARY KEY,
295
+ title TEXT NOT NULL,
296
+ repo TEXT NOT NULL, -- target repo path (e.g. my-project, demo-app-v2)
297
+ prompt TEXT NOT NULL, -- mission brief for Claude Code
298
+ completion_signal TEXT, -- string to look for in output to confirm success
299
+ status TEXT NOT NULL DEFAULT 'pending'
300
+ CHECK (status IN ('pending', 'running', 'completed', 'failed', 'cancelled')),
301
+ priority INTEGER NOT NULL DEFAULT 50, -- 0=highest, 100=lowest
302
+ depends_on TEXT, -- task ID this depends on (NULL = no dependency) — single blocker, legacy
303
+ blocked_by TEXT, -- JSON array of task IDs that must complete first (DAG dependencies)
304
+ max_turns INTEGER NOT NULL DEFAULT 25, -- --max-turns for safety
305
+ allowed_tools TEXT, -- JSON array of allowed tool patterns (NULL = default set)
306
+ session_id TEXT, -- Claude Code session ID once started
307
+ result TEXT, -- output/result summary
308
+ error TEXT, -- error message if failed
309
+ exit_code INTEGER, -- process exit code
310
+ preflight_json TEXT, -- structured runner-side viability/preflight data
311
+ failure_kind TEXT, -- normalized failure classifier for self-improvement
312
+ retryable INTEGER NOT NULL DEFAULT 0, -- whether the failure is likely transient/retryable
313
+ autopsy_json TEXT, -- structured failure autopsy + recommended action
314
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
315
+ started_at TEXT,
316
+ completed_at TEXT,
317
+ created_by TEXT NOT NULL DEFAULT 'operator', -- who created: operator, aegis, goal:{id}
318
+ authority TEXT NOT NULL DEFAULT 'operator' -- operator=run immediately, auto_safe=safe category, proposed=needs approval
319
+ CHECK (authority IN ('proposed', 'auto_safe', 'operator')),
320
+ category TEXT NOT NULL DEFAULT 'feature' -- task type for governance routing
321
+ CHECK (category IN ('docs', 'tests', 'research', 'bugfix', 'feature', 'refactor', 'deploy')),
322
+ branch TEXT, -- git branch name (auto/{task_id:8})
323
+ pr_url TEXT, -- GitHub PR URL if one was created
324
+ utility_json TEXT, -- PR utility scoring: {impact, novelty, signals[]}
325
+ github_issue_repo TEXT, -- source issue repo (e.g. 'my-org/aegis')
326
+ github_issue_number INTEGER, -- source issue number (repo-scoped)
327
+ business_unit TEXT NOT NULL DEFAULT 'stackbilt' -- partition key for multi-BU operators
328
+ );
329
+
330
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_status ON cc_tasks(status, priority);
331
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_depends ON cc_tasks(depends_on);
332
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_created ON cc_tasks(created_at);
333
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_bu ON cc_tasks(business_unit, status);
334
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_authority ON cc_tasks(authority);
335
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_gh_issue ON cc_tasks(github_issue_repo, github_issue_number);
336
+ CREATE INDEX IF NOT EXISTS idx_cc_tasks_failure_kind ON cc_tasks(failure_kind, completed_at);
337
+
338
+ -- ─── Cognitive Layer ──────────────────────────────────────────
339
+
340
+ -- Phase 1: Narratives — maintained story arcs across sessions
341
+ CREATE TABLE IF NOT EXISTS narratives (
342
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
343
+ arc TEXT NOT NULL, -- short label: "llc_formation", "oauth_migration"
344
+ arc_hash TEXT NOT NULL DEFAULT '', -- djb2 hash for dedup
345
+ title TEXT NOT NULL, -- human-readable: "LLC formation stuck on bureaucracy"
346
+ summary TEXT NOT NULL, -- 2-4 sentence current state
347
+ status TEXT NOT NULL DEFAULT 'active'
348
+ CHECK (status IN ('active', 'resolved', 'stalled', 'abandoned')),
349
+ tension TEXT, -- what's unresolved
350
+ last_beat TEXT, -- most recent development (1 sentence)
351
+ beat_count INTEGER NOT NULL DEFAULT 1,
352
+ related_topics TEXT NOT NULL DEFAULT '[]', -- JSON array of memory topic strings
353
+ related_goal_ids TEXT NOT NULL DEFAULT '[]',
354
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
355
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
356
+ resolved_at TEXT
357
+ );
358
+
359
+ -- Phase 2: Knowledge Graph — nodes + edges with spreading activation
360
+ CREATE TABLE IF NOT EXISTS kg_nodes (
361
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
362
+ label TEXT NOT NULL,
363
+ node_type TEXT NOT NULL
364
+ CHECK (node_type IN ('concept','project','person','decision','pattern','tool','event',
365
+ 'file','module','function','class','interface','type_alias')),
366
+ description TEXT,
367
+ activation REAL NOT NULL DEFAULT 0.0,
368
+ last_activated_at TEXT,
369
+ memory_ids TEXT NOT NULL DEFAULT '[]', -- JSON array of memory_entries.id links
370
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
371
+ source_system TEXT NOT NULL DEFAULT 'cognitive'
372
+ CHECK (source_system IN ('cognitive', 'code', 'manual')),
373
+ source_ref TEXT, -- e.g. "my-project:src/kernel/dispatch.ts:45"
374
+ updated_at TEXT NOT NULL DEFAULT (datetime('now'))
375
+ );
376
+
377
+ CREATE TABLE IF NOT EXISTS kg_edges (
378
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
379
+ source_id INTEGER NOT NULL REFERENCES kg_nodes(id),
380
+ target_id INTEGER NOT NULL REFERENCES kg_nodes(id),
381
+ relation TEXT NOT NULL -- depends_on, part_of, decided_by, blocks, uses, related_to, caused
382
+ CHECK (relation IN ('depends_on', 'part_of', 'decided_by', 'blocks', 'uses', 'related_to', 'caused')),
383
+ weight REAL NOT NULL DEFAULT 0.5,
384
+ confidence REAL NOT NULL DEFAULT 0.7,
385
+ evidence TEXT,
386
+ co_activation_count INTEGER NOT NULL DEFAULT 1,
387
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
388
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
389
+ first_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
390
+ last_seen_at TEXT NOT NULL DEFAULT (datetime('now')),
391
+ source_system TEXT NOT NULL DEFAULT 'cognitive'
392
+ CHECK (source_system IN ('cognitive', 'code', 'manual'))
393
+ );
394
+
395
+
396
+ -- Phase 1: CognitiveState — precomputed warm-boot blob (singleton)
397
+ CREATE TABLE IF NOT EXISTS cognitive_state (
398
+ id INTEGER PRIMARY KEY CHECK (id = 1),
399
+ state_json TEXT NOT NULL DEFAULT '{}',
400
+ version INTEGER NOT NULL DEFAULT 0,
401
+ computed_at TEXT NOT NULL DEFAULT (datetime('now')),
402
+ compute_cost REAL NOT NULL DEFAULT 0,
403
+ compute_ms INTEGER NOT NULL DEFAULT 0
404
+ );
405
+
406
+ -- ─── Cognitive Layer Indexes ──────────────────────────────────
407
+ CREATE INDEX IF NOT EXISTS idx_narratives_status ON narratives(status);
408
+ CREATE INDEX IF NOT EXISTS idx_narratives_arc ON narratives(arc);
409
+ CREATE INDEX IF NOT EXISTS idx_narratives_updated ON narratives(updated_at);
410
+ CREATE INDEX IF NOT EXISTS idx_kg_nodes_type ON kg_nodes(node_type);
411
+ CREATE INDEX IF NOT EXISTS idx_kg_nodes_label ON kg_nodes(label);
412
+ CREATE INDEX IF NOT EXISTS idx_kg_nodes_activation ON kg_nodes(activation);
413
+ CREATE INDEX IF NOT EXISTS idx_kg_nodes_source ON kg_nodes(source_system);
414
+ CREATE INDEX IF NOT EXISTS idx_kg_nodes_source_ref ON kg_nodes(source_ref);
415
+ CREATE INDEX IF NOT EXISTS idx_kg_edges_source ON kg_edges(source_id);
416
+ CREATE INDEX IF NOT EXISTS idx_kg_edges_target ON kg_edges(target_id);
417
+ CREATE INDEX IF NOT EXISTS idx_kg_edges_relation ON kg_edges(relation);
418
+ CREATE INDEX IF NOT EXISTS idx_kg_edges_source_system ON kg_edges(source_system);
419
+
420
+ -- ─── Tech Posts (consolidated to roundtable-db, kept for reference) ──
421
+ -- Posts are now in ROUNDTABLE_DB `posts` table. This table is legacy.
422
+
423
+ -- ─── Exocortex v2: Memory Blocks ─────────────────────────────
424
+
425
+ CREATE TABLE IF NOT EXISTS memory_blocks (
426
+ id TEXT PRIMARY KEY,
427
+ content TEXT NOT NULL,
428
+ version INTEGER NOT NULL DEFAULT 1,
429
+ priority INTEGER NOT NULL,
430
+ max_bytes INTEGER NOT NULL,
431
+ updated_by TEXT NOT NULL DEFAULT 'operator',
432
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
433
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
434
+ );
435
+
436
+ -- ─── Platform Feedback ──────────────────────────────────────
437
+
438
+ CREATE TABLE IF NOT EXISTS feedback (
439
+ id TEXT PRIMARY KEY,
440
+ email TEXT,
441
+ category TEXT NOT NULL DEFAULT 'general'
442
+ CHECK (category IN ('general', 'bug', 'feature', 'question')),
443
+ message TEXT NOT NULL,
444
+ source TEXT NOT NULL DEFAULT 'web' -- web, mcp, api
445
+ CHECK (source IN ('web', 'mcp', 'api')),
446
+ user_agent TEXT,
447
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
448
+ );
449
+
450
+ CREATE INDEX IF NOT EXISTS idx_feedback_created ON feedback(created_at);
451
+ CREATE INDEX IF NOT EXISTS idx_feedback_category ON feedback(category);
452
+
453
+ -- ─── Feed Watcher ───────────────────────────────────────────
454
+ CREATE TABLE IF NOT EXISTS watched_feeds (
455
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
456
+ url TEXT NOT NULL UNIQUE,
457
+ title TEXT,
458
+ category TEXT NOT NULL DEFAULT 'general',
459
+ last_fetched_at TEXT,
460
+ last_entry_id TEXT,
461
+ enabled INTEGER NOT NULL DEFAULT 1,
462
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
463
+ );
464
+
465
+ CREATE TABLE IF NOT EXISTS feed_entries (
466
+ id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(8)))),
467
+ feed_id TEXT NOT NULL REFERENCES watched_feeds(id),
468
+ entry_id TEXT NOT NULL,
469
+ title TEXT NOT NULL,
470
+ link TEXT,
471
+ summary TEXT,
472
+ published_at TEXT,
473
+ ingested_at TEXT NOT NULL DEFAULT (datetime('now')),
474
+ recorded_to_memory INTEGER NOT NULL DEFAULT 0,
475
+ UNIQUE(feed_id, entry_id)
476
+ );
477
+
478
+ CREATE INDEX IF NOT EXISTS idx_feed_entries_feed ON feed_entries(feed_id);
479
+ CREATE INDEX IF NOT EXISTS idx_feed_entries_ingested ON feed_entries(ingested_at);
480
+
481
+ -- ─── Project Board ──────────────────────────────────────────────
482
+ -- D1 cache of GitHub Projects v2 board state.
483
+ -- Written by ARGUS webhooks (real-time) and board-sync (hourly reconciliation).
484
+ -- Read by Overworld snapshot endpoint.
485
+
486
+ CREATE TABLE IF NOT EXISTS board_items (
487
+ id TEXT PRIMARY KEY, -- GitHub Projects item node ID
488
+ project_id TEXT NOT NULL, -- GitHub Projects project node ID
489
+ content_type TEXT NOT NULL CHECK (content_type IN ('issue', 'pr')),
490
+ content_node_id TEXT NOT NULL, -- GitHub node ID of the issue/PR
491
+ repo TEXT NOT NULL, -- 'my-org/aegis' format
492
+ number INTEGER NOT NULL,
493
+ title TEXT NOT NULL,
494
+ status TEXT NOT NULL DEFAULT 'backlog'
495
+ CHECK (status IN ('backlog', 'queued', 'in_progress', 'blocked', 'shipped')),
496
+ labels TEXT NOT NULL DEFAULT '[]', -- JSON array
497
+ assignee TEXT,
498
+ cc_task_id TEXT, -- FK to cc_tasks.id if linked
499
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
500
+ synced_at TEXT NOT NULL DEFAULT (datetime('now'))
501
+ );
502
+
503
+ CREATE INDEX IF NOT EXISTS idx_board_status ON board_items(status);
504
+ CREATE INDEX IF NOT EXISTS idx_board_repo ON board_items(repo);
505
+ CREATE INDEX IF NOT EXISTS idx_board_content ON board_items(content_node_id);
506
+ CREATE UNIQUE INDEX IF NOT EXISTS idx_board_repo_number ON board_items(repo, number);
507
+
508
+ -- ─── Content Queue (Content Drip) ─────────────────────────────
509
+
510
+ CREATE TABLE IF NOT EXISTS content_queue (
511
+ id TEXT PRIMARY KEY,
512
+ platform TEXT NOT NULL DEFAULT 'bluesky',
513
+ text TEXT NOT NULL,
514
+ image_url TEXT,
515
+ image_alt TEXT,
516
+ link_url TEXT,
517
+ scheduled_at TEXT NOT NULL,
518
+ published_at TEXT,
519
+ status TEXT NOT NULL DEFAULT 'scheduled'
520
+ CHECK (status IN ('scheduled', 'published', 'failed', 'cancelled')),
521
+ post_url TEXT,
522
+ error TEXT,
523
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
524
+ );
525
+
526
+ CREATE INDEX IF NOT EXISTS idx_content_queue_status ON content_queue(status, scheduled_at);
527
+
528
+ -- ─── Dynamic Tools ────────────────────────────────────────────
529
+
530
+ CREATE TABLE IF NOT EXISTS dynamic_tools (
531
+ id TEXT PRIMARY KEY,
532
+ name TEXT NOT NULL UNIQUE,
533
+ description TEXT NOT NULL,
534
+ input_schema TEXT NOT NULL DEFAULT '{}',
535
+ prompt_template TEXT NOT NULL,
536
+ executor TEXT NOT NULL DEFAULT 'gpt_oss'
537
+ CHECK (executor IN ('gpt_oss', 'workers_ai', 'groq')),
538
+ created_by TEXT NOT NULL DEFAULT 'operator',
539
+ status TEXT NOT NULL DEFAULT 'active'
540
+ CHECK (status IN ('active', 'promoted', 'retired', 'draft')),
541
+ ttl_days INTEGER,
542
+ use_count INTEGER NOT NULL DEFAULT 0,
543
+ last_used_at TEXT,
544
+ avg_latency_ms REAL NOT NULL DEFAULT 0,
545
+ avg_cost REAL NOT NULL DEFAULT 0,
546
+ created_at TEXT NOT NULL DEFAULT (datetime('now')),
547
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
548
+ expires_at TEXT
549
+ );
550
+
551
+ CREATE INDEX IF NOT EXISTS idx_dynamic_tools_status ON dynamic_tools(status);
552
+ CREATE INDEX IF NOT EXISTS idx_dynamic_tools_expires ON dynamic_tools(expires_at);
553
+
554
+ -- ─── CodeBeast Findings ──────────────────────────────────────
555
+
556
+ CREATE TABLE IF NOT EXISTS codebeast_findings (
557
+ finding_id TEXT PRIMARY KEY,
558
+ repo TEXT NOT NULL,
559
+ file_path TEXT NOT NULL DEFAULT '',
560
+ line_start INTEGER NOT NULL DEFAULT 0,
561
+ line_end INTEGER NOT NULL DEFAULT 0,
562
+ severity TEXT NOT NULL
563
+ CHECK (severity IN ('HIGH', 'MID', 'LOW', 'INFO')),
564
+ category TEXT NOT NULL DEFAULT 'LOGIC'
565
+ CHECK (category IN ('SECURITY', 'LOGIC', 'STYLE', 'DEPENDENCY', 'BOUNDARY')),
566
+ title TEXT NOT NULL,
567
+ description TEXT NOT NULL DEFAULT '',
568
+ commit_sha TEXT NOT NULL DEFAULT '',
569
+ branch TEXT NOT NULL DEFAULT 'main',
570
+ priority TEXT NOT NULL DEFAULT 'low'
571
+ CHECK (priority IN ('high', 'medium', 'low')),
572
+ status TEXT NOT NULL DEFAULT 'open'
573
+ CHECK (status IN ('open', 'resolved')),
574
+ fix_id TEXT,
575
+ outcome_summary TEXT,
576
+ fix_attempts INTEGER NOT NULL DEFAULT 0,
577
+ last_fix_error TEXT,
578
+ detected_at TEXT NOT NULL DEFAULT (datetime('now')),
579
+ resolved_at TEXT,
580
+ updated_at TEXT NOT NULL DEFAULT (datetime('now')),
581
+ created_at TEXT NOT NULL DEFAULT (datetime('now'))
582
+ );
583
+
584
+ CREATE INDEX IF NOT EXISTS idx_cb_findings_status ON codebeast_findings(status);
585
+ CREATE INDEX IF NOT EXISTS idx_cb_findings_repo ON codebeast_findings(repo);
586
+ CREATE INDEX IF NOT EXISTS idx_cb_findings_severity ON codebeast_findings(severity);