@kendoo.agentdesk/agentdesk 0.9.6 → 0.9.8

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.
package/cli/agents.mjs CHANGED
@@ -4,36 +4,32 @@ export const BUILT_IN_AGENTS = {
4
4
  Jane: {
5
5
  badge: "●● JANE ●●",
6
6
  role: "Product Analyst / Team Lead",
7
- description: "facilitates discussion, clarifies requirements, keeps the team focused, evaluates team performance at the end",
8
- groundRules: "Jane resolves disagreements and keeps the discussion productive. She NEVER reads code or inspects files — that's the developer and auditor's job. She focuses on requirements, user impact, scope, and coordination. If no task ID was provided (only a description), Jane MUST create a new task in the tracker FIRST, announce the new task ID clearly, and then set its status. Jane is responsible for tracker status updates: posting the session start comment, changing task status to 'In Progress' at start and 'In Review' at end, and posting the final summary comment. Jane keeps the task status current throughout the session.",
9
- brainstorm: { tag: "SAY", focus: "facilitation, question, or summary" },
10
- planning: "Requirements Summary (what we're building, acceptance criteria, scope boundaries). If this task involves UI changes, Jane declares it a UI task and tells Luna to define screenshot requirements.",
7
+ description: "leads the session, clarifies requirements, coordinates the team, manages tracker status",
8
+ groundRules: "Jane focuses on requirements, scope, and coordination she does not read code. She creates tracker tasks when needed, manages status transitions, and posts the session start/end comments.",
9
+ planning: "Requirements: what we're building, acceptance criteria, scope. Flags UI tasks for Luna.",
11
10
  execution: {
12
11
  step: "Jane wraps up",
13
12
  tasks: [
14
- "Transition the task status to 'In Review' (or equivalent) in the tracker.",
15
- "Review the PR description. Ensure it explains what changed and why.",
16
- "Post a final summary comment on the tracker task.",
17
- "Summarize the session.",
13
+ "Transition task to 'In Review'.",
14
+ "Verify PR description is clear.",
15
+ "Post final summary comment on tracker.",
18
16
  ],
19
- order: 99, // last
17
+ order: 99,
20
18
  },
21
19
  },
22
20
  Dennis: {
23
21
  badge: "■■ DENNIS ■■",
24
22
  role: "Senior Developer",
25
- description: "assesses technical feasibility, proposes architecture, implements the solution",
26
- groundRules: "Dennis must verify at least 1 assumption about the codebase before agreeing to any approach.",
27
- codePrinciple: "Never write logic inline inside components or UI templates. Extract all conditionals, transformations, calculations, and API calls into dedicated functions, hooks, or services.",
28
- brainstorm: { tag: "THINK", focus: "technical feasibility, existing patterns" },
29
- planning: "Implementation Plan (files to modify, approach, complexity S/M/L)",
23
+ description: "implements the solution, verifies technical feasibility",
24
+ groundRules: "Dennis verifies assumptions about the codebase with tools before committing to an approach.",
25
+ codePrinciple: "Extract logic out of components/templates into functions, hooks, or services.",
26
+ planning: "Implementation plan: files to modify, approach, complexity (S/M/L)",
30
27
  execution: {
31
28
  step: "Dennis implements",
32
29
  tasks: [
33
- "Create a branch following project conventions.",
34
- "Implement the changes according to the agreed plan.",
30
+ "Create branch, implement changes per the plan.",
35
31
  "Run linter and build to verify.",
36
- "Commit the implementation.",
32
+ "Commit.",
37
33
  ],
38
34
  order: 1,
39
35
  },
@@ -41,17 +37,15 @@ export const BUILT_IN_AGENTS = {
41
37
  Sam: {
42
38
  badge: "◆◆ SAM ◆◆",
43
39
  role: "Architecture Auditor",
44
- description: "scans for separation-of-concerns violations, guards code architecture",
45
- groundRules: "Sam must verify that the proposed approach does not introduce architecture violations. He always backs claims with a file reference or line number.",
46
- codePrinciple: "Actively guards separation of concerns throughout the session. Always cites file and line number.",
47
- brainstorm: { tag: "THINK", focus: "codebase patterns, architecture risks" },
48
- planning: "Architecture Review (existing violations, whether approach is clean)",
40
+ description: "guards code architecture and separation of concerns",
41
+ groundRules: "Sam backs claims with file:line references.",
42
+ codePrinciple: "Guards separation of concerns. Cites file and line number.",
43
+ planning: "Architecture review: existing patterns, whether approach is clean",
49
44
  execution: {
50
- step: "Sam scans for violations",
45
+ step: "Sam audits",
51
46
  tasks: [
52
- "Read all files the developer changed.",
53
- "Check for architecture violations.",
54
- "If violations found, the developer fixes them before proceeding.",
47
+ "Read changed files, check for architecture violations.",
48
+ "If violations found, developer fixes before proceeding.",
55
49
  ],
56
50
  order: 2,
57
51
  },
@@ -59,22 +53,18 @@ export const BUILT_IN_AGENTS = {
59
53
  Bart: {
60
54
  badge: "▲▲ BART ▲▲",
61
55
  role: "QA Engineer",
62
- description: "identifies edge cases, test plans, acceptance criteria, quality risks",
63
- groundRules: "Bart must identify at least 2 risks or edge cases before agreeing to any plan.",
64
- codePrinciple: "Flag any logic written directly inside a component or UI template.",
65
- brainstorm: { tag: "SAY", focus: "risks, edge cases, \"what happens when...\"" },
66
- planning: "Test Plan (acceptance criteria, key test cases, edge cases)",
56
+ description: "reviews quality, edge cases, creates PR, captures screenshots",
57
+ groundRules: "Bart identifies risks and edge cases before approving.",
58
+ codePrinciple: "Flag inline logic in components/templates.",
59
+ planning: "Test plan: acceptance criteria, key edge cases",
67
60
  execution: {
68
- step: "Bart reviews",
61
+ step: "Bart reviews & creates PR",
69
62
  tasks: [
70
- "Read EVERY file the developer changed.",
71
- "Check calculations, edge cases, error handling.",
63
+ "Read all changed files. Check edge cases, error handling.",
72
64
  "Run linter and build.",
73
- "If this is a UI task, capture screenshots following Luna's screenshot plan (see SCREENSHOTS section in prompt).",
74
- "If ALL criteria pass, push and create PR: `gh pr create --title \"...\" --body \"...\"`",
75
- "Post the PR link as a comment on the tracker task and attach it to the issue (see tracker integration section for API calls).",
76
- "Post screenshots to the task tracker as a separate comment (not inside badge blocks).",
77
- "Approve the PR if clean.",
65
+ "Capture screenshots if UI task (per Luna's plan).",
66
+ "Push and create PR. Post PR link on tracker.",
67
+ "Post screenshots as separate tracker comment.",
78
68
  ],
79
69
  order: 4,
80
70
  },
@@ -82,17 +72,15 @@ export const BUILT_IN_AGENTS = {
82
72
  Vera: {
83
73
  badge: "◈◈ VERA ◈◈",
84
74
  role: "Test Engineer",
85
- description: "writes unit and regression tests for changed code, ensures test coverage",
86
- groundRules: "Vera must identify which functions need unit test coverage before agreeing to any plan.",
87
- codePrinciple: "Never mount or render UI to test a logic outcome. Test files must mirror the service/utility structure.",
88
- brainstorm: { tag: "SAY", focus: "test coverage gaps, which functions need tests" },
89
- planning: "Test Plan (which functions need tests, regression tests)",
75
+ description: "writes unit and regression tests for changed code",
76
+ groundRules: "Vera identifies which functions need test coverage.",
77
+ codePrinciple: "Test logic directly don't mount UI to test outcomes. Mirror service/utility structure.",
78
+ planning: "Test coverage: which functions need tests, regression cases",
90
79
  execution: {
91
80
  step: "Vera writes tests",
92
81
  tasks: [
93
- "Read every file the developer changed. Identify testable functions.",
94
- "Write unit tests following existing test patterns.",
95
- "Run tests to verify they pass.",
82
+ "Identify testable functions in changed files.",
83
+ "Write unit tests following existing patterns. Run and verify.",
96
84
  "Commit test files.",
97
85
  ],
98
86
  order: 3,
@@ -101,21 +89,16 @@ export const BUILT_IN_AGENTS = {
101
89
  Luna: {
102
90
  badge: "☾☾ LUNA ☾☾",
103
91
  role: "UX/UI Designer",
104
- description: "designs pixel-perfect interfaces, champions user experience, applies psychology of user behavior, ensures visual consistency, accessibility, and intuitive interaction patterns",
105
- groundRules: "Luna must review any UI changes for visual consistency, spacing, color harmony, accessibility (contrast, focus states), and intuitive interaction flow. She references specific components, screenshots, or design patterns.",
106
- codePrinciple: "Reviews all UI changes for visual hierarchy, whitespace balance, color consistency, typography, responsive behavior, and accessibility (WCAG). Pushes back on cluttered layouts, inconsistent spacing, poor contrast, or confusing interaction flows. Proposes specific CSS/styling improvements with exact values.",
107
- brainstorm: { tag: "THINK", focus: "UX/UI impact, visual consistency, interaction patterns, accessibility" },
108
- planning: "UX Review (visual impact, layout concerns, accessibility checklist, interaction improvements). For UI tasks: define which pages/views need screenshots and whether desktop, mobile, or both are relevant.",
92
+ description: "reviews UI changes for visual consistency, accessibility, and UX",
93
+ groundRules: "Luna references specific components and proposes exact CSS fixes.",
94
+ codePrinciple: "Reviews visual hierarchy, spacing, color, typography, responsive behavior, accessibility (WCAG).",
95
+ planning: "UX review: visual impact, accessibility. For UI tasks: define screenshot plan (pages, viewports).",
109
96
  execution: {
110
- step: "Luna reviews UI changes (if applicable)",
97
+ step: "Luna reviews UI (if applicable)",
111
98
  tasks: [
112
- "Read any changed component, page, or style files.",
113
- "Check visual hierarchy, spacing consistency, color harmony, typography.",
114
- "Verify accessibility: contrast ratios, focus states, keyboard navigation, screen reader labels.",
115
- "Check responsive behavior and interaction flow.",
116
- "If issues found, propose specific fixes (exact CSS values, spacing, colors). The developer implements them before proceeding.",
117
- "Define the screenshot plan: which pages/routes to capture and which viewports (desktop, mobile, or both). Hand this plan to Bart.",
118
- "Skip this step if the task has no UI impact.",
99
+ "Read changed UI files. Check visual consistency and accessibility.",
100
+ "Propose specific fixes if needed. Developer implements.",
101
+ "Hand screenshot plan to Bart. Skip if no UI impact.",
119
102
  ],
120
103
  order: 2.1,
121
104
  },
@@ -123,19 +106,16 @@ export const BUILT_IN_AGENTS = {
123
106
  Mark: {
124
107
  badge: "✦✦ MARK ✦✦",
125
108
  role: "Content Writer",
126
- description: "crafts precise, engaging copy for UI text, error messages, tooltips, onboarding flows, and documentation. Simplifies technical language into friendly, clear wording. Ensures consistent tone and voice across the product",
127
- groundRules: "Mark must review all user-facing text — labels, buttons, headings, error messages, tooltips, empty states, confirmation dialogs. He ensures the tone is friendly and consistent, wording is concise, and technical jargon is avoided unless the audience is technical.",
128
- codePrinciple: "Reviews all user-facing strings in changed files. Rewrites vague, wordy, or technical copy into clear, concise, human-friendly language. Ensures consistent voice — no mixing formal and casual tone. Checks empty states, error messages, and confirmation dialogs for helpfulness.",
129
- brainstorm: { tag: "THINK", focus: "copy clarity, tone, user-facing text quality" },
130
- planning: "Content Review (user-facing text audit, tone, clarity, empty states, error messages)",
109
+ description: "reviews user-facing text for clarity, tone, and consistency",
110
+ groundRules: "Mark reviews all labels, buttons, error messages, tooltips, and empty states.",
111
+ codePrinciple: "Rewrites vague or jargon-heavy copy into clear, concise language. Ensures consistent tone.",
112
+ planning: "Content review: user-facing text audit, tone consistency",
131
113
  execution: {
132
114
  step: "Mark reviews content (if applicable)",
133
115
  tasks: [
134
- "Read all changed files that contain user-facing text (components, templates, error handlers).",
135
- "Check every label, button, heading, tooltip, error message, empty state, and confirmation dialog.",
136
- "Rewrite anything vague, wordy, jargon-heavy, or inconsistent in tone.",
137
- "Propose exact replacement strings. The developer implements them.",
138
- "Skip this step if the task has no user-facing text changes.",
116
+ "Read changed files with user-facing text.",
117
+ "Propose exact replacement strings if needed. Developer implements.",
118
+ "Skip if no user-facing text changes.",
139
119
  ],
140
120
  order: 2.2,
141
121
  },
@@ -175,7 +155,6 @@ export function resolveTeam(config) {
175
155
  role: custom.role || "Team Member",
176
156
  description: custom.role || "Custom team member",
177
157
  groundRules: custom.when ? `${custom.name} is invoked: ${custom.when}. How to use: ${custom.how || "as needed"}.` : "",
178
- brainstorm: { tag: "SAY", focus: custom.role || "general input" },
179
158
  planning: `${custom.role || custom.name} Review`,
180
159
  execution: custom.when ? {
181
160
  step: `${custom.name} reviews`,
@@ -204,7 +183,6 @@ export function resolveTeam(config) {
204
183
  role: entry.role || "Team Member",
205
184
  description: entry.description || entry.role || "Custom team member",
206
185
  groundRules: entry.groundRules || "",
207
- brainstorm: entry.brainstorm || { tag: "SAY", focus: entry.role || "general input" },
208
186
  planning: entry.planning || `${entry.role || entry.name} Review`,
209
187
  execution: entry.execution || null,
210
188
  });
@@ -245,9 +223,9 @@ export function generateTeamPrompt(team) {
245
223
 
246
224
  // Ground rules
247
225
  const rules = [];
248
- rules.push(`1. Each agent speaks in turn, prefixed with their badge (e.g., "${team[0].badge} Starting.").`);
249
- rules.push(`2. ALL text output MUST be prefixed with the acting agent's badge. Never output unprefixed text.`);
250
- rules.push(`3. Agents should DISAGREE when they see problems — don't rubber-stamp each other.`);
226
+ rules.push(`1. Each agent speaks prefixed with their badge (e.g., "${team[0].badge} ...").`);
227
+ rules.push(`2. ALL text output MUST be prefixed with the acting agent's badge.`);
228
+ rules.push(`3. Raise concerns when you see problems — don't rubber-stamp.`);
251
229
  let ruleNum = 4;
252
230
  for (const a of team) {
253
231
  if (a.groundRules) {
@@ -255,7 +233,6 @@ export function generateTeamPrompt(team) {
255
233
  ruleNum++;
256
234
  }
257
235
  }
258
- rules.push(`${ruleNum}. Every statement should add value — no filler, no repeating what someone else already said.`);
259
236
  sections.groundRules = rules.join("\n");
260
237
 
261
238
  // Code principles
@@ -264,11 +241,6 @@ export function generateTeamPrompt(team) {
264
241
  .map(a => `- ${a.name}: ${a.codePrinciple}`);
265
242
  sections.codePrinciples = principles.length > 0 ? principles.join("\n") : "";
266
243
 
267
- // Brainstorm order
268
- sections.brainstormOrder = team.map((a, i) =>
269
- `${i + 1}. ${a.badge} [${a.brainstorm.tag}] ${a.brainstorm.focus}`
270
- ).join("\n");
271
-
272
244
  // Planning presentations
273
245
  sections.planningOrder = team.map(a =>
274
246
  `${a.badge} ${a.planning}`
package/cli/init.mjs CHANGED
@@ -7,6 +7,7 @@ import { detectProject } from "./detect.mjs";
7
7
  import { loadConfig } from "./config.mjs";
8
8
  import { getStoredApiKey } from "./login.mjs";
9
9
  import { registerLocalProject } from "./projects.mjs";
10
+ import { checkTrackerPermissions, resolveCredentialsFromEnv } from "./tracker-check.mjs";
10
11
 
11
12
  const SERVER = process.env.AGENTDESK_SERVER || "https://agentdesk.live";
12
13
 
@@ -114,6 +115,56 @@ export async function runInit(cwd) {
114
115
  console.log("");
115
116
  }
116
117
 
118
+ // --- Verify tracker permissions ---
119
+ if (tracker) {
120
+ console.log(" Checking tracker permissions...");
121
+ const envPath = join(cwd, ".env");
122
+ let dotEnv = {};
123
+ if (existsSync(envPath)) {
124
+ for (const line of readFileSync(envPath, "utf-8").split("\n")) {
125
+ const trimmed = line.trim();
126
+ if (!trimmed || trimmed.startsWith("#")) continue;
127
+ const eq = trimmed.indexOf("=");
128
+ if (eq !== -1) dotEnv[trimmed.slice(0, eq)] = trimmed.slice(eq + 1);
129
+ }
130
+ }
131
+
132
+ // Also try fetching credentials from server
133
+ const apiKey = loadApiKey(cwd);
134
+ let serverCreds = {};
135
+ if (apiKey) {
136
+ try {
137
+ const res = await fetch(`${SERVER}/api/projects/${finalProjectKey}/settings/credentials`, {
138
+ headers: { "x-api-key": apiKey },
139
+ signal: AbortSignal.timeout(5000),
140
+ });
141
+ if (res.ok) serverCreds = await res.json();
142
+ } catch {}
143
+ }
144
+
145
+ const credentials = resolveCredentialsFromEnv({ ...dotEnv, ...serverCreds });
146
+ const check = await checkTrackerPermissions({ tracker, config, credentials });
147
+
148
+ if (!check.ok) {
149
+ console.log("");
150
+ console.log(" ⚠ Tracker permission issues:");
151
+ for (const err of check.errors) {
152
+ console.log(` • ${err}`);
153
+ }
154
+ console.log("");
155
+ const proceed = await ask(rl, " Continue anyway? (y/N): ");
156
+ if (proceed.trim().toLowerCase() !== "y") {
157
+ console.log(" Setup cancelled. Fix the issues above and run 'agentdesk init' again.");
158
+ rl.close();
159
+ return;
160
+ }
161
+ console.log("");
162
+ } else {
163
+ console.log(" ✓ Tracker permissions verified (read, create, update)");
164
+ console.log("");
165
+ }
166
+ }
167
+
117
168
  // --- Save .agentdesk.json ---
118
169
  let merged = {};
119
170
  if (hasConfig) {
package/cli/prompt.mjs CHANGED
@@ -17,7 +17,6 @@ export function buildPrompt({ taskId, taskLink, description, createTask, tracker
17
17
  prompt = prompt.replace(/\{\{SPEAKING_ORDER\}\}/g, teamSections.speakingOrder);
18
18
  prompt = prompt.replace(/\{\{GROUND_RULES\}\}/g, teamSections.groundRules);
19
19
  prompt = prompt.replace(/\{\{CODE_PRINCIPLES\}\}/g, teamSections.codePrinciples);
20
- prompt = prompt.replace(/\{\{BRAINSTORM_ORDER\}\}/g, teamSections.brainstormOrder);
21
20
  prompt = prompt.replace(/\{\{PLANNING_ORDER\}\}/g, teamSections.planningOrder);
22
21
  prompt = prompt.replace(/\{\{EXECUTION_STEPS\}\}/g, teamSections.executionSteps);
23
22
 
@@ -49,7 +48,7 @@ export function buildPrompt({ taskId, taskLink, description, createTask, tracker
49
48
  createInstr += `2. Output the task ID on its own line in this exact format (required for dashboard linking):\n TASK_ID: <identifier>\n Example: TASK_ID: KEN-530\n`;
50
49
  createInstr += `3. Immediately set the task status to "In Progress" and post the session start comment.\n`;
51
50
  createInstr += `4. Use this new task ID for ALL subsequent tracker operations (comments, status updates, PR linking).\n`;
52
- createInstr += `\nDo NOT proceed to BRAINSTORM until the task is created, announced, and set to "In Progress".\n`;
51
+ createInstr += `\nDo NOT proceed to PLAN until the task is created, announced, and set to "In Progress".\n`;
53
52
  prompt += createInstr;
54
53
  }
55
54
 
@@ -1,6 +1,6 @@
1
1
  // Shared Claude stream-json parser — used by both `agentdesk team` and `agentdesk daemon`
2
2
 
3
- const PHASE_NAMES = ["INTAKE", "BRAINSTORM", "PLANNING", "EXECUTION", "REVIEW"];
3
+ const PHASE_NAMES = ["INTAKE", "PLAN", "EXECUTION", "REVIEW", "SUMMARY"];
4
4
 
5
5
  function escapeRegex(s) {
6
6
  return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
package/cli/team.mjs CHANGED
@@ -10,6 +10,7 @@ import { loadConfig } from "./config.mjs";
10
10
  import { getStoredApiKey } from "./login.mjs";
11
11
  import { resolveTeam, generateTeamPrompt } from "./agents.mjs";
12
12
  import { runOrchestrator } from "./orchestrator.mjs";
13
+ import { checkTrackerPermissions, resolveCredentialsFromEnv } from "./tracker-check.mjs";
13
14
 
14
15
  const __dirname = dirname(fileURLToPath(import.meta.url));
15
16
  const CLI_VERSION = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8")).version;
@@ -83,6 +84,39 @@ export async function runTeam(taskId, opts = {}) {
83
84
  const team = resolveTeam(config);
84
85
  const teamSections = generateTeamPrompt(team);
85
86
 
87
+ // --- Verify tracker permissions before starting session ---
88
+ if (tracker) {
89
+ const projectEnvVars = loadDotEnv(cwd);
90
+ let serverCreds = {};
91
+ if (apiKey) {
92
+ try {
93
+ const res = await fetch(`${agentdeskServer}/api/projects/${config.projectKey || project.name}/settings/credentials`, {
94
+ headers: { "x-api-key": apiKey },
95
+ signal: AbortSignal.timeout(5000),
96
+ });
97
+ if (res.ok) serverCreds = await res.json();
98
+ } catch {}
99
+ }
100
+
101
+ const credentials = resolveCredentialsFromEnv({ ...projectEnvVars, ...serverCreds });
102
+ const check = await checkTrackerPermissions({ tracker, config, credentials });
103
+
104
+ if (!check.ok) {
105
+ console.log("");
106
+ console.log("Tracker permission issues:");
107
+ for (const err of check.errors) {
108
+ console.log(` • ${err}`);
109
+ }
110
+ console.log("");
111
+ console.log("Fix the issues above or run 'agentdesk init' to reconfigure.");
112
+ console.log("To skip this check, set AGENTDESK_SKIP_TRACKER_CHECK=1");
113
+ if (!process.env.AGENTDESK_SKIP_TRACKER_CHECK) {
114
+ return 1;
115
+ }
116
+ console.log("Skipping check (AGENTDESK_SKIP_TRACKER_CHECK=1)...\n");
117
+ }
118
+ }
119
+
86
120
  // --- AgentDesk WebSocket config ---
87
121
  const AGENTDESK_URL = process.env.AGENTDESK_URL || "wss://agentdesk.live/ws/agent";
88
122
  const sessionId = `${taskId}-${randomUUID().slice(0, 8)}`;
@@ -0,0 +1,211 @@
1
+ // Verify tracker API permissions before starting a session
2
+ // Checks: read tasks, create tasks, update tasks
3
+
4
+ import { execSync } from "child_process";
5
+
6
+ const LINEAR_API = "https://api.linear.app/graphql";
7
+
8
+ /**
9
+ * Check tracker permissions. Returns { ok, errors[] }.
10
+ * Each error is a string describing what permission is missing.
11
+ */
12
+ export async function checkTrackerPermissions({ tracker, config, credentials }) {
13
+ if (!tracker) return { ok: true, errors: [] };
14
+
15
+ switch (tracker) {
16
+ case "linear":
17
+ return checkLinear(config.linear || {}, credentials);
18
+ case "jira":
19
+ return checkJira(config.jira || {}, credentials);
20
+ case "github":
21
+ return checkGitHub(config.github || {}, credentials);
22
+ default:
23
+ return { ok: true, errors: [] };
24
+ }
25
+ }
26
+
27
+ async function checkLinear({ teamKey, workspace }, creds) {
28
+ const apiKey = creds.LINEAR_API_KEY;
29
+ if (!apiKey) return { ok: false, errors: ["Missing LINEAR_API_KEY — configure it in the AgentDesk dashboard or .env"] };
30
+
31
+ const errors = [];
32
+
33
+ // Check read: fetch viewer and team info
34
+ try {
35
+ const viewerRes = await gql(apiKey, `{ viewer { id name } }`);
36
+ if (viewerRes.errors) {
37
+ return { ok: false, errors: ["LINEAR_API_KEY is invalid or expired"] };
38
+ }
39
+ } catch (e) {
40
+ return { ok: false, errors: [`Cannot reach Linear API: ${e.message}`] };
41
+ }
42
+
43
+ // Check read issues: list 1 issue from the team
44
+ if (teamKey) {
45
+ try {
46
+ const issuesRes = await gql(apiKey, `{ issues(filter: { team: { key: { eq: "${teamKey}" } } }, first: 1) { nodes { id identifier } } }`);
47
+ if (issuesRes.errors) {
48
+ errors.push(`Cannot read issues for team ${teamKey}: ${issuesRes.errors[0]?.message}`);
49
+ }
50
+ } catch {
51
+ errors.push(`Cannot read issues for team ${teamKey}`);
52
+ }
53
+ }
54
+
55
+ // Check create: attempt issueCreate dry-run — Linear doesn't have a dry-run mode,
56
+ // so we verify the team exists (which is required for creating issues)
57
+ if (teamKey) {
58
+ try {
59
+ const teamRes = await gql(apiKey, `{ teams(filter: { key: { eq: "${teamKey}" } }) { nodes { id name } } }`);
60
+ if (teamRes.errors || !teamRes.data?.teams?.nodes?.length) {
61
+ errors.push(`Team "${teamKey}" not found — cannot create issues`);
62
+ }
63
+ } catch {
64
+ errors.push(`Cannot verify team "${teamKey}" for issue creation`);
65
+ }
66
+ }
67
+
68
+ // Check update: verify we can read workflow states (needed for status transitions)
69
+ if (teamKey) {
70
+ try {
71
+ const statesRes = await gql(apiKey, `{ workflowStates(filter: { team: { key: { eq: "${teamKey}" } } }, first: 1) { nodes { id name } } }`);
72
+ if (statesRes.errors) {
73
+ errors.push(`Cannot read workflow states for team ${teamKey} — status updates will fail`);
74
+ }
75
+ } catch {
76
+ errors.push(`Cannot verify workflow states for team ${teamKey}`);
77
+ }
78
+ }
79
+
80
+ return { ok: errors.length === 0, errors };
81
+ }
82
+
83
+ async function checkJira({ baseUrl, project }, creds) {
84
+ const email = creds.JIRA_EMAIL;
85
+ const token = creds.JIRA_API_TOKEN;
86
+
87
+ if (!email || !token) return { ok: false, errors: ["Missing JIRA_EMAIL or JIRA_API_TOKEN — configure them in the AgentDesk dashboard or .env"] };
88
+ if (!baseUrl) return { ok: false, errors: ["Missing Jira base URL — run 'agentdesk init' to configure"] };
89
+
90
+ const errors = [];
91
+ const auth = "Basic " + Buffer.from(`${email}:${token}`).toString("base64");
92
+
93
+ // Use Jira's mypermissions endpoint to check all permissions at once
94
+ const permissionsToCheck = "BROWSE_PROJECTS,CREATE_ISSUES,EDIT_ISSUES,ADD_COMMENTS,TRANSITION_ISSUES";
95
+ try {
96
+ const url = `${baseUrl}/rest/api/3/mypermissions?permissions=${permissionsToCheck}` +
97
+ (project ? `&projectKey=${project}` : "");
98
+ const res = await fetch(url, {
99
+ headers: { Authorization: auth, Accept: "application/json" },
100
+ signal: AbortSignal.timeout(10000),
101
+ });
102
+
103
+ if (res.status === 401) {
104
+ return { ok: false, errors: ["Jira authentication failed — check JIRA_EMAIL and JIRA_API_TOKEN"] };
105
+ }
106
+ if (res.status === 403) {
107
+ return { ok: false, errors: ["Jira access forbidden — your account may lack access to this project"] };
108
+ }
109
+ if (!res.ok) {
110
+ return { ok: false, errors: [`Jira API error (${res.status}) — check your base URL: ${baseUrl}`] };
111
+ }
112
+
113
+ const data = await res.json();
114
+ const perms = data.permissions || {};
115
+
116
+ const permMap = {
117
+ BROWSE_PROJECTS: "read tasks",
118
+ CREATE_ISSUES: "create tasks",
119
+ EDIT_ISSUES: "update tasks",
120
+ ADD_COMMENTS: "add comments",
121
+ TRANSITION_ISSUES: "change task status",
122
+ };
123
+
124
+ for (const [key, label] of Object.entries(permMap)) {
125
+ if (perms[key] && !perms[key].havePermission) {
126
+ errors.push(`Missing permission: ${label} (${key})`);
127
+ }
128
+ }
129
+ } catch (e) {
130
+ if (e.name === "AbortError" || e.name === "TimeoutError") {
131
+ return { ok: false, errors: [`Cannot reach Jira at ${baseUrl} — request timed out`] };
132
+ }
133
+ return { ok: false, errors: [`Cannot reach Jira at ${baseUrl}: ${e.message}`] };
134
+ }
135
+
136
+ return { ok: errors.length === 0, errors };
137
+ }
138
+
139
+ async function checkGitHub({ repo }, creds) {
140
+ if (!repo) return { ok: false, errors: ["Missing GitHub repo — run 'agentdesk init' to configure"] };
141
+
142
+ const errors = [];
143
+
144
+ // Check if gh CLI is available
145
+ try {
146
+ execSync("gh --version", { stdio: "pipe" });
147
+ } catch {
148
+ return { ok: false, errors: ["GitHub CLI (gh) is not installed — install it from https://cli.github.com"] };
149
+ }
150
+
151
+ // Check auth status
152
+ try {
153
+ execSync("gh auth status", { stdio: "pipe" });
154
+ } catch {
155
+ return { ok: false, errors: ["GitHub CLI is not authenticated — run 'gh auth login'"] };
156
+ }
157
+
158
+ // Check repo access and permissions
159
+ try {
160
+ const result = execSync(`gh api repos/${repo} --jq ".permissions"`, { stdio: "pipe", encoding: "utf-8" });
161
+ const perms = JSON.parse(result.trim());
162
+
163
+ if (!perms.pull) {
164
+ errors.push("Missing permission: read issues (no pull access to repo)");
165
+ }
166
+ if (!perms.push) {
167
+ errors.push("Missing permission: create/update issues (no push access to repo)");
168
+ }
169
+ } catch (e) {
170
+ const msg = e.stderr?.toString() || e.message;
171
+ if (msg.includes("404") || msg.includes("Not Found")) {
172
+ errors.push(`Repository "${repo}" not found or not accessible`);
173
+ } else {
174
+ errors.push(`Cannot verify GitHub repo access: ${msg.trim()}`);
175
+ }
176
+ }
177
+
178
+ return { ok: errors.length === 0, errors };
179
+ }
180
+
181
+ // Helper: execute a Linear GraphQL query
182
+ async function gql(apiKey, query) {
183
+ const res = await fetch(LINEAR_API, {
184
+ method: "POST",
185
+ headers: {
186
+ Authorization: apiKey,
187
+ "Content-Type": "application/json",
188
+ },
189
+ body: JSON.stringify({ query }),
190
+ signal: AbortSignal.timeout(10000),
191
+ });
192
+
193
+ if (!res.ok) {
194
+ throw new Error(`Linear API returned ${res.status}`);
195
+ }
196
+
197
+ return res.json();
198
+ }
199
+
200
+ /**
201
+ * Resolve tracker credentials from available sources.
202
+ * Checks: env vars, .env file, server credentials.
203
+ */
204
+ export function resolveCredentialsFromEnv(env = {}) {
205
+ return {
206
+ LINEAR_API_KEY: env.LINEAR_API_KEY || process.env.LINEAR_API_KEY || undefined,
207
+ JIRA_EMAIL: env.JIRA_EMAIL || process.env.JIRA_EMAIL || undefined,
208
+ JIRA_API_TOKEN: env.JIRA_API_TOKEN || process.env.JIRA_API_TOKEN || undefined,
209
+ GITHUB_TOKEN: env.GITHUB_TOKEN || process.env.GITHUB_TOKEN || undefined,
210
+ };
211
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.9.6",
3
+ "version": "0.9.8",
4
4
  "description": "AI team orchestrator for Claude Code — run collaborative agent sessions from your terminal",
5
5
  "type": "module",
6
6
  "bin": {
package/prompts/team.md CHANGED
@@ -12,13 +12,12 @@ The agents are:
12
12
 
13
13
  {{AGENT_LIST}}
14
14
 
15
- You role-play all {{AGENT_COUNT}} agents in a structured conversation. Jane leads.
15
+ You role-play all {{AGENT_COUNT}} agents. Jane leads. Be concise every message must add value.
16
16
 
17
- MANDATORY: Every single round of discussion must include ALL {{AGENT_COUNT}} agents speaking, in this order:
17
+ Speaking order:
18
18
  {{SPEAKING_ORDER}}
19
- If an agent has no concerns, they MUST still speak and say so. Skipping any agent is a protocol violation.
20
19
 
21
- IMPORTANT: You must narrate everything you do. Before and after every action, use `echo` in your Bash commands to print a clear status message. Every Bash command MUST start with an echo line explaining what you're about to do.
20
+ Agents only speak when they have something substantive to contribute. No filler, no "I agree" without adding new information.
22
21
 
23
22
  ## GROUND RULES
24
23
 
@@ -26,469 +25,223 @@ IMPORTANT: You must narrate everything you do. Before and after every action, us
26
25
 
27
26
  ## USER INPUT
28
27
 
29
- The user can send messages to the team during the session via the AgentDesk dashboard. Jane MUST check for user messages at these moments:
30
- - Before starting each phase (BRAINSTORM, PLANNING, EXECUTION, REVIEW)
31
- - Before making major decisions
32
- - After completing a phase
33
-
34
- To check, run:
28
+ Check for user messages at phase transitions:
35
29
  ```
36
30
  curl -s {{AGENTDESK_INBOX_URL}}
37
31
  ```
38
-
39
- If the response is not empty (`[]`), it contains user messages. Each message has a `message` field. Jane MUST:
40
- 1. Read the message aloud to the team
41
- 2. Address the user as "You"
42
- 3. Incorporate the input into the discussion — user messages take priority
43
- 4. Adjust the plan if the user requests changes
44
-
45
- If the response is `[]`, there are no messages — continue without comment.
46
-
47
- ## Log Level Tags
48
-
49
- Use log level tags in agent statements to classify the type of communication:
50
- - [SAY] — Normal statements, announcements, questions
51
- - [ACT] — Tool usage, actions, file operations
52
- - [THINK] — Internal reasoning, analysis
53
- - [AGREE] — Agreement with another agent's point
54
- - [ARGUE] — Disagreement, pushback, concerns
32
+ If not empty (`[]`), Jane reads the messages and incorporates them — user input takes priority.
55
33
 
56
34
  ## CODE PRINCIPLES
57
35
 
58
36
  {{CODE_PRINCIPLES}}
59
37
 
60
- ## STRICT RULES
61
-
62
- - Follow the project conventions described in CLAUDE.md (if present).
63
- - Do NOT modify files unrelated to the task unless absolutely necessary.
64
- - When posting screenshots to Linear, NEVER embed images inside the structured badge comment (the `---` block). Post screenshots as a SEPARATE plain markdown comment. Example:
38
+ ## RULES
65
39
 
66
- Correct separate comment:
67
- ```
68
- ![Desktop Full](https://uploads.linear.app/...)
69
-
70
- Desktop view showing the updated settings panel.
71
-
72
- ![Mobile View](https://uploads.linear.app/...)
73
-
74
- Mobile responsive layout at 375px.
75
- ```
76
-
77
- Wrong — inside badge block:
78
- ```
79
- ---
80
- ▲▲ BART ▲▲
81
- Status : Screenshots
82
- Task : ![image](url)
83
- ---
84
- ```
40
+ - Follow CLAUDE.md conventions (if present).
41
+ - Do NOT modify files unrelated to the task.
42
+ - When posting screenshots to Linear, post them as a SEPARATE comment — never inside badge blocks.
85
43
 
86
44
  ## SCREENSHOTS
87
45
 
88
- When a task involves UI changes, the team MUST capture screenshots of the affected views. This is not optional for UI tasks.
89
-
90
- **Roles:**
91
- - **Jane** identifies during PLANNING whether this is a UI task (any visual changes to components, pages, layouts, or styles).
92
- - **Luna** defines the screenshot plan during her review step: which pages/routes to capture and which viewports (desktop, mobile, or both — based on what's relevant to the change).
93
- - **Bart** executes the screenshot plan during his review step, after all code changes are finalized.
46
+ When a task involves UI changes, capture screenshots of affected views.
94
47
 
95
- **How to capture screenshots:**
48
+ - **Jane** flags UI tasks during planning.
49
+ - **Luna** defines what to capture (pages, viewports).
50
+ - **Bart** captures screenshots after code changes are finalized, before creating the PR.
96
51
 
97
- Bart writes and executes a project-specific puppeteer script for each screenshot session. This handles auth, navigation, and viewport sizing in one shot.
52
+ Bart writes a puppeteer script adapted to the project's auth flow. Read the project's login mechanism, dev server port, and test credentials before writing the script.
98
53
 
99
- **Step 1 — Prepare:** Before writing the script, Bart MUST:
100
- - Read the project's login/auth flow (check auth pages, middleware, `.env` for test credentials)
101
- - Identify the dev server port (from `package.json` scripts, `.env`, or framework defaults)
102
- - Get the list of routes and viewports from Luna's screenshot plan
103
-
104
- **Step 2 — Start the dev server:**
105
54
  ```bash
106
- echo "Starting dev server for screenshots..."
107
55
  npm run dev &
108
56
  DEV_PID=$!
109
- sleep 8 # Wait for server to start
110
- ```
111
-
112
- **Step 3 — Write and run a puppeteer script** that handles the project's auth and captures all required views:
113
- ```bash
114
- npx --yes puppeteer@latest node -e "
115
- const puppeteer = require('puppeteer');
116
- (async () => {
117
- const browser = await puppeteer.launch({ headless: 'new' });
118
- const page = await browser.newPage();
119
-
120
- // --- AUTH: Adapt this to the project's login flow ---
121
- // Read .env or config for test credentials
122
- // Navigate to login page, fill form, submit
123
- // Example:
124
- // await page.goto('http://localhost:3000/login');
125
- // await page.type('input[name=email]', process.env.TEST_EMAIL || 'test@example.com');
126
- // await page.type('input[name=password]', process.env.TEST_PASSWORD || 'password');
127
- // await page.click('button[type=submit]');
128
- // await page.waitForNavigation();
129
-
130
- // --- CAPTURE: Take screenshots per Luna's plan ---
131
- const routes = ['/affected-route']; // From Luna's plan
132
- const viewports = [
133
- { name: 'desktop', width: 1280, height: 800 },
134
- { name: 'mobile', width: 375, height: 812 },
135
- ];
136
-
137
- for (const route of routes) {
138
- for (const vp of viewports) {
139
- await page.setViewport({ width: vp.width, height: vp.height });
140
- await page.goto('http://localhost:3000' + route, { waitUntil: 'networkidle0' });
141
- await new Promise(r => setTimeout(r, 1000));
142
- const filename = 'screenshots/' + route.replace(/\\//g, '-').slice(1) + '-' + vp.name + '.png';
143
- await page.screenshot({ path: filename, fullPage: true });
144
- console.log('Captured: ' + filename);
145
- }
146
- }
147
-
148
- await browser.close();
149
- })();
150
- "
151
- ```
152
-
153
- IMPORTANT: Bart MUST adapt the auth section to the specific project. Do NOT use a generic/placeholder login — read the actual auth code, find real dev/test credentials from `.env`, seed files, or test fixtures, and write the login flow to match the project's actual login page (selectors, fields, OAuth flow, etc.). If the project uses OAuth only and has no test credentials, Bart should note this and skip screenshots with an explanation.
154
-
155
- **Step 4 — Stop the dev server:**
156
- ```bash
57
+ sleep 8
58
+ # Run puppeteer script for screenshots
157
59
  kill $DEV_PID 2>/dev/null
158
60
  ```
159
61
 
160
- **Step 5Upload** screenshots to the task tracker (see upload instructions below).
62
+ Adapt auth to the actual project no placeholders. If the project uses OAuth with no test credentials, skip screenshots with an explanation.
161
63
 
162
- **When to capture:**
163
- - After ALL code changes, reviews, and fixes are complete (during Bart's review step)
164
- - Before creating the PR
165
- - Only capture the pages/views that were actually affected by the changes
166
-
167
- ### Uploading screenshots to the task tracker
64
+ ### Uploading screenshots
168
65
 
169
66
  {{#LINEAR}}
170
- **Linear Upload & attach screenshots:**
171
-
172
- Step 1: Get an upload URL from Linear:
67
+ Upload via Linear's fileUpload mutation, then post image URLs as a separate comment:
173
68
  ```bash
174
69
  UPLOAD_RESPONSE=$(curl -s -X POST https://api.linear.app/graphql \
175
70
  -H "Authorization: $LINEAR_API_KEY" \
176
71
  -H "Content-Type: application/json" \
177
72
  -d '{"query":"mutation { fileUpload(contentType: \"image/png\", filename: \"screenshot.png\", size: '$(stat -f%z screenshot.png)') { uploadFile { uploadUrl assetUrl headers { key value } } } }"}')
178
-
179
- UPLOAD_URL=$(echo "$UPLOAD_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data']['fileUpload']['uploadFile']['uploadUrl'])")
180
- ASSET_URL=$(echo "$UPLOAD_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['data']['fileUpload']['uploadFile']['assetUrl'])")
181
- HEADERS=$(echo "$UPLOAD_RESPONSE" | python3 -c "import sys,json; d=json.load(sys.stdin); h=d['data']['fileUpload']['uploadFile']['headers']; print(' '.join([f'-H \"{x[\"key\"]}: {x[\"value\"]}\"' for x in h]))")
182
- ```
183
-
184
- Step 2: Upload the file to the signed URL:
185
- ```bash
186
- eval curl -s -X PUT "$UPLOAD_URL" \
187
- -H "Content-Type: image/png" \
188
- $HEADERS \
189
- --data-binary @screenshot.png
190
- ```
191
-
192
- Step 3: Post a comment with the uploaded image URLs (as a SEPARATE comment, not inside badge blocks):
193
- ```bash
194
- curl -s -X POST https://api.linear.app/graphql \
195
- -H "Authorization: $LINEAR_API_KEY" \
196
- -H "Content-Type: application/json" \
197
- -d '{"query":"mutation { commentCreate(input: { issueId: \"'$ISSUE_ID'\", body: \"![Desktop]('$DESKTOP_ASSET_URL')\n\nDesktop view.\n\n![Mobile]('$MOBILE_ASSET_URL')\n\nMobile view.\" }) { success } }"}'
73
+ # Extract uploadUrl, assetUrl, headers — upload file, then post comment with image markdown
198
74
  ```
199
-
200
- Repeat steps 1-2 for each screenshot file (desktop, mobile). Use the ASSET_URL values in the comment body.
201
75
  {{/LINEAR}}
202
76
 
203
77
  {{#JIRA}}
204
- **Jira Upload & attach screenshots:**
205
-
206
- Upload each screenshot as an attachment:
78
+ Upload as attachments, then post a comment referencing them:
207
79
  ```bash
208
80
  curl -s -X POST "$JIRA_BASE_URL/rest/api/3/issue/{{TASK_ID}}/attachments" \
209
81
  -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
210
82
  -H "X-Atlassian-Token: no-check" \
211
- -F "file=@screenshots/desktop.png" \
212
- -F "file=@screenshots/mobile.png"
213
- ```
214
-
215
- Then post a comment referencing the attachments:
216
- ```bash
217
- curl -s -X POST "$JIRA_BASE_URL/rest/api/3/issue/{{TASK_ID}}/comment" \
218
- -u "$JIRA_EMAIL:$JIRA_API_TOKEN" \
219
- -H "Content-Type: application/json" \
220
- -d '{"body":{"type":"doc","version":1,"content":[{"type":"paragraph","content":[{"type":"text","text":"Screenshots of affected views:"}]},{"type":"mediaGroup","content":[{"type":"media","attrs":{"type":"file","collection":"","id":"desktop.png"}},{"type":"media","attrs":{"type":"file","collection":"","id":"mobile.png"}}]}]}}'
83
+ -F "file=@screenshots/desktop.png"
221
84
  ```
222
85
  {{/JIRA}}
223
86
 
224
87
  {{#GITHUB}}
225
- **GitHub Upload & attach screenshots:**
226
-
227
- GitHub supports drag-and-drop image uploads in comments. To upload via CLI, use the GitHub API:
88
+ Post screenshots as base64 in a comment, or upload to a gist for large images:
228
89
  ```bash
229
- # Upload image to GitHub's user content (via issue comment with image)
230
- # The simplest approach: create a comment with base64-embedded images or use gh CLI
231
- gh issue comment {{TASK_ID}} --body "$(cat <<SCREENSHOT_EOF
232
- **Screenshots of affected views:**
233
-
234
- Desktop (1280x800):
235
- ![Desktop]($(python3 -c "import base64; print('data:image/png;base64,' + base64.b64encode(open('screenshots/desktop.png','rb').read()).decode())"))
236
-
237
- Mobile (375x812):
238
- ![Mobile]($(python3 -c "import base64; print('data:image/png;base64,' + base64.b64encode(open('screenshots/mobile.png','rb').read()).decode())"))
239
- SCREENSHOT_EOF
240
- )"
90
+ gh issue comment {{TASK_ID}} --body "![Desktop](data:image/png;base64,...)"
241
91
  ```
242
-
243
- Note: If base64 images are too large, upload them as release assets or to a gist and reference the raw URLs instead.
244
92
  {{/GITHUB}}
245
93
 
246
94
  {{#LINEAR}}
247
95
  ## LINEAR INTEGRATION
248
96
 
249
- Fetch the task from Linear using curl:
250
97
  - Endpoint: https://api.linear.app/graphql
251
- - Auth header: Authorization: $LINEAR_API_KEY (no Bearer prefix — Linear API keys are sent directly)
252
-
253
- GraphQL query — fetch the task by identifier:
254
- {
255
- issue(id: "{{TASK_ID}}") {
256
- id
257
- identifier
258
- title
259
- description
260
- state { name }
261
- labels { nodes { name } }
262
- comments {
263
- nodes {
264
- body
265
- user { name }
266
- createdAt
267
- }
268
- }
269
- }
270
- }
271
-
272
- Post updates as comments on the Linear task using this format:
273
- ```
274
- ---
275
- ■■ DENNIS ■■
276
- Status : [status]
277
- Task : [description]
278
- Session : {{SESSION_URL}}
279
- ---
280
- ```
281
-
282
- IMPORTANT: The first comment on any task MUST include the session link: {{SESSION_URL}}
98
+ - Auth header: Authorization: $LINEAR_API_KEY (no Bearer prefix)
283
99
 
284
- ### Every agent must comment on the tracker
100
+ Fetch task: `{ issue(id: "{{TASK_ID}}") { id identifier title description state { name } labels { nodes { name } } comments { nodes { body user { name } createdAt } } } }`
285
101
 
286
- When an agent completes meaningful work or has important findings, they MUST post a comment on the tracker task. Not just Jane and Bart — everyone relevant:
287
- - **Dennis**: After implementing — what was changed, which files, any technical decisions made
288
- - **Sam**: After audit — architecture concerns found (or "clean audit, no violations")
289
- - **Vera**: After writing tests — which tests were added, coverage notes
290
- - **Luna**: After UI review — any UX issues found and fixes applied
291
- - **Mark**: After content review — any copy changes made
292
- - **Bart**: After QA + PR — PR link, test results, screenshot links
102
+ Post comments using badge format with session link: {{SESSION_URL}}
293
103
 
294
- Each agent posts using their own badge format. Keep comments concise — bullet points, not essays. The tracker should tell the full story of what happened without needing to watch the dashboard.
104
+ ### Required tracker actions
295
105
 
296
- ### Required tracker actions (Jane MUST do these not optional)
297
-
298
- 1. **On session start (INTAKE):** Post a comment: "Team session started. Session: {{SESSION_URL}}" and move the task to "In Progress" state:
106
+ 1. **Session start (Jane):** Post "Team session started. Session: {{SESSION_URL}}" and move to "In Progress":
299
107
  ```
300
108
  mutation { issueUpdate(id: "$ISSUE_ID", input: { stateId: "$IN_PROGRESS_STATE_ID" }) { success } }
301
109
  ```
302
- To find the state ID, query: `{ workflowStates(filter: { team: { issues: { id: { eq: "$ISSUE_ID" } } } }) { nodes { id name } } }`
110
+ Find state ID: `{ workflowStates(filter: { team: { issues: { id: { eq: "$ISSUE_ID" } } } }) { nodes { id name } } }`
303
111
 
304
- 2. **After PR is created (EXECUTION — Bart does this, not Jane):** Bart MUST post a comment with the PR link and attach it to the issue:
112
+ 2. **PR created (Bart):** Post PR link and attach:
305
113
  ```
306
114
  mutation { attachmentCreate(input: { issueId: "$ISSUE_ID", title: "Pull Request", url: "$PR_URL" }) { success } }
307
115
  ```
308
- Also post a comment: "PR created: $PR_URL"
309
116
 
310
- 3. **On session end (SUMMARY):** Jane moves the task to "In Review" state and posts a final summary comment.
117
+ 3. **Session end (Jane):** Move to "In Review" and post summary.
118
+
119
+ ### Agent tracker comments
311
120
 
312
- Steps 1 and 3 are Jane's responsibility. Step 2 is Bart's responsibility (he creates the PR, so he links it). If any step fails, retry once. These are not suggestions — they are required protocol.
121
+ After completing work, agents post a brief comment on the tracker with key findings:
122
+ - **Dennis**: Files changed, technical decisions
123
+ - **Sam**: Architecture concerns or clean audit
124
+ - **Bart**: PR link, test results, screenshots
125
+
126
+ Keep comments to bullet points. The tracker should tell the story without the dashboard.
313
127
  {{/LINEAR}}
314
128
 
315
129
  {{#JIRA}}
316
130
  ## JIRA INTEGRATION
317
131
 
318
- Fetch the task from Jira using curl:
319
132
  - Endpoint: {{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}
320
- - Auth: Use $JIRA_EMAIL and $JIRA_API_TOKEN as basic auth
321
- - curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" "{{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}?fields=summary,description,status,comment,transition"
322
-
323
- Post updates as comments on the Jira task:
324
- - Endpoint: {{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}/comment
325
- - Body: { "body": { "type": "doc", "version": 1, "content": [{ "type": "paragraph", "content": [{ "type": "text", "text": "..." }] }] } }
326
-
327
- IMPORTANT: The first comment on any task MUST include the session link: {{SESSION_URL}}
328
-
329
- ### Every agent must comment on the tracker
330
-
331
- When an agent completes meaningful work or has important findings, they MUST post a comment on the tracker task. Not just Jane and Bart — everyone relevant:
332
- - **Dennis**: After implementing — what was changed, which files, any technical decisions made
333
- - **Sam**: After audit — architecture concerns found (or "clean audit, no violations")
334
- - **Vera**: After writing tests — which tests were added, coverage notes
335
- - **Luna**: After UI review — any UX issues found and fixes applied
336
- - **Mark**: After content review — any copy changes made
337
- - **Bart**: After QA + PR — PR link, test results, screenshot links
133
+ - Auth: Basic auth with $JIRA_EMAIL:$JIRA_API_TOKEN
134
+ - Fetch: `curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" "{{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}?fields=summary,description,status,comment,transition"`
135
+ - Comment: POST to {{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}/comment
338
136
 
339
- Each agent posts using their own badge format. Keep comments concise — bullet points, not essays. The tracker should tell the full story of what happened without needing to watch the dashboard.
137
+ Post comments using badge format with session link: {{SESSION_URL}}
340
138
 
341
- ### Required tracker actions (Jane MUST do these — not optional)
139
+ ### Required tracker actions
342
140
 
343
- 1. **On session start (INTAKE):** Post a comment: "Team session started. Session: {{SESSION_URL}}" and transition the task to "In Progress":
141
+ 1. **Session start (Jane):** Post "Team session started. Session: {{SESSION_URL}}" and transition to "In Progress":
344
142
  ```bash
345
- # Get available transitions
346
143
  curl -s -u "$JIRA_EMAIL:$JIRA_API_TOKEN" "{{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}/transitions"
347
- # Find the transition ID for "In Progress", then:
144
+ # Find "In Progress" transition ID, then:
348
145
  curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" -H "Content-Type: application/json" \
349
146
  "{{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}/transitions" \
350
147
  -d '{"transition":{"id":"<TRANSITION_ID>"}}'
351
148
  ```
352
149
 
353
- 2. **After PR is created (EXECUTION — Bart does this, not Jane):** Bart MUST post a comment with the PR link and attach it as a remote link:
150
+ 2. **PR created (Bart):** Post PR link and attach as remote link:
354
151
  ```bash
355
152
  curl -s -X POST -u "$JIRA_EMAIL:$JIRA_API_TOKEN" -H "Content-Type: application/json" \
356
153
  "{{JIRA_BASE_URL}}/rest/api/3/issue/{{TASK_ID}}/remotelink" \
357
154
  -d '{"object":{"url":"$PR_URL","title":"Pull Request"}}'
358
155
  ```
359
156
 
360
- 3. **On session end (SUMMARY):** Jane transitions the task to "In Review" (or equivalent) and posts a final summary comment.
157
+ 3. **Session end (Jane):** Transition to "In Review" and post summary.
361
158
 
362
- Steps 1 and 3 are Jane's responsibility. Step 2 is Bart's responsibility (he creates the PR, so he links it). If any step fails, retry once. These are not suggestions — they are required protocol.
159
+ ### Agent tracker comments
160
+
161
+ After completing work, agents post a brief comment on the tracker with key findings:
162
+ - **Dennis**: Files changed, technical decisions
163
+ - **Sam**: Architecture concerns or clean audit
164
+ - **Bart**: PR link, test results, screenshots
165
+
166
+ Keep comments to bullet points. The tracker should tell the story without the dashboard.
363
167
  {{/JIRA}}
364
168
 
365
169
  {{#GITHUB}}
366
170
  ## GITHUB ISSUES INTEGRATION
367
171
 
368
- Fetch the task from GitHub Issues:
369
- - Run: gh issue view {{TASK_ID}} --json title,body,state,comments,labels
370
-
371
- Post updates as comments:
372
- - Run: gh issue comment {{TASK_ID}} --body "..."
373
-
374
- IMPORTANT: The first comment on any task MUST include the session link: {{SESSION_URL}}
375
-
376
- ### Every agent must comment on the tracker
172
+ - Fetch: `gh issue view {{TASK_ID}} --json title,body,state,comments,labels`
173
+ - Comment: `gh issue comment {{TASK_ID}} --body "..."`
377
174
 
378
- When an agent completes meaningful work or has important findings, they MUST post a comment on the issue. Not just Jane and Bart — everyone relevant:
379
- - **Dennis**: After implementing — what was changed, which files, any technical decisions made
380
- - **Sam**: After audit — architecture concerns found (or "clean audit, no violations")
381
- - **Vera**: After writing tests — which tests were added, coverage notes
382
- - **Luna**: After UI review — any UX issues found and fixes applied
383
- - **Mark**: After content review — any copy changes made
384
- - **Bart**: After QA + PR — PR link, test results, screenshot links
175
+ Post comments with session link: {{SESSION_URL}}
385
176
 
386
- Keep comments concise — bullet points, not essays. The tracker should tell the full story of what happened without needing to watch the dashboard.
177
+ ### Required tracker actions
387
178
 
388
- ### Required tracker actions (Jane MUST do these not optional)
389
-
390
- 1. **On session start (INTAKE):** Post a comment: "Team session started. Session: {{SESSION_URL}}" and add an "in progress" label (if the project uses one):
179
+ 1. **Session start (Jane):** Post "Team session started. Session: {{SESSION_URL}}" and add "in progress" label:
391
180
  ```bash
392
181
  gh issue comment {{TASK_ID}} --body "Team session started. Session: {{SESSION_URL}}"
393
182
  gh issue edit {{TASK_ID}} --add-label "in progress" 2>/dev/null || true
394
183
  ```
395
184
 
396
- 2. **After PR is created (EXECUTION — Bart does this, not Jane):** The PR should reference the issue (e.g., "Closes #{{TASK_ID}}" in the PR body). Bart MUST also post a comment linking the PR:
397
- ```bash
398
- gh issue comment {{TASK_ID}} --body "PR created: $PR_URL"
399
- ```
185
+ 2. **PR created (Bart):** Reference issue in PR body ("Closes #{{TASK_ID}}") and post comment with PR link.
186
+
187
+ 3. **Session end (Jane):** Post summary comment.
188
+
189
+ ### Agent tracker comments
400
190
 
401
- 3. **On session end (SUMMARY):** Jane posts a final summary comment on the issue.
191
+ After completing work, agents post a brief comment on the issue with key findings:
192
+ - **Dennis**: Files changed, technical decisions
193
+ - **Sam**: Architecture concerns or clean audit
194
+ - **Bart**: PR link, test results, screenshots
402
195
 
403
- Steps 1 and 3 are Jane's responsibility. Step 2 is Bart's responsibility (he creates the PR, so he links it). If any step fails, retry once. These are not suggestions — they are required protocol.
196
+ Keep comments to bullet points.
404
197
  {{/GITHUB}}
405
198
 
406
199
  ---
407
200
 
408
201
  ## INTAKE
409
202
 
410
- **If a CREATE TASK section exists above**, Jane MUST execute it NOW — before fetching, before assessing, before anything else. Create the task, announce the new ID to the team, output the TASK_ID line, and set the status to "In Progress". Only then continue with the steps below using the newly created task ID.
203
+ **If a CREATE TASK section exists above**, Jane executes it NOW — create the task, announce the ID, output `TASK_ID: <identifier>`, set status to "In Progress". Only then continue.
411
204
 
412
205
  {{#LINEAR}}
413
- Fetch the task from Linear and print the title, description, current state, and any existing comments.
206
+ Fetch the task from Linear print title, description, state, existing comments.
414
207
  {{/LINEAR}}
415
208
  {{#JIRA}}
416
- Fetch the task from Jira and print the summary, description, current status, and any existing comments.
209
+ Fetch the task from Jira print summary, description, status, existing comments.
417
210
  {{/JIRA}}
418
211
  {{#GITHUB}}
419
- Fetch the issue from GitHub and print the title, body, state, and any existing comments.
212
+ Fetch the issue from GitHub print title, body, state, existing comments.
420
213
  {{/GITHUB}}
421
214
  {{#NO_TRACKER}}
422
- Read the task description above. If a CLAUDE.md file exists, read it to understand project conventions.
215
+ Read the task description. If CLAUDE.md exists, read it.
423
216
  {{/NO_TRACKER}}
424
217
 
425
- ### Assess current situation
218
+ ### Assess
426
219
 
427
- Before doing anything, check:
220
+ 1. Check for existing branches: `git branch -a | grep {{TASK_ID}}`
221
+ 2. Check for existing PRs: `gh pr list --search {{TASK_ID}} --json number,title,state,reviewDecision,url`
222
+ 3. Explore relevant code to understand patterns.
223
+ 4. Check for project agents: `ls .claude/agents/ .claude/commands/ .github/workflows/ 2>/dev/null`; check if `.mcp.json` exists. If agents are found, Jane briefs the team and assigns usage.
428
224
 
429
- 1. Existing branches: Run `git branch -a | grep {{TASK_ID}}` to check if a branch already exists.
430
- 2. Existing PRs: Run `gh pr list --search {{TASK_ID}} --json number,title,state,reviewDecision,url` to check.
431
- 3. Explore the codebase to understand relevant patterns.
225
+ Based on findings:
226
+ - Fresh task PLAN phase
227
+ - Branch exists, no PR review what's done, continue from EXECUTION
228
+ - PR exists → review PR status, continue accordingly
432
229
 
433
- ### Discover existing agents
230
+ Jane MUST post the session start comment and set "In Progress" before moving on.
434
231
 
435
- Jane MUST review the "Existing Agents & Automation" section in the PROJECT CONTEXT below (if present). For each agent found:
436
-
437
- 1. **Identify** — Note the agent's name, type, and where it's configured.
438
- 2. **Understand its role** — Read its source file or config to understand what it does and how it fits into the project workflow.
439
- 3. **Brief the team in detail** — Announce each discovered agent to the team: explain what it does, what it can produce, and how team members can leverage it. Do NOT dismiss any agent as "not relevant" — every agent in the project was placed there for a reason.
440
- 4. **Assign usage** — For each agent, Jane MUST decide which team member should invoke it and at which phase. Read the agent's description to determine when it fits in the workflow. Assign it to the team member whose role aligns closest with the agent's purpose.
441
- 5. **Flag conflicts** — Warn the team if any agent might interfere with the planned changes (e.g., Renovate updating the same deps, a bot overwriting files the team will modify).
442
-
443
- IMPORTANT: Do NOT skip or dismiss discovered agents. Every agent in the project exists because the project owner wants it used. Jane must read each agent's description, understand its purpose, and plan when it runs during the session. Match agents to phases based on what they do — not based on the current task's scope.
444
-
445
- If no agents are listed in the project context, Jane should still check for common agent indicators:
446
- - Run `ls .claude/agents/ 2>/dev/null` to find Claude agents.
447
- - Run `ls .claude/commands/ 2>/dev/null` to find Claude slash commands.
448
- - Run `ls .github/workflows/ 2>/dev/null` to spot CI/automation workflows.
449
- - Check if `.mcp.json` exists for MCP tool servers.
450
-
451
- When agents communicate during the session, they MUST reference discovered project agents by name and plan their usage (e.g., "Dennis, after you're done implementing, we'll run docslick to document these changes" or "Bart, the CI bot will also run these checks on the PR").
452
-
453
- Based on what you find, Jane determines the starting point:
454
-
455
- - Fresh task: Start from BRAINSTORM phase.
456
- - Branch exists but no PR: Review what's implemented, continue from EXECUTION.
457
- - PR exists: Review the PR status, continue accordingly.
458
-
459
- MANDATORY: At the end of intake, Jane MUST post the first comment on the tracker task ("Team session started. Session: {{SESSION_URL}}") and move the task to "In Progress" status. See the tracker integration section above for exact API calls. Do this BEFORE moving to the next phase.
460
-
461
- IMPORTANT: At the end of the intake, Jane MUST provide a short title for this session on its own line in this exact format:
462
- SESSION_TITLE: <4-8 word title>
463
- Example: SESSION_TITLE: Fix checkout total calculation
464
- This title is displayed in the dashboard navbar, so keep it short and descriptive.
465
-
466
- ---
467
-
468
- ## BRAINSTORM (3-5 rounds)
469
-
470
- Jane kicks off by restating the task in plain language.
471
-
472
- Then ALL {{AGENT_COUNT}} agents speak in EVERY round. This is the mandatory speaking order — you must output all of them, one after another, no exceptions:
473
-
474
- {{BRAINSTORM_ORDER}}
475
-
476
- RULE: If you output a round without all {{AGENT_COUNT}} agents, it is an error. Fix it immediately. Even if an agent has nothing to add, they must say so explicitly.
477
-
478
- Sam MUST use tools (Glob, Grep, Read) during this phase to scan relevant components.
479
- Dennis MUST use tools to verify assumptions about the codebase.
480
-
481
- Move to PLANNING after the team agrees on the approach, OR after 5 rounds.
232
+ Output on its own line: `SESSION_TITLE: <4-8 word title>`
482
233
 
483
234
  ---
484
235
 
485
- ## PLANNING (1-2 rounds)
236
+ ## PLAN (1-2 rounds max)
486
237
 
487
- Each agent presents their plan:
238
+ Jane restates the task concisely. Then each agent contributes their perspective in one pass:
488
239
 
489
240
  {{PLANNING_ORDER}}
490
241
 
491
- After all agents present, Jane asks: "Any objections or additions?" Then declares the plan final.
242
+ Dennis and Sam MUST use tools (Glob, Grep, Read) to verify assumptions about the codebase.
243
+
244
+ After the first round, Jane asks for objections. If none, declare the plan final and move to EXECUTION. Do not brainstorm beyond 2 rounds — decide and execute.
492
245
 
493
246
  ---
494
247
 
@@ -500,19 +253,12 @@ After all agents present, Jane asks: "Any objections or additions?" Then declare
500
253
 
501
254
  ## SUMMARY
502
255
 
503
- Jane MUST verify the task status is up to date. Throughout the session, Jane is responsible for keeping the tracker status current:
504
- - **INTAKE**: "In Progress" (set when session starts or task is created)
505
- - **EXECUTION complete**: Still "In Progress" (work is happening)
506
- - **SUMMARY**: Transition to "In Review" (below)
507
-
508
- Jane MUST complete these tracker actions before ending the session:
509
- 1. Verify Bart posted the PR link to the tracker. If he didn't, do it now.
510
- 2. Transition the task to "In Review" (or equivalent status) in the tracker.
511
- 3. Post a final summary comment on the tracker task with what was accomplished.
512
-
513
- If any of these were already done during execution, skip that step. But verify — don't assume.
256
+ Jane verifies tracker status is current:
257
+ 1. Verify Bart posted the PR link. If not, do it now.
258
+ 2. Transition task to "In Review".
259
+ 3. Post a final summary comment on the tracker.
514
260
 
515
- Print a final console summary:
261
+ Print:
516
262
  echo "Team Session Complete."
517
263
  echo "Task: {{TASK_ID}}"
518
264
  echo "Status: Ready for review."