agent-enderun 0.6.5 → 0.6.6

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 (56) hide show
  1. package/.enderun/BRAIN_DASHBOARD.md +12 -12
  2. package/.enderun/PROJECT_MEMORY.md +15 -123
  3. package/.enderun/STATUS.md +13 -13
  4. package/.enderun/agents/README.md +40 -0
  5. package/.enderun/agents/analyst.md +178 -58
  6. package/.enderun/agents/backend.md +224 -58
  7. package/.enderun/agents/explorer.md +123 -50
  8. package/.enderun/agents/frontend.md +216 -26
  9. package/.enderun/agents/git.md +146 -72
  10. package/.enderun/agents/manager.md +23 -3
  11. package/.enderun/agents/mobile.md +136 -66
  12. package/.enderun/agents/native.md +176 -63
  13. package/.enderun/blueprints/README.md +82 -0
  14. package/.enderun/docs/README.md +50 -0
  15. package/.enderun/docs/phase1-reference-app-execution-plan.md +177 -0
  16. package/.enderun/docs/structure-audit-2026-05-24.md +72 -0
  17. package/.enderun/knowledge/README.md +22 -0
  18. package/.enderun/knowledge/database_governance_guidelines.md +118 -0
  19. package/.enderun/knowledge/deployment_checklist.md +132 -6
  20. package/.enderun/knowledge/documentation_ownership.md +122 -0
  21. package/.enderun/knowledge/documentation_ownership_status.md +122 -0
  22. package/.enderun/knowledge/enterprise_capabilities_reference.md +149 -0
  23. package/.enderun/knowledge/enterprise_frontend_adaptation.md +232 -0
  24. package/.enderun/knowledge/enterprise_project_adaptation.md +168 -0
  25. package/.enderun/knowledge/frontend_professionalization_guidelines.md +20 -17
  26. package/.enderun/knowledge/frontend_real_battle_test_protocol.md +162 -0
  27. package/.enderun/knowledge/hermes_live_test_guidelines.md +5 -5
  28. package/.enderun/knowledge/manager_authority_audit_enforcement.md +8 -8
  29. package/.enderun/knowledge/project_scaffold_guidelines.md +4 -4
  30. package/.enderun/knowledge/reference_application_guidelines.md +6 -6
  31. package/ENDERUN.md +13 -6
  32. package/README.md +98 -183
  33. package/bin/hermes-sandbox.js +136 -0
  34. package/docs/action-plan-2026.md +119 -0
  35. package/docs/getting-started.md +12 -238
  36. package/docs/roadmap.md +15 -73
  37. package/framework-mcp/README.md +1 -1
  38. package/framework-mcp/dist/schemas.js +6 -0
  39. package/framework-mcp/dist/tools/database.js +7 -2
  40. package/framework-mcp/dist/tools/framework.js +4 -4
  41. package/framework-mcp/dist/tools/knowledge.js +1 -1
  42. package/framework-mcp/dist/tools/memory.js +2 -2
  43. package/framework-mcp/dist/tools/messages.js +71 -11
  44. package/framework-mcp/dist/utils.js +1 -1
  45. package/framework-mcp/package.json +1 -1
  46. package/framework-mcp/src/tools/database.ts +7 -2
  47. package/framework-mcp/src/tools/framework.ts +4 -4
  48. package/framework-mcp/src/tools/knowledge.ts +1 -1
  49. package/framework-mcp/src/tools/memory.ts +2 -2
  50. package/framework-mcp/src/tools/messages.ts +4 -4
  51. package/framework-mcp/src/utils.ts +18 -1
  52. package/framework-mcp/tsconfig.json +1 -1
  53. package/package.json +3 -3
  54. package/.enderun/messages/2026-05-23-backend-to-manager-auth-errors-reply.json +0 -23
  55. package/.enderun/messages/2026-05-23-manager-to-backend-auth-errors.json +0 -26
  56. /package/.enderun/blueprints/backend/errors/{blueprint.json → config/meta.json} +0 -0
@@ -1,7 +1,7 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
3
  import { getFrameworkDir } from "../utils.js";
4
- import { SEND_AGENT_MESSAGE_ARGS_SCHEMA, READ_AGENT_MESSAGES_ARGS_SCHEMA, GET_AGENT_INBOX_STATS_ARGS_SCHEMA } from "../schemas.js";
4
+ import { SEND_AGENT_MESSAGE_ARGS_SCHEMA, READ_AGENT_MESSAGES_ARGS_SCHEMA, GET_AGENT_INBOX_STATS_ARGS_SCHEMA, UPDATE_AGENT_MESSAGE_STATUS_ARGS_SCHEMA } from "../schemas.js";
5
5
  export const messageTools = [
6
6
  {
7
7
  name: "send_agent_message",
@@ -9,13 +9,14 @@ export const messageTools = [
9
9
  inputSchema: {
10
10
  type: "object",
11
11
  properties: {
12
+ from: { type: "string", description: "Sender agent name (e.g. @manager, @backend)" },
12
13
  to: { type: "string", description: "Recipient agent name" },
13
14
  message: { type: "string", description: "The message content" },
14
15
  traceId: { type: "string", description: "The active Trace ID" },
15
16
  category: { type: "string", enum: ["ACTION", "DELEGATION", "INFO", "ALERT"], default: "INFO" },
16
17
  priority: { type: "string", enum: ["LOW", "MEDIUM", "HIGH", "URGENT"], default: "MEDIUM" },
17
18
  },
18
- required: ["to", "message", "traceId"],
19
+ required: ["from", "to", "message", "traceId"],
19
20
  },
20
21
  },
21
22
  {
@@ -41,6 +42,19 @@ export const messageTools = [
41
42
  required: ["agent"],
42
43
  },
43
44
  },
45
+ {
46
+ name: "update_agent_message_status",
47
+ description: "Allows an agent to acknowledge, complete, or reject a Hermes message by Trace ID (advances the orchestration lifecycle).",
48
+ inputSchema: {
49
+ type: "object",
50
+ properties: {
51
+ agent: { type: "string", description: "The agent performing the status update" },
52
+ traceId: { type: "string", description: "Trace ID of the message to update" },
53
+ newStatus: { type: "string", enum: ["ACKNOWLEDGED", "COMPLETED", "REJECTED"], description: "New lifecycle status" },
54
+ },
55
+ required: ["agent", "traceId", "newStatus"],
56
+ },
57
+ },
44
58
  ];
45
59
  function normalizeAgentName(agent) {
46
60
  const normalized = agent.replace(/^@/, "").trim();
@@ -61,20 +75,22 @@ export const messageHandlers = {
61
75
  fs.mkdirSync(messagesDir, { recursive: true });
62
76
  const messagePath = path.join(messagesDir, `${recipient}.json`);
63
77
  const messages = (fs.existsSync(messagePath) ? JSON.parse(fs.readFileSync(messagePath, "utf-8")) : []);
78
+ const sender = normalizeAgentName(parsed.data.from) || "unknown";
64
79
  messages.push({
65
80
  timestamp: new Date().toISOString(),
66
- from: "manager",
81
+ from: sender,
82
+ to: recipient,
67
83
  traceId: parsed.data.traceId,
68
84
  category: parsed.data.category,
69
85
  priority: parsed.data.priority,
70
86
  content: parsed.data.message,
71
- read: false
87
+ status: "PENDING"
72
88
  });
73
89
  fs.writeFileSync(messagePath, JSON.stringify(messages, null, 2));
74
90
  return { content: [{ type: "text", text: `Hermes: Message sent to @${recipient} [${parsed.data.category} | ${parsed.data.priority}].` }] };
75
91
  }
76
92
  catch {
77
- return { content: [{ type: "text", text: "Failed to get message statistics." }] };
93
+ return { content: [{ type: "text", text: "Failed to send agent message." }] };
78
94
  }
79
95
  },
80
96
  read_agent_messages: async (args, projectRoot) => {
@@ -90,11 +106,20 @@ export const messageHandlers = {
90
106
  if (!fs.existsSync(messagePath))
91
107
  return { content: [{ type: "text", text: "No messages found." }] };
92
108
  const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
93
- const unread = messages.filter((m) => !m.read && (!parsed.data.traceId || m.traceId === parsed.data.traceId));
94
- fs.writeFileSync(messagePath, JSON.stringify(messages.map((m) => (!m.read && (!parsed.data.traceId || m.traceId === parsed.data.traceId) ? { ...m, read: true } : m)), null, 2));
95
- if (unread.length === 0)
109
+ const pending = messages.filter((m) => (m.status === "PENDING" || m.status === "ACKNOWLEDGED") &&
110
+ (!parsed.data.traceId || m.traceId === parsed.data.traceId));
111
+ // Transition PENDING → READ (Do not regress ACKNOWLEDGED messages back to READ)
112
+ const updated = messages.map((m) => {
113
+ if (m.status === "PENDING" &&
114
+ (!parsed.data.traceId || m.traceId === parsed.data.traceId)) {
115
+ return { ...m, status: "READ" };
116
+ }
117
+ return m;
118
+ });
119
+ fs.writeFileSync(messagePath, JSON.stringify(updated, null, 2));
120
+ if (pending.length === 0)
96
121
  return { content: [{ type: "text", text: "No new messages." }] };
97
- const formatted = unread.map((m) => `- [${m.priority}] **${m.from}** (${m.category}): ${m.content} *(Trace: ${m.traceId})*`).join("\n");
122
+ const formatted = pending.map((m) => `- [${m.priority}] **${m.from}** (${m.category}): ${m.content} *(Trace: ${m.traceId})*`).join("\n");
98
123
  return { content: [{ type: "text", text: `### HERMES INBOX: @${agentName}\n\n${formatted}` }] };
99
124
  }
100
125
  catch {
@@ -114,20 +139,55 @@ export const messageHandlers = {
114
139
  if (!fs.existsSync(messagePath))
115
140
  return { content: [{ type: "text", text: "Inbox empty." }] };
116
141
  const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
117
- const unread = messages.filter(m => !m.read);
142
+ const pendingOrRead = messages.filter(m => m.status === "PENDING" || m.status === "READ");
118
143
  const priorityDist = messages.reduce((acc, m) => {
119
144
  acc[m.priority] = (acc[m.priority] || 0) + 1;
120
145
  return acc;
121
146
  }, {});
147
+ const statusDist = messages.reduce((acc, m) => {
148
+ acc[m.status] = (acc[m.status] || 0) + 1;
149
+ return acc;
150
+ }, {});
122
151
  return {
123
152
  content: [{
124
153
  type: "text",
125
- text: `### INBOX STATS: @${agentName}\n- Total: ${messages.length}\n- Unread: ${unread.length}\n- Priority Distribution: ${JSON.stringify(priorityDist)}`
154
+ text: `### INBOX STATS: @${agentName}\n- Total: ${messages.length}\n- Pending/Read: ${pendingOrRead.length}\n- By Priority: ${JSON.stringify(priorityDist)}\n- By Status: ${JSON.stringify(statusDist)}`
126
155
  }]
127
156
  };
128
157
  }
129
158
  catch {
130
159
  return { content: [{ type: "text", text: "Failed to read agent messages." }] };
131
160
  }
161
+ },
162
+ update_agent_message_status: async (args, projectRoot) => {
163
+ const parsed = UPDATE_AGENT_MESSAGE_STATUS_ARGS_SCHEMA.safeParse(args ?? {});
164
+ if (!parsed.success)
165
+ return { content: [{ type: "text", text: "Invalid arguments for status update." }] };
166
+ try {
167
+ const frameworkDir = getFrameworkDir(projectRoot);
168
+ const agentName = normalizeAgentName(parsed.data.agent);
169
+ if (!agentName)
170
+ return { content: [{ type: "text", text: "Invalid agent name." }] };
171
+ const messagePath = path.join(projectRoot, frameworkDir, "messages", `${agentName}.json`);
172
+ if (!fs.existsSync(messagePath))
173
+ return { content: [{ type: "text", text: "No messages for this agent." }] };
174
+ const messages = JSON.parse(fs.readFileSync(messagePath, "utf-8"));
175
+ let updated = false;
176
+ const newMessages = messages.map((m) => {
177
+ if (m.traceId === parsed.data.traceId) {
178
+ updated = true;
179
+ return { ...m, status: parsed.data.newStatus };
180
+ }
181
+ return m;
182
+ });
183
+ if (!updated) {
184
+ return { content: [{ type: "text", text: `No message found with Trace ID ${parsed.data.traceId}.` }] };
185
+ }
186
+ fs.writeFileSync(messagePath, JSON.stringify(newMessages, null, 2));
187
+ return { content: [{ type: "text", text: `Hermes: Message ${parsed.data.traceId} marked as ${parsed.data.newStatus}.` }] };
188
+ }
189
+ catch {
190
+ return { content: [{ type: "text", text: "Failed to update message status." }] };
191
+ }
132
192
  }
133
193
  };
@@ -1,6 +1,6 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
- export const FRAMEWORK_VERSION = "0.6.1";
3
+ export const FRAMEWORK_VERSION = "0.6.5";
4
4
  export function getFrameworkDir(projectRoot) {
5
5
  const adapters = [".antigravitycli", ".claude", ".cursor", ".enderun", ".codex"];
6
6
  for (const adp of adapters) {
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-enderun-mcp",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "Enterprise-grade MCP Server for AI Agent Framework",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -30,11 +30,16 @@ export const databaseHandlers = {
30
30
  for (const sourceFile of tsProject.getSourceFiles()) {
31
31
  const text = sourceFile.getFullText();
32
32
  const tableMatches = Array.from(text.matchAll(/\.createTable\(['"]([^'"]+)['"]\)/g));
33
- for (const match of tableMatches) {
33
+ for (let i = 0; i < tableMatches.length; i++) {
34
+ const match = tableMatches[i] as any;
34
35
  const tableName = match[1]; tablesFound++;
35
36
  mermaid += ` ${tableName} {\n`;
37
+ const startIndex = match.index ?? 0;
38
+ const nextMatch = tableMatches[i + 1];
39
+ const endIndex = nextMatch ? (nextMatch.index ?? text.length) : text.length;
40
+ const tableBlockText = text.substring(startIndex, endIndex);
36
41
  const colRegex = /\.addColumn\(['"]([^'"]+)['"]\s*,\s*['"]([^'"]+)['"]/g;
37
- let colMatch; while ((colMatch = colRegex.exec(text)) !== null) {
42
+ let colMatch; while ((colMatch = colRegex.exec(tableBlockText)) !== null) {
38
43
  mermaid += ` ${colMatch[2].replace(/[^a-zA-Z0-9]/g, '_')} ${colMatch[1]}\n`;
39
44
  }
40
45
  mermaid += ` }\n`;
@@ -78,7 +78,7 @@ export const frameworkHandlers = {
78
78
  fs.writeFileSync(memoryPath, bootstrapContent);
79
79
  return { content: [{ type: "text", text: `Legacy Codebase Bootstrap complete. Detected Stack: ${techStack}.` }] };
80
80
  } catch {
81
- return { content: [{ type: "text", text: "Failed to get project gaps." }] };
81
+ return { content: [{ type: "text", text: "Failed to bootstrap legacy memory." }] };
82
82
  }
83
83
  },
84
84
  get_framework_status: async (args: unknown, projectRoot: string) => {
@@ -93,7 +93,7 @@ export const frameworkHandlers = {
93
93
  content: [{ type: "text", text: `Framework active (v${FRAMEWORK_VERSION}). Phase: ${phase}. Profile: ${profile}.` }],
94
94
  };
95
95
  } catch {
96
- return { content: [{ type: "text", text: "Failed to get memory insights." }] };
96
+ return { content: [{ type: "text", text: "Failed to get framework status." }] };
97
97
  }
98
98
  },
99
99
  get_project_gaps: async (args: unknown, projectRoot: string) => {
@@ -146,7 +146,7 @@ export const frameworkHandlers = {
146
146
  content: [{ type: "text", text: `### LIVE MEMORY INSIGHTS\n\n**Active Tasks:**\n${activeTasks.trim()}\n\n**Recent History:**\n${history.trim().substring(0, 1000)}...\n\n**Brain Snapshot:**\n${dashboardAgents.trim().substring(0, 500)}...` }],
147
147
  };
148
148
  } catch {
149
- return { content: [{ type: "text", text: "Failed to get framework status." }] };
149
+ return { content: [{ type: "text", text: "Failed to get memory insights." }] };
150
150
  }
151
151
  },
152
152
  codebase_context: async (args: unknown, projectRoot: string) => {
@@ -159,7 +159,7 @@ export const frameworkHandlers = {
159
159
  content: [{ type: "text", text: "### CONTEXT ARTIFACTS\n\n" + `PROJECT_MEMORY: ${fs.existsSync(memoryPath) ? "present" : "missing"}\n` + `BRAIN_DASHBOARD: ${fs.existsSync(dashboardPath) ? "present" : "missing"}\n` + `Docs:\n${artifacts.length > 0 ? artifacts.join("\n") : "No markdown artifacts found."}` }],
160
160
  };
161
161
  } catch {
162
- return { content: [{ type: "text", text: "Failed to bootstrap legacy memory." }] };
162
+ return { content: [{ type: "text", text: "Failed to gather codebase context." }] };
163
163
  }
164
164
  },
165
165
  get_system_time: async () => {
@@ -94,7 +94,7 @@ function parseFrontmatter(content: string) {
94
94
  if (!fs.existsSync(kbDir)) fs.mkdirSync(kbDir, { recursive: true });
95
95
 
96
96
  const fileName = parsed.data.topic.replace(/[^a-z0-9]/gi, "_").toLowerCase() + ".md";
97
- const tags = parsed.data.tags;
97
+ const tags = parsed.data.tags || [];
98
98
 
99
99
  let finalContent = parsed.data.content;
100
100
  if (!finalContent.startsWith("---")) {
@@ -73,7 +73,7 @@ export const memoryHandlers = {
73
73
  if (fs.existsSync(lockPath) && fs.readFileSync(lockPath, "utf-8").includes(lockOwner)) fs.unlinkSync(lockPath);
74
74
  return { content: [{ type: "text", text: `Section ${section} updated successfully.` }] };
75
75
  } catch {
76
- return { content: [{ type: "text", text: "Failed to read project memory." }] };
76
+ return { content: [{ type: "text", text: "Failed to update project memory." }] };
77
77
  }
78
78
  },
79
79
  read_project_memory: async (args: unknown, projectRoot: string) => {
@@ -83,7 +83,7 @@ export const memoryHandlers = {
83
83
  if (!fs.existsSync(memoryPath)) return { content: [{ type: "text", text: `ERROR: ${frameworkDir}/PROJECT_MEMORY.md not found.` }] };
84
84
  return { content: [{ type: "text", text: fs.readFileSync(memoryPath, "utf-8") }] };
85
85
  } catch {
86
- return { content: [{ type: "text", text: "Failed to update project memory." }] };
86
+ return { content: [{ type: "text", text: "Failed to read project memory." }] };
87
87
  }
88
88
  },
89
89
  };
@@ -123,9 +123,9 @@ export const messageHandlers = {
123
123
  (!parsed.data.traceId || m.traceId === parsed.data.traceId)
124
124
  );
125
125
 
126
- // Transition PENDING → READ
126
+ // Transition PENDING → READ (Do not regress ACKNOWLEDGED messages back to READ)
127
127
  const updated = messages.map((m) => {
128
- if ((m.status === "PENDING" || m.status === "ACKNOWLEDGED") &&
128
+ if (m.status === "PENDING" &&
129
129
  (!parsed.data.traceId || m.traceId === parsed.data.traceId)) {
130
130
  return { ...m, status: "READ" as const };
131
131
  }
@@ -140,8 +140,8 @@ export const messageHandlers = {
140
140
  ).join("\n");
141
141
 
142
142
  return { content: [{ type: "text", text: `### HERMES INBOX: @${agentName}\n\n${formatted}` }] };
143
- } catch {
144
- return { content: [{ type: "text", text: "Failed to send agent message." }] };
143
+ } catch {
144
+ return { content: [{ type: "text", text: "Failed to read agent messages." }] };
145
145
  }
146
146
  },
147
147
  get_agent_inbox_stats: async (args: unknown, projectRoot: string) => {
@@ -1,7 +1,24 @@
1
1
  import path from "path";
2
2
  import fs from "fs";
3
+ import { fileURLToPath } from "url";
3
4
 
4
- export const FRAMEWORK_VERSION = "0.6.5";
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+
8
+ const getPackageVersion = (): string => {
9
+ try {
10
+ const pkgPath = path.join(__dirname, "../package.json");
11
+ if (fs.existsSync(pkgPath)) {
12
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
13
+ return pkg.version || "0.6.6";
14
+ }
15
+ } catch {
16
+ // fallback
17
+ }
18
+ return "0.6.6";
19
+ };
20
+
21
+ export const FRAMEWORK_VERSION = getPackageVersion();
5
22
 
6
23
  export function getFrameworkDir(projectRoot: string): string {
7
24
  const adapters = [".antigravitycli", ".claude", ".cursor", ".enderun", ".codex"];
@@ -4,7 +4,7 @@
4
4
  "module": "NodeNext",
5
5
  "moduleResolution": "NodeNext",
6
6
  "outDir": "./dist",
7
- "strict": false,
7
+ "strict": true,
8
8
  "esModuleInterop": true,
9
9
  "skipLibCheck": true,
10
10
  "forceConsistentCasingInFileNames": true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-enderun",
3
- "version": "0.6.5",
3
+ "version": "0.6.6",
4
4
  "description": "The Supreme AI Governance & Orchestration Framework for Enterprise Development",
5
5
  "author": "Yusuf BEKAR",
6
6
  "license": "MIT",
@@ -69,7 +69,7 @@
69
69
  "@modelcontextprotocol/sdk": "^1.26.0",
70
70
  "@pandacss/dev": "^0.53.0",
71
71
  "@types/node": "^22.13.4",
72
- "agent-enderun": "^0.6.5",
72
+ "agent-enderun": "^0.6.6",
73
73
  "concurrently": "^9.1.2",
74
74
  "eslint": "^9.20.1",
75
75
  "ts-morph": "^28.0.0",
@@ -80,7 +80,7 @@
80
80
  "zod": "^3.24.2"
81
81
  },
82
82
  "enderun": {
83
- "version": "0.6.5",
83
+ "version": "0.6.6",
84
84
  "initializedAt": "2026-05-23T13:00:32.411Z"
85
85
  },
86
86
  "dependencies": {}
@@ -1,23 +0,0 @@
1
- {
2
- "id": "msg_01H7K9P2Q3R4S5T6U7V8W9X0Y2",
3
- "timestamp": "2026-05-23T18:22:00.000Z",
4
- "from": "@backend",
5
- "to": "@manager",
6
- "traceId": "01H7K9P2Q3R4S5T6U7V8W9X0Y1",
7
- "category": "INFO",
8
- "priority": "MEDIUM",
9
- "status": "COMPLETED",
10
- "subject": "Re: Implement User Authentication DomainError hierarchy",
11
- "content": {
12
- "status": "COMPLETED",
13
- "filesCreated": [
14
- "apps/backend/src/errors/domain-error.ts",
15
- "apps/backend/src/errors/index.ts"
16
- ],
17
- "notes": "Followed the gold standard blueprint exactly. All 6 error classes implemented with proper branded error codes.",
18
- "nextStep": "Ready for review by @analyst"
19
- },
20
- "metadata": {
21
- "inReplyTo": "msg_01H7K9P2Q3R4S5T6U7V8W9X0Y1"
22
- }
23
- }
@@ -1,26 +0,0 @@
1
- {
2
- "id": "msg_01H7K9P2Q3R4S5T6U7V8W9X0Y1",
3
- "timestamp": "2026-05-23T18:15:00.000Z",
4
- "from": "@manager",
5
- "to": "@backend",
6
- "traceId": "01H7K9P2Q3R4S5T6U7V8W9X0Y1",
7
- "category": "DELEGATION",
8
- "priority": "HIGH",
9
- "status": "ACKNOWLEDGED",
10
- "subject": "Implement User Authentication DomainError hierarchy",
11
- "content": {
12
- "task": "Create the standard DomainError base class and all required subclasses (NotFoundError, ValidationError, UnauthorizedError, etc.) in apps/backend/src/errors/",
13
- "reference": "Blueprint: backend/errors/domain-error.ts",
14
- "deadline": "End of current phase",
15
- "constraints": [
16
- "Must follow Branded Types pattern",
17
- "No direct throw new Error() allowed",
18
- "Must be exported from index.ts"
19
- ]
20
- },
21
- "metadata": {
22
- "relatedTo": "trace_01H7K9P2Q3R4S5T6U7V8W9X0Y1",
23
- "requiresResponse": true,
24
- "estimatedEffort": "2 hours"
25
- }
26
- }