@kendoo.agentdesk/agentdesk 0.13.1 → 0.14.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.
package/README.md CHANGED
@@ -141,6 +141,36 @@ Add project-specific rules that all agents follow. Set via Web UI or in `.agentd
141
141
 
142
142
  Instructions are injected into the team prompt. Use them for project conventions that go beyond what `CLAUDE.md` covers (e.g., tracker workflow rules, PR policies, agent coordination preferences).
143
143
 
144
+ ### Screenshots
145
+
146
+ Screenshots are captured by default for UI-related tasks. Bart captures desktop and mobile screenshots before creating the PR and attaches them to the task tracker.
147
+
148
+ To disable, set `screenshots` to `false` in `.agentdesk.json` or toggle it off in project settings:
149
+
150
+ ```json
151
+ {
152
+ "screenshots": false
153
+ }
154
+ ```
155
+
156
+ You can also toggle screenshots per session when starting a task from the Web UI.
157
+
158
+ ### Model per phase
159
+
160
+ In phased mode (`INTAKE → PLAN → EXECUTION`), you can pick a different Claude model per phase from project settings. Useful when you want a stronger model for planning and implementation but a cheaper one for intake.
161
+
162
+ ```json
163
+ {
164
+ "phaseModels": {
165
+ "INTAKE": "sonnet",
166
+ "PLAN": "opus",
167
+ "EXECUTION": "opus"
168
+ }
169
+ }
170
+ ```
171
+
172
+ Valid values: `"default"` (Claude Code's default), `"opus"`, `"sonnet"`, `"haiku"`. Non-phased runs use the `EXECUTION` model.
173
+
144
174
  ## How It Works
145
175
 
146
176
  All agents collaborate in a single Claude process — each with distinct roles, ground rules, and areas of expertise.
package/cli/config.mjs CHANGED
@@ -39,6 +39,15 @@ const DEFAULTS = {
39
39
  // Each entry: { name, role, when, how }
40
40
  projectAgents: [],
41
41
 
42
+ // Capture screenshots for UI tasks (default: on)
43
+ screenshots: true,
44
+
45
+ // Model per phase — override Claude Code's default per phase.
46
+ // Keys: INTAKE, PLAN, EXECUTION. Values: "default" | "opus" | "sonnet" | "haiku".
47
+ // Missing entry or "default" = use Claude Code's default model.
48
+ // Example: { "PLAN": "opus", "EXECUTION": "opus" }
49
+ phaseModels: {},
50
+
42
51
  // Extra prompt instructions appended to the team prompt
43
52
  instructions: null,
44
53
  };
package/cli/daemon.mjs CHANGED
@@ -313,7 +313,7 @@ export async function runDaemon() {
313
313
 
314
314
  // 4. Session handling
315
315
 
316
- async function handleStartSession({ sessionId, projectId, taskId: remoteTaskId, prompt, phased }) {
316
+ async function handleStartSession({ sessionId, projectId, taskId: remoteTaskId, prompt, phased, screenshots: screenshotsOverride }) {
317
317
  // Validate project against local allowlist
318
318
  const project = projects.find(p => p.id === projectId);
319
319
  if (!project) {
@@ -343,6 +343,7 @@ export async function runDaemon() {
343
343
  const projectEnv = loadDotEnv(project.path);
344
344
  const projectApiKey = projectEnv.AGENTDESK_API_KEY || process.env.AGENTDESK_API_KEY || apiKey;
345
345
  const config = await loadConfig(project.path, { apiKey: projectApiKey, serverUrl: agentdeskServer, projectName: project.name });
346
+ if (screenshotsOverride !== undefined) config.screenshots = screenshotsOverride;
346
347
  const tracker = config.tracker || null;
347
348
 
348
349
  // Use provided task ID or generate from description
@@ -44,6 +44,16 @@ function timestamp() {
44
44
  .map(n => String(n).padStart(2, "0")).join(":");
45
45
  }
46
46
 
47
+ // Resolve --model args for a given phase based on project settings.
48
+ // phaseModels is { INTAKE?, PLAN?, EXECUTION? } with values "opus"|"sonnet"|"haiku"|"default".
49
+ // Returns [] when no override (so Claude Code picks its default).
50
+ function modelArgsForPhase(phase, phaseModels) {
51
+ const choice = phaseModels?.[phase];
52
+ if (!choice || choice === "default") return [];
53
+ // Claude Code accepts short aliases: opus, sonnet, haiku
54
+ return ["--model", choice];
55
+ }
56
+
47
57
  export async function runOrchestrator({
48
58
  taskId, taskLink, description, createTask, tracker, config,
49
59
  project, team, teamSections, sessionUrl, cwd,
@@ -79,9 +89,12 @@ export async function runOrchestrator({
79
89
 
80
90
  emit({ type: "phase:change", phase: soloAgent ? "EXECUTION" : "INTAKE" });
81
91
 
92
+ // Non-phased single run spans all phases in one process — use EXECUTION's model
93
+ // as the representative choice (matches where the heavy lifting happens).
94
+ const modelArgs = modelArgsForPhase("EXECUTION", config?.phaseModels);
82
95
  const child = spawn(
83
96
  "claude",
84
- ["-p", fullPrompt, "--allowedTools", "Bash,Read,Edit,Write,Glob,Grep", "--verbose", "--output-format", "stream-json"],
97
+ ["-p", fullPrompt, ...modelArgs, "--allowedTools", "Bash,Read,Edit,Write,Glob,Grep", "--verbose", "--output-format", "stream-json"],
85
98
  { stdio: ["pipe", "pipe", "inherit"], shell: false, env, cwd }
86
99
  );
87
100
  child.stdin.end();
@@ -174,10 +187,10 @@ export async function runOrchestrator({
174
187
 
175
188
  // --- Phased orchestrator: runs 3 sequential Claude processes ---
176
189
 
177
- async function runSinglePhase({ prompt, cwd, env, teamNames, emit }) {
190
+ async function runSinglePhase({ prompt, cwd, env, teamNames, emit, modelArgs = [] }) {
178
191
  const child = spawn(
179
192
  "claude",
180
- ["-p", prompt, "--allowedTools", "Bash,Read,Edit,Write,Glob,Grep", "--verbose", "--output-format", "stream-json"],
193
+ ["-p", prompt, ...modelArgs, "--allowedTools", "Bash,Read,Edit,Write,Glob,Grep", "--verbose", "--output-format", "stream-json"],
181
194
  { stdio: ["pipe", "pipe", "inherit"], shell: false, env, cwd }
182
195
  );
183
196
  child.stdin.end();
@@ -260,7 +273,8 @@ export async function runPhasedOrchestrator({
260
273
  tracker, config, project, teamSections, sessionUrl, cwd, sessionMemory,
261
274
  });
262
275
 
263
- const result = await runSinglePhase({ prompt, cwd, env, teamNames, emit });
276
+ const modelArgs = modelArgsForPhase(phase, config?.phaseModels);
277
+ const result = await runSinglePhase({ prompt, cwd, env, teamNames, emit, modelArgs });
264
278
 
265
279
  // Allow daemon to track the child process for cancellation
266
280
  if (onChild) onChild(result.child);
package/cli/prompt.mjs CHANGED
@@ -77,6 +77,16 @@ export function buildPrompt({ taskId, taskLink, description, createTask, tracker
77
77
  prompt += createInstr;
78
78
  }
79
79
 
80
+ // Screenshots toggle — default on if not explicitly set to false
81
+ const screenshotsEnabled = config.screenshots !== false;
82
+ if (screenshotsEnabled) {
83
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_ENABLED\}\}([\s\S]*?)\{\{\/SCREENSHOTS_ENABLED\}\}/g, "$1");
84
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_DISABLED\}\}[\s\S]*?\{\{\/SCREENSHOTS_DISABLED\}\}/g, "");
85
+ } else {
86
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_ENABLED\}\}[\s\S]*?\{\{\/SCREENSHOTS_ENABLED\}\}/g, "");
87
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_DISABLED\}\}([\s\S]*?)\{\{\/SCREENSHOTS_DISABLED\}\}/g, "$1");
88
+ }
89
+
80
90
  // Tracker integration — enable the matching section, strip the rest
81
91
  const trackers = ["LINEAR", "JIRA", "GITHUB"];
82
92
  for (const t of trackers) {
@@ -395,6 +405,16 @@ export function buildPhasedPrompt({ phase, taskId, taskLink, description, create
395
405
  prompt = prompt.replace(/\{\{#TASK_DESCRIPTION\}\}[\s\S]*?\{\{\/TASK_DESCRIPTION\}\}/g, "");
396
406
  }
397
407
 
408
+ // Screenshots toggle
409
+ const phasedScreenshots = config.screenshots !== false;
410
+ if (phasedScreenshots) {
411
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_ENABLED\}\}([\s\S]*?)\{\{\/SCREENSHOTS_ENABLED\}\}/g, "$1");
412
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_DISABLED\}\}[\s\S]*?\{\{\/SCREENSHOTS_DISABLED\}\}/g, "");
413
+ } else {
414
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_ENABLED\}\}[\s\S]*?\{\{\/SCREENSHOTS_ENABLED\}\}/g, "");
415
+ prompt = prompt.replace(/\{\{#SCREENSHOTS_DISABLED\}\}([\s\S]*?)\{\{\/SCREENSHOTS_DISABLED\}\}/g, "$1");
416
+ }
417
+
398
418
  // Tracker integration
399
419
  const trackers = ["LINEAR", "JIRA", "GITHUB"];
400
420
  for (const t of trackers) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kendoo.agentdesk/agentdesk",
3
- "version": "0.13.1",
3
+ "version": "0.14.0",
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/phased.md CHANGED
@@ -274,9 +274,16 @@ Speaking order:
274
274
  - Do NOT modify files unrelated to the task.
275
275
  - When posting screenshots to Linear, post them as a SEPARATE comment.
276
276
 
277
+ {{#SCREENSHOTS_ENABLED}}
277
278
  ## SCREENSHOTS
278
279
 
279
- When a task involves UI changes, Bart captures screenshots after code changes are finalized, before creating the PR. Adapt auth to the actual project.
280
+ Screenshots are **enabled** for this project. When a task involves UI changes, Bart MUST capture screenshots after code changes are finalized, before creating the PR. Adapt auth to the actual project.
281
+ {{/SCREENSHOTS_ENABLED}}
282
+ {{#SCREENSHOTS_DISABLED}}
283
+ ## SCREENSHOTS
284
+
285
+ Screenshots are **disabled** for this project. Do NOT capture screenshots unless the user explicitly requests them.
286
+ {{/SCREENSHOTS_DISABLED}}
280
287
 
281
288
  {{#LINEAR}}
282
289
  Upload via Linear's fileUpload mutation, then post image URLs as a separate comment.
package/prompts/team.md CHANGED
@@ -56,9 +56,10 @@ This is a hard constraint that MUST NOT be violated under any circumstances:
56
56
  - Do NOT modify files unrelated to the task.
57
57
  - When posting screenshots to Linear, post them as a SEPARATE comment — never inside badge blocks.
58
58
 
59
+ {{#SCREENSHOTS_ENABLED}}
59
60
  ## SCREENSHOTS
60
61
 
61
- When a task involves UI changes, capture screenshots of affected views.
62
+ Screenshots are **enabled** for this project. When a task involves UI changes, Bart MUST capture screenshots this is not optional.
62
63
 
63
64
  - **Jane** flags UI tasks during planning.
64
65
  - **Luna** defines what to capture (pages, viewports).
@@ -75,6 +76,12 @@ kill $DEV_PID 2>/dev/null
75
76
  ```
76
77
 
77
78
  Adapt auth to the actual project — no placeholders. If the project uses OAuth with no test credentials, skip screenshots with an explanation.
79
+ {{/SCREENSHOTS_ENABLED}}
80
+ {{#SCREENSHOTS_DISABLED}}
81
+ ## SCREENSHOTS
82
+
83
+ Screenshots are **disabled** for this project. Do NOT capture screenshots unless the user explicitly requests them in the task description.
84
+ {{/SCREENSHOTS_DISABLED}}
78
85
 
79
86
  ### Uploading screenshots
80
87