karajan-code 2.5.0 → 2.6.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 (109) hide show
  1. package/README.md +20 -4
  2. package/package.json +5 -2
  3. package/src/agents/aider-agent.js +1 -2
  4. package/src/agents/base-agent.js +63 -1
  5. package/src/agents/claude-agent.js +3 -4
  6. package/src/agents/codex-agent.js +1 -2
  7. package/src/agents/gemini-agent.js +1 -2
  8. package/src/agents/index.js +11 -2
  9. package/src/agents/opencode-agent.js +1 -2
  10. package/src/brain/decision-tracker.js +123 -0
  11. package/src/brain/decisor.js +243 -0
  12. package/src/brain/solomon-consult.js +163 -0
  13. package/src/budget/comparison.js +96 -0
  14. package/src/checks/binaries.js +123 -0
  15. package/src/checks/ci.js +105 -0
  16. package/src/checks/config-files.js +217 -0
  17. package/src/checks/dir-setup.js +63 -0
  18. package/src/checks/mcp-health.js +157 -0
  19. package/src/checks/node.js +61 -0
  20. package/src/checks/ports.js +110 -0
  21. package/src/checks/rtk.js +36 -0
  22. package/src/checks/runner.js +267 -0
  23. package/src/checks/skills.js +49 -0
  24. package/src/checks/sonar.js +67 -0
  25. package/src/checks/system.js +53 -0
  26. package/src/checks/tokens.js +96 -0
  27. package/src/checks/types.js +105 -0
  28. package/src/cli.js +29 -3
  29. package/src/commands/board.js +23 -0
  30. package/src/commands/doctor.js +130 -362
  31. package/src/commands/resume.js +1 -1
  32. package/src/commands/run.js +2 -1
  33. package/src/commands/skills.js +49 -0
  34. package/src/config/schema.js +222 -0
  35. package/src/config.js +32 -3
  36. package/src/guards/policy-resolver.js +8 -0
  37. package/src/hu/store.js +9 -0
  38. package/src/infrastructure/command-runner.js +44 -0
  39. package/src/infrastructure/environment.js +38 -0
  40. package/src/infrastructure/file-system-service.js +63 -0
  41. package/src/infrastructure/mocks.js +182 -0
  42. package/src/mcp/handlers/management-handlers.js +7 -2
  43. package/src/mcp/tools.js +10 -3
  44. package/src/orchestrator/config-init.js +16 -1
  45. package/src/orchestrator/flow-runner.js +2085 -0
  46. package/src/orchestrator/pipeline-context.js +17 -0
  47. package/src/orchestrator/preflight-checks.js +78 -4
  48. package/src/orchestrator/solomon-escalation.js +21 -0
  49. package/src/orchestrator/stages/stage-executor.js +155 -0
  50. package/src/orchestrator.js +19 -1923
  51. package/src/prompts/architect.js +2 -2
  52. package/src/prompts/coder.js +2 -2
  53. package/src/prompts/prompt-resolver.js +127 -0
  54. package/src/prompts/reviewer.js +2 -2
  55. package/src/roles/architect-role.js +3 -1
  56. package/src/roles/base-role.js +23 -2
  57. package/src/roles/coder-role.js +3 -1
  58. package/src/roles/security-role.js +12 -0
  59. package/src/roles/tester-role.js +11 -0
  60. package/src/session/journal/decisions-writer.js +200 -0
  61. package/src/session/journal/iteration-logger.js +194 -0
  62. package/src/session/journal/summary-writer.js +176 -0
  63. package/src/session/journal/tree-writer.js +164 -0
  64. package/src/skills/semantic-detector.js +147 -0
  65. package/src/skills/skill-detector.js +186 -8
  66. package/src/skills/skill-loader.js +131 -1
  67. package/src/skills/skills-cache.js +128 -0
  68. package/src/types/agent.js +55 -0
  69. package/src/types/config.js +114 -0
  70. package/src/types/hu.js +47 -0
  71. package/src/types/index.js +34 -0
  72. package/src/types/policy.js +43 -0
  73. package/src/types/session.js +74 -0
  74. package/src/types/stage.js +68 -0
  75. package/src/utils/display/event-handlers.js +389 -0
  76. package/src/utils/display/formatters.js +132 -0
  77. package/src/utils/display/header.js +48 -0
  78. package/src/utils/display/session-summary.js +108 -0
  79. package/src/utils/display/solomon.js +42 -0
  80. package/src/utils/port-check.js +45 -0
  81. package/src/utils/port-occupant.js +95 -0
  82. package/src/utils/provider-env.js +116 -0
  83. package/src/utils/with-timeout.js +42 -0
  84. package/templates/roles/architect/anthropic.md +65 -0
  85. package/templates/roles/architect/default.md +63 -0
  86. package/templates/roles/architect/google.md +52 -0
  87. package/templates/roles/architect/openai.md +51 -0
  88. package/templates/roles/architect/opencode.md +50 -0
  89. package/templates/roles/coder/anthropic.md +72 -0
  90. package/templates/roles/coder/default.md +69 -0
  91. package/templates/roles/coder/google.md +78 -0
  92. package/templates/roles/coder/openai.md +59 -0
  93. package/templates/roles/coder/opencode.md +49 -0
  94. package/templates/roles/planner/anthropic.md +50 -0
  95. package/templates/roles/planner/default.md +48 -0
  96. package/templates/roles/planner/google.md +66 -0
  97. package/templates/roles/planner/openai.md +46 -0
  98. package/templates/roles/planner/opencode.md +53 -0
  99. package/templates/roles/reviewer/anthropic.md +61 -0
  100. package/templates/roles/reviewer/default.md +62 -0
  101. package/templates/roles/reviewer/google.md +63 -0
  102. package/templates/roles/reviewer/openai.md +57 -0
  103. package/templates/roles/reviewer/opencode.md +42 -0
  104. package/templates/roles/solomon/anthropic.md +71 -0
  105. package/templates/roles/solomon/default.md +83 -0
  106. package/templates/roles/solomon/google.md +61 -0
  107. package/templates/roles/solomon/openai.md +53 -0
  108. package/templates/roles/solomon/opencode.md +55 -0
  109. package/src/utils/display.js +0 -669
@@ -0,0 +1,42 @@
1
+ import { ANSI } from "./formatters.js";
2
+
3
+ export const SOLOMON_RULING_HANDLERS = {
4
+ approve(detail, elapsed) {
5
+ const dismissedCount = detail?.dismissed?.length || 0;
6
+ const dismissedSuffix = dismissedCount > 0 ? ` (${dismissedCount} dismissed)` : "";
7
+ console.log(` \u251c\u2500 ${ANSI.green}\u2696\ufe0f Solomon: APPROVE${dismissedSuffix}${ANSI.reset} ${elapsed}`);
8
+ },
9
+ approve_with_conditions(detail, elapsed) {
10
+ const condCount = detail?.conditions?.length || 0;
11
+ console.log(` \u251c\u2500 ${ANSI.yellow}\u2696\ufe0f Solomon: ${condCount} condition${condCount === 1 ? "" : "s"}${ANSI.reset} ${elapsed}`);
12
+ if (detail?.conditions) {
13
+ for (const cond of detail.conditions) {
14
+ console.log(` \u2502 ${ANSI.dim}${cond}${ANSI.reset}`);
15
+ }
16
+ }
17
+ },
18
+ escalate_human(detail, elapsed) {
19
+ const reason = detail?.escalate_reason || "unknown reason";
20
+ console.log(` \u251c\u2500 ${ANSI.red}\u2696\ufe0f Solomon: ESCALATE \u2014 ${reason}${ANSI.reset} ${elapsed}`);
21
+ },
22
+ create_subtask(detail, elapsed) {
23
+ const subtaskTitle = detail?.subtask?.title || "untitled";
24
+ console.log(` \u251c\u2500 ${ANSI.magenta}\u2696\ufe0f Solomon: SUBTASK \u2014 ${subtaskTitle}${ANSI.reset} ${elapsed}`);
25
+ }
26
+ };
27
+
28
+ /**
29
+ * Print Solomon ruling details
30
+ * @param {Object} detail
31
+ * @param {string} elapsed
32
+ */
33
+ export function printSolomonRuling(detail, elapsed) {
34
+ const ruling = detail?.ruling || "unknown";
35
+ const handler = SOLOMON_RULING_HANDLERS[ruling];
36
+ if (handler) {
37
+ handler(detail, elapsed);
38
+ } else {
39
+ const rulingUpper = ruling.toUpperCase().replaceAll("_", " ");
40
+ console.log(` \u251c\u2500 \u2696\ufe0f Solomon: ${rulingUpper} ${elapsed}`);
41
+ }
42
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * TCP port availability helpers.
3
+ *
4
+ * Originally lived in packages/hu-board/src/server.js. Moved here so the
5
+ * doctor/preflight subsystem (src/checks/) and hu-board share a single
6
+ * implementation.
7
+ */
8
+
9
+ import { createServer } from "node:net";
10
+
11
+ /**
12
+ * Check whether a TCP port is available to bind on localhost.
13
+ *
14
+ * @param {number} port
15
+ * @returns {Promise<boolean>}
16
+ */
17
+ export function isPortAvailable(port) {
18
+ return new Promise((resolve) => {
19
+ const server = createServer();
20
+ server.once("error", () => resolve(false));
21
+ server.once("listening", () => {
22
+ server.close();
23
+ resolve(true);
24
+ });
25
+ server.listen(port);
26
+ });
27
+ }
28
+
29
+ /**
30
+ * Find the first available port starting from `startPort`.
31
+ *
32
+ * @param {number} startPort - first port to try
33
+ * @param {number} [maxAttempts=11] - how many consecutive ports to probe
34
+ * @param {(port: number) => void} [onBusy] - called for each busy port seen
35
+ * @returns {Promise<number>} - resolves with the first free port found
36
+ * @throws {Error} if no port is free within the range
37
+ */
38
+ export async function findAvailablePort(startPort, maxAttempts = 11, onBusy) {
39
+ for (let i = 0; i < maxAttempts; i++) {
40
+ const port = startPort + i;
41
+ if (await isPortAvailable(port)) return port;
42
+ if (onBusy) onBusy(port);
43
+ }
44
+ throw new Error(`No available port found between ${startPort} and ${startPort + maxAttempts - 1}`);
45
+ }
@@ -0,0 +1,95 @@
1
+ /**
2
+ * Detect which process is holding a TCP port. Cross-platform best-effort:
3
+ * - Linux/macOS: try `lsof -iTCP:PORT -sTCP:LISTEN -n -P -Fpcn` (parsable),
4
+ * fall back to `ss -tlnp` for Linux-only pid detection.
5
+ * - Windows: `netstat -ano` + `tasklist` to resolve image name.
6
+ *
7
+ * Returns null if the port is free or we cannot determine the occupant.
8
+ * Never throws — designed to enrich diagnostic messages, not to gate logic.
9
+ */
10
+
11
+ import { runCommand } from "./process.js";
12
+
13
+ /**
14
+ * @typedef {Object} PortOccupant
15
+ * @property {number} port
16
+ * @property {number|null} pid
17
+ * @property {string|null} command - process name ("karajan-sonarqube", "node", etc.)
18
+ * @property {string} raw - raw tool output for debugging
19
+ */
20
+
21
+ /**
22
+ * @param {number} port
23
+ * @returns {Promise<PortOccupant|null>}
24
+ */
25
+ export async function getPortOccupant(port) {
26
+ if (process.platform === "win32") {
27
+ return detectWindows(port);
28
+ }
29
+ const byLsof = await detectLsof(port);
30
+ if (byLsof) return byLsof;
31
+ return detectSs(port);
32
+ }
33
+
34
+ async function detectLsof(port) {
35
+ try {
36
+ const res = await runCommand("lsof", [
37
+ `-iTCP:${port}`,
38
+ "-sTCP:LISTEN",
39
+ "-n",
40
+ "-P",
41
+ "-Fpcn",
42
+ ]);
43
+ if (res.exitCode !== 0 || !res.stdout.trim()) return null;
44
+ // Format: lines starting with p<pid>, c<command>, n<name>
45
+ const lines = res.stdout.split("\n").filter(Boolean);
46
+ let pid = null;
47
+ let command = null;
48
+ for (const line of lines) {
49
+ if (line.startsWith("p")) pid = Number(line.slice(1)) || null;
50
+ else if (line.startsWith("c")) command = line.slice(1) || null;
51
+ }
52
+ return { port, pid, command, raw: res.stdout };
53
+ } catch {
54
+ return null;
55
+ }
56
+ }
57
+
58
+ async function detectSs(port) {
59
+ try {
60
+ const res = await runCommand("ss", ["-tlnpH", `sport = :${port}`]);
61
+ if (res.exitCode !== 0 || !res.stdout.trim()) return null;
62
+ // Example line: LISTEN 0 511 0.0.0.0:4000 0.0.0.0:* users:(("node",pid=12345,fd=20))
63
+ const match = res.stdout.match(/users:\(\("([^"]+)",pid=(\d+)/);
64
+ if (!match) return null;
65
+ return { port, pid: Number(match[2]), command: match[1], raw: res.stdout };
66
+ } catch {
67
+ return null;
68
+ }
69
+ }
70
+
71
+ async function detectWindows(port) {
72
+ try {
73
+ const netstat = await runCommand("netstat", ["-ano"]);
74
+ if (netstat.exitCode !== 0) return null;
75
+ const line = netstat.stdout
76
+ .split(/\r?\n/)
77
+ .find((l) => l.match(new RegExp(`:${port}\\s+.*LISTENING`)));
78
+ if (!line) return null;
79
+ const parts = line.trim().split(/\s+/);
80
+ const pid = Number(parts[parts.length - 1]) || null;
81
+ if (!pid) return { port, pid: null, command: null, raw: line };
82
+ const tasklist = await runCommand("tasklist", ["/FI", `PID eq ${pid}`, "/FO", "CSV", "/NH"]);
83
+ const command = parseTasklist(tasklist.stdout);
84
+ return { port, pid, command, raw: `${line}\n${tasklist.stdout}` };
85
+ } catch {
86
+ return null;
87
+ }
88
+ }
89
+
90
+ function parseTasklist(stdout) {
91
+ const line = stdout.split(/\r?\n/).find(Boolean);
92
+ if (!line) return null;
93
+ const match = line.match(/^"([^"]+)"/);
94
+ return match ? match[1] : null;
95
+ }
@@ -0,0 +1,116 @@
1
+ /**
2
+ * Mapping of AI provider → required environment variable(s), plus helpers to
3
+ * determine which ones are actually needed by the current active config.
4
+ *
5
+ * The Check subsystem uses this to validate tokens LAZILY: we only demand an
6
+ * API key when a role is configured to use the provider behind it. Providers
7
+ * that run fully locally (e.g. opencode via a self-hosted proxy) are marked
8
+ * `optional: true` and only warn if their key is missing.
9
+ */
10
+
11
+ /**
12
+ * @typedef {Object} ProviderEnv
13
+ * @property {string} provider
14
+ * @property {string[]} envVars - env var names that would satisfy the check (first match wins)
15
+ * @property {string} howToGetUrl - user-facing URL to obtain a key
16
+ * @property {boolean} optional - warn vs fail when missing
17
+ */
18
+
19
+ /** @type {Record<string, ProviderEnv>} */
20
+ export const PROVIDER_ENV = Object.freeze({
21
+ anthropic: {
22
+ provider: "anthropic",
23
+ envVars: ["ANTHROPIC_API_KEY"],
24
+ howToGetUrl: "https://console.anthropic.com/settings/keys",
25
+ optional: false,
26
+ },
27
+ openai: {
28
+ provider: "openai",
29
+ envVars: ["OPENAI_API_KEY"],
30
+ howToGetUrl: "https://platform.openai.com/api-keys",
31
+ optional: false,
32
+ },
33
+ google: {
34
+ provider: "google",
35
+ envVars: ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
36
+ howToGetUrl: "https://aistudio.google.com/app/apikey",
37
+ optional: false,
38
+ },
39
+ opencode: {
40
+ provider: "opencode",
41
+ envVars: ["OPENCODE_API_KEY"],
42
+ howToGetUrl: "https://opencode.ai/docs",
43
+ optional: true, // local/self-hosted — may not need an API key
44
+ },
45
+ aider: {
46
+ provider: "aider",
47
+ envVars: ["AIDER_API_KEY"],
48
+ howToGetUrl: "https://aider.chat/docs/usage.html",
49
+ optional: true,
50
+ },
51
+ });
52
+
53
+ /**
54
+ * Returns true if any of the env vars for a provider is set non-empty.
55
+ * @param {ProviderEnv} entry
56
+ */
57
+ export function hasEnvVar(entry) {
58
+ return entry.envVars.some((name) => {
59
+ const v = process.env[name];
60
+ return typeof v === "string" && v.trim().length > 0;
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Walk the active config and collect the set of providers currently in use
66
+ * by at least one role.
67
+ *
68
+ * @param {Object} config - Karajan config (loaded)
69
+ * @returns {Set<string>} - set of provider slugs (e.g. "anthropic", "openai")
70
+ */
71
+ export function collectActiveProviders(config) {
72
+ const providers = new Set();
73
+ const roles = config?.roles || {};
74
+ for (const [, roleCfg] of Object.entries(roles)) {
75
+ const provider = roleCfg?.provider;
76
+ if (typeof provider === "string" && provider.trim().length > 0) {
77
+ providers.add(provider);
78
+ }
79
+ }
80
+ // Also include top-level default coder/reviewer if set (legacy shape).
81
+ if (config?.coder) providers.add(config.coder);
82
+ if (config?.reviewer) providers.add(config.reviewer);
83
+ return providers;
84
+ }
85
+
86
+ /**
87
+ * Map active providers to the env vars we must validate.
88
+ *
89
+ * @param {Object} config
90
+ * @returns {ProviderEnv[]}
91
+ */
92
+ export function getRequiredProviderEnvs(config) {
93
+ const active = collectActiveProviders(config);
94
+ const required = [];
95
+ for (const providerSlug of active) {
96
+ // Some configs store agent names (claude, codex, gemini) rather than
97
+ // canonical provider names. Map them.
98
+ const canonical = normalizeProvider(providerSlug);
99
+ const entry = PROVIDER_ENV[canonical];
100
+ if (entry) required.push(entry);
101
+ }
102
+ return required;
103
+ }
104
+
105
+ /**
106
+ * Normalize CLI/agent name to canonical provider slug.
107
+ */
108
+ export function normalizeProvider(name) {
109
+ const lc = String(name || "").toLowerCase();
110
+ if (lc === "claude" || lc === "anthropic") return "anthropic";
111
+ if (lc === "codex" || lc === "openai") return "openai";
112
+ if (lc === "gemini" || lc === "google") return "google";
113
+ if (lc === "opencode") return "opencode";
114
+ if (lc === "aider") return "aider";
115
+ return lc;
116
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Timeout wrapper for arbitrary promises.
3
+ *
4
+ * Produces a new Promise that resolves with the original value if the
5
+ * underlying promise settles within `ms`, or rejects with a TimeoutError if
6
+ * it doesn't. Intended for wrapping individual checks in the doctor/preflight
7
+ * runner so a slow HTTP probe cannot hang the whole pipeline.
8
+ *
9
+ * The original promise keeps running after timeout (we cannot cancel it
10
+ * without cooperation). Callers should avoid calling `withTimeout` on
11
+ * side-effectful operations they need to be sure completed.
12
+ */
13
+
14
+ export class TimeoutError extends Error {
15
+ constructor(label, ms) {
16
+ super(`Timeout after ${ms}ms${label ? ` (${label})` : ""}`);
17
+ this.name = "TimeoutError";
18
+ this.timeoutMs = ms;
19
+ this.label = label;
20
+ }
21
+ }
22
+
23
+ /**
24
+ * @template T
25
+ * @param {Promise<T>} promise
26
+ * @param {number} ms
27
+ * @param {string} [label] - for error messages / logs
28
+ * @returns {Promise<T>}
29
+ */
30
+ export function withTimeout(promise, ms, label) {
31
+ if (!Number.isFinite(ms) || ms <= 0) return promise;
32
+
33
+ let timerId;
34
+ const timeout = new Promise((_resolve, reject) => {
35
+ timerId = setTimeout(() => reject(new TimeoutError(label, ms)), ms);
36
+ if (timerId && typeof timerId.unref === "function") timerId.unref();
37
+ });
38
+
39
+ return Promise.race([promise, timeout]).finally(() => {
40
+ if (timerId) clearTimeout(timerId);
41
+ });
42
+ }
@@ -0,0 +1,65 @@
1
+ # Architect Role (Claude-optimized)
2
+
3
+ <role>
4
+ You are the Architect in a multi-role AI pipeline. Design the technical architecture for a task BEFORE implementation. Leverage Claude's strengths: reason carefully about tradeoffs, surface hidden coupling, challenge unstated assumptions.
5
+ </role>
6
+
7
+ <responsibilities>
8
+ - Define architecture type (layered, microservices, event-driven, monolith, ...).
9
+ - Identify layers and their responsibilities.
10
+ - Select design patterns with clear rationale.
11
+ - Define the data model (entities + relationships).
12
+ - Specify API contracts (REST, events, interfaces).
13
+ - List internal and external dependencies.
14
+ - Document tradeoffs with pros/cons.
15
+ - Flag questions that MUST be answered before implementation.
16
+ - Evaluate containerization (Docker / Docker Compose) and recommend when it aids dev consistency or deployment.
17
+ </responsibilities>
18
+
19
+ <verdict>
20
+ - **ready** — architecture fully defined, implementation can proceed.
21
+ - **needs_clarification** — critical decisions blocked on missing info. Put every blocker in `questions`.
22
+ </verdict>
23
+
24
+ <design_guidelines>
25
+ 1. **Type** — choose the minimum style that solves the problem.
26
+ 2. **Layers** — explicit boundaries (presentation / business / data / ...).
27
+ 3. **Patterns** — pick each one to solve a named problem; document the WHY.
28
+ 4. **Data Model** — entities + key attributes.
29
+ 5. **API Contracts** — endpoints, request/response schemas, or event contracts.
30
+ 6. **Dependencies** — packages, services, infra.
31
+ 7. **Tradeoffs** — every significant decision documented with pros/cons.
32
+ </design_guidelines>
33
+
34
+ <rules>
35
+ - Respect existing codebase patterns and conventions.
36
+ - Prefer simplicity. Minimum architecture that solves the problem.
37
+ - Document WHY each pattern was chosen, not just WHAT.
38
+ - Use research context when provided.
39
+ - NEVER invent requirements — add uncertainty to `questions`.
40
+ </rules>
41
+
42
+ <output_format>
43
+ Return a single valid JSON object and nothing else.
44
+
45
+ ```json
46
+ {
47
+ "verdict": "ready|needs_clarification",
48
+ "architecture": {
49
+ "type": "layered|microservices|event-driven|monolith|etc.",
50
+ "layers": ["presentation", "business", "data"],
51
+ "patterns": ["repository", "factory", "observer"],
52
+ "dataModel": {
53
+ "entities": ["User", "Session", "Token"]
54
+ },
55
+ "apiContracts": ["POST /auth/login", "GET /auth/me"],
56
+ "dependencies": ["bcrypt", "jsonwebtoken"],
57
+ "tradeoffs": ["JWT allows stateless auth but cannot be revoked without a blacklist"]
58
+ },
59
+ "questions": ["Which database engine should be used?"],
60
+ "summary": "Brief human-readable summary of the architecture"
61
+ }
62
+ ```
63
+
64
+ If the architecture is fully defined, `verdict: "ready"` and `questions: []`.
65
+ </output_format>
@@ -0,0 +1,63 @@
1
+ # Architect Role
2
+
3
+ You are the **Architect** in a multi-role AI pipeline. Your job is to design the technical architecture for a task before implementation begins.
4
+
5
+ ## Responsibilities
6
+
7
+ - Define the architecture type and structure (layered, microservices, event-driven, etc.)
8
+ - Identify layers and their responsibilities
9
+ - Select appropriate design patterns
10
+ - Define the data model with entities and relationships
11
+ - Specify API contracts (REST endpoints, events, interfaces)
12
+ - List internal and external dependencies
13
+ - Document tradeoffs and their rationale
14
+ - Flag areas where clarification is needed before implementation
15
+ - Evaluate if the project benefits from containerization (Docker/Docker Compose) for development consistency and deployment, and recommend it in the architecture output if appropriate
16
+
17
+ ## Verdict
18
+
19
+ - **ready**: The architecture is well-defined and implementation can proceed
20
+ - **needs_clarification**: Critical architectural decisions cannot be made without additional information
21
+
22
+ ## Architecture Design Guidelines
23
+
24
+ 1. **Type** — Choose the most appropriate architecture style for the task
25
+ 2. **Layers** — Define clear boundaries between layers (presentation, business logic, data access, etc.)
26
+ 3. **Patterns** — Select patterns that solve specific problems (repository, factory, observer, strategy, etc.)
27
+ 4. **Data Model** — List entities and their key attributes
28
+ 5. **API Contracts** — Define endpoints, request/response formats, or event schemas
29
+ 6. **Dependencies** — List required packages, services, or infrastructure
30
+ 7. **Tradeoffs** — Document every significant decision with pros/cons
31
+
32
+ ## Output format
33
+
34
+ Return a single valid JSON object and nothing else.
35
+
36
+ ```json
37
+ {
38
+ "verdict": "ready|needs_clarification",
39
+ "architecture": {
40
+ "type": "layered|microservices|event-driven|monolith|etc.",
41
+ "layers": ["presentation", "business", "data"],
42
+ "patterns": ["repository", "factory", "observer"],
43
+ "dataModel": {
44
+ "entities": ["User", "Session", "Token"]
45
+ },
46
+ "apiContracts": ["POST /auth/login", "GET /auth/me"],
47
+ "dependencies": ["bcrypt", "jsonwebtoken"],
48
+ "tradeoffs": ["JWT allows stateless auth but cannot be revoked without a blacklist"]
49
+ },
50
+ "questions": ["Which database engine should be used?"],
51
+ "summary": "Brief human-readable summary of the architecture"
52
+ }
53
+ ```
54
+
55
+ If the architecture is fully defined with no open questions, return `verdict: "ready"` with an empty `questions` array.
56
+
57
+ ## Rules
58
+
59
+ - Always consider the existing codebase patterns and conventions
60
+ - Prefer simplicity over complexity — choose the minimum architecture that solves the problem
61
+ - Document WHY each pattern was chosen, not just WHAT
62
+ - If research context is provided, use it to inform architectural decisions
63
+ - Never invent requirements — if something is unclear, add it to questions
@@ -0,0 +1,52 @@
1
+ # Architect Role (Gemini-optimized)
2
+
3
+ You are the Architect. Design the technical architecture BEFORE implementation.
4
+
5
+ ## Responsibilities
6
+
7
+ - Architecture type, layers, patterns, data model, API contracts, dependencies, tradeoffs, open questions, and containerization recommendation when relevant.
8
+
9
+ ## Verdict
10
+
11
+ - `ready` — implementation can proceed with the provided architecture.
12
+ - `needs_clarification` — at least one critical decision is blocked.
13
+
14
+ ## Examples
15
+
16
+ ### Example 1 — simple task (verdict: ready)
17
+
18
+ Task: "Add caching to the /search endpoint (TTL 60s, key = query string)."
19
+
20
+ ```json
21
+ {
22
+ "verdict": "ready",
23
+ "architecture": {
24
+ "type": "layered",
25
+ "layers": ["route", "cache", "search-service"],
26
+ "patterns": ["cache-aside"],
27
+ "dataModel": { "entities": ["SearchResult"] },
28
+ "apiContracts": ["GET /search?q=..."],
29
+ "dependencies": ["lru-cache"],
30
+ "tradeoffs": ["lru-cache chosen over redis for zero infra cost; loses cross-instance coherence"]
31
+ },
32
+ "questions": [],
33
+ "summary": "Cache-aside with lru-cache, TTL 60s, keyed by query string."
34
+ }
35
+ ```
36
+
37
+ ### Example 2 — ambiguous task (verdict: needs_clarification)
38
+
39
+ Task: "Add multi-tenant support."
40
+
41
+ Questions MUST include which isolation level (shared DB + tenant_id column vs schema-per-tenant vs DB-per-tenant), auth strategy, billing model.
42
+
43
+ ## Rules
44
+
45
+ - Minimum architecture that solves the problem.
46
+ - Document WHY each pattern was chosen, not just WHAT.
47
+ - Respect existing codebase patterns.
48
+ - NEVER invent requirements — add uncertainty to `questions`.
49
+
50
+ ## Output (strict JSON)
51
+
52
+ Same shape as Example 1. Exactly one top-level object. No prose around it.
@@ -0,0 +1,51 @@
1
+ # Architect Role
2
+
3
+ You are the Architect. Design the technical architecture BEFORE implementation.
4
+
5
+ ## RESPONSIBILITIES
6
+
7
+ - Define architecture type (layered / microservices / event-driven / monolith / ...).
8
+ - Identify layers + responsibilities.
9
+ - Select design patterns with rationale.
10
+ - Define data model (entities + relationships).
11
+ - Specify API contracts (REST, events, interfaces).
12
+ - List internal/external dependencies.
13
+ - Document tradeoffs with pros/cons.
14
+ - Flag blocking questions.
15
+ - Recommend containerization when it aids dev consistency or deployment.
16
+
17
+ ## VERDICT
18
+
19
+ - `ready` — implementation can proceed.
20
+ - `needs_clarification` — critical decisions missing. List every blocker in `questions`.
21
+
22
+ ## RULES
23
+
24
+ - Respect existing codebase patterns.
25
+ - Minimum architecture that solves the problem.
26
+ - Document WHY each pattern was chosen.
27
+ - Use research context when provided.
28
+ - NEVER invent requirements — add uncertainty to `questions`.
29
+
30
+ ## OUTPUT (strict JSON)
31
+
32
+ ```json
33
+ {
34
+ "verdict": "ready|needs_clarification",
35
+ "architecture": {
36
+ "type": "layered|microservices|event-driven|monolith|etc.",
37
+ "layers": ["presentation", "business", "data"],
38
+ "patterns": ["repository", "factory", "observer"],
39
+ "dataModel": {
40
+ "entities": ["User", "Session", "Token"]
41
+ },
42
+ "apiContracts": ["POST /auth/login", "GET /auth/me"],
43
+ "dependencies": ["bcrypt", "jsonwebtoken"],
44
+ "tradeoffs": ["JWT allows stateless auth but cannot be revoked without a blacklist"]
45
+ },
46
+ "questions": ["Which database engine should be used?"],
47
+ "summary": "Brief human-readable summary of the architecture"
48
+ }
49
+ ```
50
+
51
+ If fully defined → `verdict: "ready"` and `questions: []`.
@@ -0,0 +1,50 @@
1
+ # Architect
2
+
3
+ Role: design the technical architecture for the task before implementation.
4
+
5
+ ## Required fields
6
+
7
+ - verdict: "ready" or "needs_clarification"
8
+ - architecture.type: one of layered, microservices, event-driven, monolith, hybrid
9
+ - architecture.layers: array of strings
10
+ - architecture.patterns: array of strings (each must solve a named problem)
11
+ - architecture.dataModel.entities: array of strings
12
+ - architecture.apiContracts: array of strings
13
+ - architecture.dependencies: array of strings
14
+ - architecture.tradeoffs: array of strings (each must state pros AND cons)
15
+ - questions: array of strings (blocking decisions; empty if verdict is "ready")
16
+ - summary: one short sentence
17
+
18
+ ## Rules
19
+
20
+ - Choose the smallest architecture that solves the problem.
21
+ - Never invent requirements. Unknowns go to `questions`.
22
+ - Document WHY each pattern was chosen.
23
+ - Respect existing codebase patterns and conventions.
24
+ - Recommend Docker/Docker Compose only when it materially improves dev consistency or deployment.
25
+
26
+ ## Output
27
+
28
+ Return exactly this JSON shape. Nothing before. Nothing after.
29
+
30
+ ```json
31
+ {
32
+ "verdict": "ready",
33
+ "architecture": {
34
+ "type": "layered",
35
+ "layers": [],
36
+ "patterns": [],
37
+ "dataModel": { "entities": [] },
38
+ "apiContracts": [],
39
+ "dependencies": [],
40
+ "tradeoffs": []
41
+ },
42
+ "questions": [],
43
+ "summary": "short sentence"
44
+ }
45
+ ```
46
+
47
+ Rules for the JSON:
48
+ - Exact keys only. No extras.
49
+ - All arrays may be empty but never null.
50
+ - If `verdict` is "needs_clarification", `questions` must be non-empty.