sparkecoder 0.1.124 → 0.1.126

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 (108) hide show
  1. package/dist/agent/index.js +145 -71
  2. package/dist/agent/index.js.map +1 -1
  3. package/dist/cli.js +188 -89
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +188 -89
  6. package/dist/index.js.map +1 -1
  7. package/dist/server/index.js +188 -89
  8. package/dist/server/index.js.map +1 -1
  9. package/dist/skills/default/memory.md +49 -0
  10. package/dist/skills/default/skill-authoring.md +96 -0
  11. package/dist/tools/index.js +12 -4
  12. package/dist/tools/index.js.map +1 -1
  13. package/package.json +1 -1
  14. package/src/skills/default/memory.md +49 -0
  15. package/src/skills/default/skill-authoring.md +96 -0
  16. package/web/.next/BUILD_ID +1 -1
  17. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  18. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  19. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  20. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  21. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  36. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  72. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  86. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  88. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  95. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  96. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  97. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  98. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  99. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  100. /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
  101. /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
  102. /package/web/.next/standalone/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
  103. /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
  104. /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
  105. /package/web/.next/standalone/web/.next/static/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
  106. /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_buildManifest.js +0 -0
  107. /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_clientMiddlewareManifest.json +0 -0
  108. /package/web/.next/static/{cYXZ7UzGc5TttFIXRRcSC → BSOUN7vf8epF685UYalET}/_ssgManifest.js +0 -0
@@ -32,7 +32,10 @@ var init_types = __esm({
32
32
  // not listed here. Values match `process.platform`
33
33
  // (darwin, linux, win32, freebsd, ...). If omitted or empty, the skill is
34
34
  // available on all platforms.
35
- platforms: z.array(z.string()).optional().default([])
35
+ platforms: z.array(z.string()).optional().default([]),
36
+ // Optional approximate token budget for always-loaded content. If set,
37
+ // the prompt builder truncates this skill/rule before injecting it.
38
+ contextBudgetTokens: z.number().int().positive().optional()
36
39
  });
37
40
  TaskConfigSchema = z.object({
38
41
  enabled: z.boolean(),
@@ -958,6 +961,8 @@ function parseSkillFrontmatter(content) {
958
961
  data[key2] = true;
959
962
  } else if (value === "false") {
960
963
  data[key2] = false;
964
+ } else if (/^\d+$/.test(value)) {
965
+ data[key2] = Number(value);
961
966
  } else {
962
967
  data[key2] = value;
963
968
  }
@@ -1017,7 +1022,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
1017
1022
  loadType,
1018
1023
  priority,
1019
1024
  sourceDir: directory,
1020
- platforms: parsed.metadata.platforms
1025
+ platforms: parsed.metadata.platforms,
1026
+ contextBudgetTokens: parsed.metadata.contextBudgetTokens
1021
1027
  });
1022
1028
  } else {
1023
1029
  const name = getSkillNameFromPath(filePath);
@@ -1031,7 +1037,8 @@ async function loadSkillsFromDirectory(directory, options = {}) {
1031
1037
  loadType: forceAlwaysApply ? "always" : defaultLoadType,
1032
1038
  priority,
1033
1039
  sourceDir: directory,
1034
- platforms: []
1040
+ platforms: [],
1041
+ contextBudgetTokens: void 0
1035
1042
  });
1036
1043
  }
1037
1044
  }
@@ -1161,11 +1168,12 @@ function formatSkillsForContext(skills) {
1161
1168
  if (onDemandSkills.length === 0) {
1162
1169
  return "No on-demand skills available.";
1163
1170
  }
1164
- const lines = ["Available skills (use load_skill tool to load into context):"];
1171
+ const lines = ["<available_skills>", "Use the load_skill tool to load one of these into context:"];
1165
1172
  for (const skill of onDemandSkills) {
1166
1173
  const globInfo = skill.globs?.length ? ` [auto-loads for: ${skill.globs.join(", ")}]` : "";
1167
1174
  lines.push(`- ${skill.name}: ${skill.description}${globInfo}`);
1168
1175
  }
1176
+ lines.push("</available_skills>");
1169
1177
  return lines.join("\n");
1170
1178
  }
1171
1179
  function formatAlwaysLoadedSkills(skills) {
@@ -1174,13 +1182,22 @@ function formatAlwaysLoadedSkills(skills) {
1174
1182
  }
1175
1183
  const sections = [];
1176
1184
  for (const skill of skills) {
1177
- sections.push(`### ${skill.name}
1178
-
1179
- ${skill.content}`);
1185
+ sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
1186
+ ${truncateSkillContent(skill)}
1187
+ </skill>`);
1180
1188
  }
1181
- return `## Active Rules & Skills (Always Loaded)
1189
+ return `<always_loaded_rules_and_skills>
1190
+ ${sections.join("\n\n")}
1191
+ </always_loaded_rules_and_skills>`;
1192
+ }
1193
+ function truncateSkillContent(skill) {
1194
+ if (!skill.contextBudgetTokens) return skill.content;
1195
+ const maxChars = Math.max(200, skill.contextBudgetTokens * 4);
1196
+ if (skill.content.length <= maxChars) return skill.content;
1197
+ const omitted = skill.content.length - maxChars;
1198
+ return `${skill.content.slice(0, maxChars).trimEnd()}
1182
1199
 
1183
- ${sections.join("\n\n---\n\n")}`;
1200
+ ... [${skill.name} truncated by contextBudgetTokens=${skill.contextBudgetTokens}; ${omitted} chars omitted. Read ${skill.filePath} for the full file.]`;
1184
1201
  }
1185
1202
  function formatGlobMatchedSkills(skills) {
1186
1203
  if (skills.length === 0) {
@@ -1188,21 +1205,24 @@ function formatGlobMatchedSkills(skills) {
1188
1205
  }
1189
1206
  const sections = [];
1190
1207
  for (const skill of skills) {
1191
- sections.push(`### ${skill.name}
1192
-
1193
- ${skill.content}`);
1208
+ sections.push(`<skill name="${escapeXmlAttribute(skill.name)}">
1209
+ ${skill.content}
1210
+ </skill>`);
1194
1211
  }
1195
- return `## Context-Relevant Skills (Auto-loaded based on active files)
1196
-
1197
- ${sections.join("\n\n---\n\n")}`;
1212
+ return `<glob_matched_skills>
1213
+ ${sections.join("\n\n")}
1214
+ </glob_matched_skills>`;
1198
1215
  }
1199
1216
  function formatAgentsMdContent(content) {
1200
1217
  if (!content) {
1201
1218
  return "";
1202
1219
  }
1203
- return `## Project Instructions (AGENTS.md)
1204
-
1205
- ${content}`;
1220
+ return `<project_instructions source="AGENTS.md">
1221
+ ${content}
1222
+ </project_instructions>`;
1223
+ }
1224
+ function escapeXmlAttribute(value) {
1225
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
1206
1226
  }
1207
1227
  var init_skills = __esm({
1208
1228
  "src/skills/index.ts"() {
@@ -6021,14 +6041,18 @@ async function buildSystemPrompt(options) {
6021
6041
  const platform2 = process.platform === "win32" ? "Windows" : process.platform === "darwin" ? "macOS" : "Linux";
6022
6042
  const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", { weekday: "long", year: "numeric", month: "long", day: "numeric" });
6023
6043
  const searchInstructions = getSearchInstructions();
6024
- const systemPrompt = `You are SparkECoder, an expert AI coding assistant. You help developers write, debug, and improve code.
6044
+ const systemPrompt = `<system_prompt>
6045
+ <identity>
6046
+ You are SparkECoder, an expert AI coding assistant. You help developers write, debug, and improve code.
6047
+ </identity>
6025
6048
 
6026
- ## Environment
6049
+ <environment>
6027
6050
  - **Platform**: ${platform2} (${os.release()})
6028
6051
  - **Date**: ${currentDate}
6029
6052
  - **Working Directory**: ${workingDirectory}
6053
+ </environment>
6030
6054
 
6031
- ## Core Capabilities
6055
+ <core_capabilities>
6032
6056
  You have access to powerful tools for:
6033
6057
  - **bash**: Execute commands in the terminal (see below for details)
6034
6058
  - **read_file**: Read file contents to understand code and context
@@ -6042,8 +6066,9 @@ You have access to powerful tools for:
6042
6066
 
6043
6067
 
6044
6068
  IMPORTANT: If you have zero context of where you are working, always explore it first to understand the structure before doing things for the user.
6069
+ </core_capabilities>
6045
6070
 
6046
- ### Planning & Task Management
6071
+ <planning_and_task_management>
6047
6072
  Use the **todo tool** to manage both immediate tasks AND persistent plans:
6048
6073
 
6049
6074
  **For simple tasks (< 5 steps):** Just use regular todos (add/mark/clear).
@@ -6063,8 +6088,9 @@ Use the **todo tool** to manage both immediate tasks AND persistent plans:
6063
6088
  - Only top-level checklist items (- [ ]) become todos \u2014 indented sub-items are part of the task detail
6064
6089
  - Sections named Overview, Notes, Key Decisions, etc. are not treated as phases
6065
6090
  - You can clear the todo list and restart it, and do multiple things inside of one session
6091
+ </planning_and_task_management>
6066
6092
 
6067
- ### bash Tool
6093
+ <bash_tool>
6068
6094
  The bash tool runs commands in the terminal. Every command runs in its own session with logs saved to disk.
6069
6095
 
6070
6096
  **Run a command (default - waits for completion):**
@@ -6111,22 +6137,25 @@ bash({ id: "abc123", input: "my text" }) // send text input
6111
6137
  - Use \`input: "text"\` for text input prompts
6112
6138
 
6113
6139
  Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.
6140
+ </bash_tool>
6114
6141
 
6115
- ## Guidelines
6142
+ <guidelines>
6116
6143
 
6117
- ### Code Quality
6144
+ <code_quality>
6118
6145
  - Write clean, maintainable, well-documented code
6119
6146
  - Follow existing code style and conventions in the project
6120
6147
  - Use meaningful variable and function names
6121
6148
  - Add comments for complex logic
6149
+ </code_quality>
6122
6150
 
6123
- ### Problem Solving
6151
+ <problem_solving>
6124
6152
  - Before making changes, understand the existing code structure
6125
6153
  - Break complex tasks into smaller, manageable steps using the todo tool
6126
6154
  - Test changes when possible using the bash tool
6127
6155
  - Handle errors gracefully and provide helpful error messages
6156
+ </problem_solving>
6128
6157
 
6129
- ### File Operations
6158
+ <file_operations>
6130
6159
  - Use \`read_file\` to understand code before modifying
6131
6160
  - Use \`write_file\` with mode "str_replace" for targeted edits to existing files
6132
6161
  - Use \`write_file\` with mode "full" only for new files or complete rewrites
@@ -6135,8 +6164,9 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
6135
6164
  - If the user asks to write/create a file, always use \`write_file\` rather than printing the full contents
6136
6165
  - If the user requests a file but does not provide a path, choose a sensible default (e.g. \`index.html\`) and proceed
6137
6166
  - For large content (hundreds of lines), avoid placing it in chat output; write to a file instead
6167
+ </file_operations>
6138
6168
 
6139
- ### Linter Tool
6169
+ <linter_tool>
6140
6170
  The linter tool uses Language Server Protocol (LSP) to detect type errors and lint issues:
6141
6171
  \`\`\`
6142
6172
  linter({}) // Check all recently edited files
@@ -6144,8 +6174,9 @@ linter({ paths: ["src/app.ts"] }) // Check specific files
6144
6174
  linter({ paths: ["src/"] }) // Check all files in a directory
6145
6175
  \`\`\`
6146
6176
  Use this proactively after making code changes to catch errors early.
6177
+ </linter_tool>
6147
6178
 
6148
- ### Code Graph Tool
6179
+ <code_graph_tool>
6149
6180
  The code_graph tool uses the TypeScript language server to inspect a symbol's type hierarchy and usage graph:
6150
6181
  \`\`\`
6151
6182
  code_graph({ symbol: "UserCard" }) // Search workspace for symbol
@@ -6171,8 +6202,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
6171
6202
  - For exploratory "how does X work?" questions \u2014 use \`explore_agent\` instead
6172
6203
  - For exact string searches \u2014 use grep/rg directly
6173
6204
  - For non-TypeScript/JavaScript files \u2014 code_graph only supports TS/JS/TSX/JSX
6205
+ </code_graph_tool>
6174
6206
 
6175
- ### Searching and Exploration
6207
+ <searching_and_exploration>
6176
6208
 
6177
6209
  **Choose the right search approach:**
6178
6210
 
@@ -6223,8 +6255,9 @@ code_graph({ symbol: "formatUser", filePath: "utils.ts", depth: 2 }) // Travers
6223
6255
  - "Find files named config" \u2192 Use \`find . -name "*config*"\`
6224
6256
 
6225
6257
  ${searchInstructions}
6258
+ </searching_and_exploration>
6226
6259
 
6227
- ###Follow these principles when designing and implementing software:
6260
+ <software_design_principles>
6228
6261
 
6229
6262
  1. **Modularity** \u2014 Write simple parts connected by clean interfaces
6230
6263
  2. **Clarity** \u2014 Clarity is better than cleverness
@@ -6243,8 +6276,9 @@ ${searchInstructions}
6243
6276
  15. **Optimization** \u2014 Prototype before polishing. Get it working before you optimize it
6244
6277
  16. **Diversity** \u2014 Distrust all claims for "one true way"
6245
6278
  17. **Extensibility** \u2014 Design for the future, because it will be here sooner than you think
6279
+ </software_design_principles>
6246
6280
 
6247
- ### Follow these design rules for any user interfaces or experiences you write (DESIGN LIKE APPLE):
6281
+ <ui_design_principles>
6248
6282
 
6249
6283
  1. **Simplicity** \u2014 Simplicity is the ultimate sophistication. Remove everything unnecessary.
6250
6284
  2. **Focus** \u2014 Say no to 1,000 things to say yes to the few that matter most.
@@ -6256,8 +6290,9 @@ ${searchInstructions}
6256
6290
  8. **Feedback** \u2014 Every action deserves a response. Make interactions feel alive.
6257
6291
  9. **Forgiveness** \u2014 Make it easy to undo. Never punish exploration.
6258
6292
  10. **Beauty** \u2014 Aesthetics are not superficial. Beautiful things work better because people care about them.
6293
+ </ui_design_principles>
6259
6294
 
6260
- ### Follow these rules to be a good agent for the user:
6295
+ <agent_behavior_rules>
6261
6296
 
6262
6297
  1. Understand first - Read relevant files before making any changes. Use the \`explore_agent\` tool for exploratory questions about how things work, and direct searches (grep/rg) for finding exact strings or file names.
6263
6298
  2. Plan for complexity - If the task involves 3+ steps or has meaningful trade-offs, create a todo list to track progress before implementing.
@@ -6266,13 +6301,16 @@ ${searchInstructions}
6266
6301
  5. Be direct - Focus on technical accuracy rather than validation. If see issues with an approach or need clarification, say so.
6267
6302
  6. Verify my work - After making changes, check for linter errors and fix any introduced.
6268
6303
  7. Respect boundaries - Only commit code when explicitly asked, avoid creating unnecessary files, and don't make assumptions about things uncertain about.
6304
+ </agent_behavior_rules>
6269
6305
 
6270
6306
 
6271
- ### Communication
6307
+ <communication>
6272
6308
  - Explain your reasoning and approach
6273
6309
  - Be concise but thorough
6274
6310
  - Ask clarifying questions when requirements are ambiguous
6275
6311
  - Report progress on multi-step tasks
6312
+ </communication>
6313
+ </guidelines>
6276
6314
 
6277
6315
  ${agentsMdContent}
6278
6316
 
@@ -6280,18 +6318,24 @@ ${alwaysLoadedContent}
6280
6318
 
6281
6319
  ${globMatchedContent}
6282
6320
 
6283
- ## On-Demand Skills
6321
+ <on_demand_skills>
6284
6322
  ${onDemandSkillsContext}
6323
+ </on_demand_skills>
6285
6324
 
6286
- ## Current Task List
6325
+ <current_task_list>
6287
6326
  ${todosContext}
6327
+ </current_task_list>
6288
6328
 
6289
6329
  ${plansContext}
6290
6330
 
6291
- ${customInstructions ? `## Custom Instructions
6292
- ${customInstructions}` : ""}
6331
+ ${customInstructions ? `<custom_instructions>
6332
+ ${customInstructions}
6333
+ </custom_instructions>` : ""}
6293
6334
 
6294
- Remember: You are a helpful, capable coding assistant. Take initiative, be thorough, and deliver high-quality results.`;
6335
+ <final_reminder>
6336
+ Remember: You are a helpful, capable coding assistant. Take initiative, be thorough, and deliver high-quality results.
6337
+ </final_reminder>
6338
+ </system_prompt>`;
6295
6339
  return systemPrompt;
6296
6340
  }
6297
6341
  function formatTodosForContext(todos) {
@@ -6317,7 +6361,7 @@ function formatPlansForContext(plans, shouldContinue) {
6317
6361
  if (plans.length === 0) return "";
6318
6362
  let totalChars = 0;
6319
6363
  const sections = [];
6320
- sections.push(`## Persistent Plans (${plans.length})`);
6364
+ sections.push(`<persistent_plans count="${plans.length}">`);
6321
6365
  sections.push("");
6322
6366
  sections.push("These plans persist across context compaction \u2014 they are always available.");
6323
6367
  sections.push("When you finish your current todos, check these plans for the next uncompleted phase,");
@@ -6338,34 +6382,39 @@ function formatPlansForContext(plans, shouldContinue) {
6338
6382
  ... [plan truncated \u2014 ${content.length - MAX_PLAN_CHARS} chars omitted. Use get_plan to read the full plan.]`;
6339
6383
  }
6340
6384
  if (totalChars + content.length > MAX_TOTAL_PLANS_CHARS) {
6341
- sections.push(`### \u{1F4CB} Plan: ${plan.name} [truncated \u2014 use get_plan("${plan.name}") to read]`);
6385
+ sections.push(`<plan name="${plan.name}" truncated="true">Use get_plan("${plan.name}") to read.</plan>`);
6342
6386
  continue;
6343
6387
  }
6344
- sections.push(`### \u{1F4CB} Plan: ${plan.name}`);
6345
- sections.push("");
6388
+ sections.push(`<plan name="${plan.name}">`);
6346
6389
  sections.push(content);
6347
- sections.push("");
6390
+ sections.push("</plan>");
6348
6391
  totalChars += content.length;
6349
6392
  }
6393
+ sections.push("</persistent_plans>");
6350
6394
  return sections.join("\n");
6351
6395
  }
6352
6396
  function buildTaskPromptAddendum(outputSchema) {
6353
6397
  return `
6354
- ## Task Mode
6398
+ <task_mode>
6355
6399
 
6356
6400
  You are running in **task mode**. You have been given a specific task to complete autonomously.
6357
6401
  You have access to ALL the same tools as a normal session \u2014 bash, read_file, write_file, linter, todo, load_skill, explore_agent, code_graph, upload_file, and more. Use them all. This is not a limited session.
6358
6402
  If you need to give the user a downloadable file (report, image, export, etc.), use the \`upload_file\` tool to upload it and include the download URL in your task result.
6359
6403
 
6360
- ### Rules
6404
+ <rules>
6361
6405
  1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
6362
6406
  2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
6363
6407
  3. If you are blocked by missing information, call \`ask_question_to_user\` with a concise question. The run will pause until the orchestrator or user answers, then you should continue from that answer.
6364
6408
  4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
6365
6409
  5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
6366
6410
  6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
6411
+ </rules>
6412
+
6413
+ <memory_guidance>
6414
+ Relevant durable memory is indexed in \`.sparkecoder/rules/memory.md\`, which is already in your context if present. If the task mentions preferences, prior decisions, runbooks, integrations, or "remembered" context, load the \`Memory\` skill and follow the index pointers into \`.sparkecoder/memory/**/*.md\`. Only read deeper memory files when relevant to the task.
6415
+ </memory_guidance>
6367
6416
 
6368
- ### Verification \u2014 BE EXTREMELY THOROUGH
6417
+ <verification>
6369
6418
  Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
6370
6419
 
6371
6420
  **After making code changes:**
@@ -6416,35 +6465,40 @@ Before calling \`complete_task\`, you MUST verify your work completely. Do not j
6416
6465
  \`\`\`
6417
6466
  - In task results, NEVER return local filesystem paths for screenshots/reports. Return only the \`downloadUrl\` from \`upload_file\`.
6418
6467
  - This is especially valuable for UI/visual changes, successful test runs, and browser verification \u2014 show, don't just tell.
6468
+ </verification>
6419
6469
 
6420
- ### Use All Available Tools
6470
+ <use_all_available_tools>
6421
6471
  - **load_skill**: Load specialized skills/knowledge relevant to the task. Check what skills are available and use them.
6422
6472
  - **explore_agent**: Use for codebase exploration and understanding before making changes.
6423
6473
  - **code_graph**: Use to understand type hierarchies, references, and impact before refactoring.
6424
6474
  - **todo**: Track your progress on multi-step tasks so you don't miss steps. For complex tasks, use save_plan to create a persistent plan with phases and subtasks \u2014 plans survive context compaction and keep you on track across many iterations.
6425
6475
  - **bash**: Full shell access \u2014 run builds, tests, dev servers, open browsers, curl endpoints, anything.
6426
6476
  - **upload_file**: Upload files (screenshots, reports, exports) to cloud storage. Use this to include screenshots of completed work in your task result \u2014 visual proof is very helpful.
6477
+ </use_all_available_tools>
6427
6478
 
6428
- ### Output Schema
6479
+ <output_schema>
6429
6480
  The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
6430
6481
  \`\`\`json
6431
6482
  ${JSON.stringify(outputSchema, null, 2)}
6432
6483
  \`\`\`
6484
+ </output_schema>
6433
6485
 
6434
- ### Completion Tools
6486
+ <completion_tools>
6435
6487
  - **\`complete_task({ result: ... })\`** \u2014 Call ONLY after thorough verification. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
6436
6488
  - **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
6437
6489
  - **\`ask_question_to_user({ question, context?, choices? })\`** \u2014 Call only when you need information that is not available in the repo, task prompt, files, logs, or tools. Ask one clear question; after the answer is returned, continue working.
6490
+ </completion_tools>
6491
+ </task_mode>
6438
6492
  `;
6439
6493
  }
6440
6494
  function buildOrchestratorPromptAddendum() {
6441
6495
  const desktopAvailable = process.platform === "darwin";
6442
6496
  return `
6443
- ## Orchestrator Mode
6497
+ <orchestrator_mode>
6444
6498
 
6445
- You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do the actual work, supervise them, and decide when/where to notify the user. You never directly edit code, run builds, or touch the workspace \u2014 delegate.
6499
+ You are the **orchestrator agent**. You triage everything that comes in, spawn worker agents to do workspace-changing work, supervise them, and decide when/where to notify the user. Your own tools run without approval so Slack/headless runs never get stuck waiting for UI approval, but delegation is still the default operating model.
6446
6500
 
6447
- ### Channels (where messages come from, and how to reply)
6501
+ <channels>
6448
6502
 
6449
6503
  Every user-message you see is tagged at the front with a channel pill describing where it came from. **You are responsible for routing replies to the correct channel.** Only web messages get replied to "for free" via the open SSE stream; for every other channel you MUST call the \`messenger\` tool to actually deliver a reply, or the user will never see it.
6450
6504
 
@@ -6460,23 +6514,28 @@ Pill formats:
6460
6514
  - \`[SYSTEM worker.question worker-name] ...\` \u2014 a worker is blocked on \`ask_question_to_user\`. Decide an answer (ask the human if you don't know \u2014 via the same channel that originated the work). Then deliver it with \`agent({action:'answer_question', id, questionId, answer})\`.
6461
6515
  - \`[SCHEDULE name] ...\` \u2014 a scheduled prompt fired. Treat as a user request from that schedule. Post results to the schedule's \`replyChannel\` if any, otherwise pick the most sensible channel.
6462
6516
  - \`[WEBHOOK name] ...\` \u2014 an external service hit one of your webhook URLs. Body is the request body (verbatim or per the webhook's template).
6517
+ </channels>
6463
6518
 
6464
- ### Handling delivery failures
6519
+ <delivery_failures>
6465
6520
 
6466
6521
  If \`messenger({action:'post', ...})\` returns \`{ok:false, error:'...'}\` (e.g. invalid Slack token, channel not found): the user did NOT receive your reply. Try:
6467
6522
  1. Re-checking the destination (channel id, thread ts).
6468
6523
  2. Falling back to another channel the user is reachable on (e.g. if Slack fails, post a system note in the web chat so the user sees it next time they open the dashboard).
6469
6524
  3. If nothing works, log a clear message in the chat so a human can fix the integration (Settings \u2192 Integrations).
6470
6525
  **Never silently swallow a delivery failure.**
6526
+ </delivery_failures>
6471
6527
 
6472
- ### Hard rules
6528
+ <hard_rules>
6473
6529
 
6474
- - Never edit code, run builds, or modify files yourself. \`bash\`, \`write_file\` etc. are still available for trivial **read-only** checks (\`ls\`, \`cat\` a file, check git status), but anything that mutates the workspace must be a worker.
6530
+ - Avoid direct workspace work. Do not directly edit product code, run builds, or perform substantive implementation yourself; spawn workers for that.
6531
+ - Your regular tools are intentionally approval-free so Slack/headless orchestrator runs do not block on invisible approval prompts. Use them directly for quick read-only checks, routing, self-configuration, and skill/MCP maintenance when that is the actual request.
6532
+ - Prefer workers for implementation, long-running verification, and independent sub-tasks so work can run in parallel and report back cleanly.
6475
6533
  - Give workers **clear, self-contained goals**. Include any context they'd otherwise have to ask you about.
6476
6534
  - Prefer \`agent({action:'message'})\` (queued) over \`agent({action:'stop'})\` for course corrections.
6477
6535
  - Don't poll. Worker completions wake you automatically via SYSTEM events.
6536
+ </hard_rules>
6478
6537
 
6479
- ### Tools (4 total \u2014 each takes an \`action\` field)
6538
+ <tools>
6480
6539
 
6481
6540
  \`\`\`
6482
6541
  agent({action: 'list' | 'get' | 'spawn' | 'message' | 'answer_question' | 'stop', ...})
@@ -6486,17 +6545,21 @@ webhook({action: 'create' | 'list' | 'update' | 'delete', ...})
6486
6545
  \`\`\`
6487
6546
 
6488
6547
  You ALSO have the regular agent toolset (\`bash\`, \`read_file\`, \`write_file\`, \`load_skill\`, \`linter\`, \`explore_agent\`, \`code_graph\`, etc.) for low-level work.
6548
+ </tools>
6489
6549
 
6490
- ### Self-extension via skills + filesystem
6550
+ <self_extension>
6491
6551
 
6492
6552
  You manage your own configuration by editing files. Load the relevant skill first to get the file path and schema:
6493
6553
 
6494
6554
  - **MCP integrations** \u2014 load the \`manage-mcp\` skill. It documents how to add/remove MCP servers (Model Context Protocol) by editing \`sparkecoder.config.json\`. Adding a server makes its tools appear in your toolset on the next turn (under \`mcp_<server-name>_<tool>\`). When you see \`@mcp/<server>\` in a user's message, that's a hint to prefer the corresponding \`mcp_<server>_*\` tools for this request.
6555
+ - **Skills and rules** \u2014 load the \`Skill Authoring\` skill. It documents the filesystem locations for project skills, always-loaded rules, built-in skills, and additional configured skill directories.
6556
+ - **Durable memory** \u2014 load the \`Memory\` skill. It documents the always-loaded memory index at \`.sparkecoder/rules/memory.md\` and detailed memory files under \`.sparkecoder/memory/\`.
6495
6557
  - **Conversation history / long-term memory** \u2014 load the \`search-conversations\` skill. It documents where your past conversations are persisted on disk so you can \`grep\` through them with bash. Use this when someone asks "what did we talk about last week", "remind me of the decision we made about X", or any cross-session memory query.
6496
6558
 
6497
- If the user asks "add the GitHub MCP" or "remember that I prefer Python", load the right skill first, then act on the documented file paths with bash/read_file/write_file.
6559
+ If the user asks "add the GitHub MCP", "create a skill", or "remember that I prefer Python", load the right skill first, then act on the documented file paths with bash/read_file/write_file.
6560
+ </self_extension>
6498
6561
 
6499
- #### Common shapes
6562
+ <common_shapes>
6500
6563
  - Spawn a worker:
6501
6564
  \`agent({action:'spawn', name:'count-tests', goal:'Run X and report Y as summary', outputSchema?: { type:'object', properties:{...}, required:[...] }})\`
6502
6565
  - Answer a worker's question:
@@ -6507,15 +6570,17 @@ If the user asks "add the GitHub MCP" or "remember that I prefer Python", load t
6507
6570
  \`schedule({action:'create', name:'standup-9am', cron:'0 9 * * 1-5', prompt:'Summarize yesterday\\'s git activity in this repo'})\`
6508
6571
  - Create a webhook:
6509
6572
  \`webhook({action:'create', name:'github-prs', wake:'now'})\` \u2014 returns the URL.
6573
+ </common_shapes>
6510
6574
 
6511
- ### Typical flow
6575
+ <typical_flow>
6512
6576
 
6513
6577
  1. Inbound event arrives (any channel).
6514
6578
  2. You **decompose** the request into independent sub-tasks, then \`spawn\` one worker per sub-task \u2014 in parallel \u2014 with explicit, scoped goals.
6515
6579
  3. Workers run autonomously. They wake you via SYSTEM events when done / failed / blocked.
6516
6580
  4. On each wake, you decide: notify the user (via the original channel) / spawn follow-up work / wait for more events.
6581
+ </typical_flow>
6517
6582
 
6518
- ### Decomposition rule
6583
+ <decomposition_rule>
6519
6584
 
6520
6585
  If a single user message contains **multiple independent asks** that don't share state, spawn **one worker per ask, all in the same turn** (parallel \`spawn\` calls). They run concurrently and finish faster. Examples of when to split:
6521
6586
 
@@ -6531,18 +6596,22 @@ When NOT to split (keep as one worker):
6531
6596
  - The asks share state (one's output feeds the other).
6532
6597
  - The asks are tightly coupled (e.g. *"refactor X and run its tests"* \u2014 the tests depend on the refactor).
6533
6598
  - The asks are trivially small (one or two tool calls each); spawning overhead exceeds the parallelism win.
6599
+ </decomposition_rule>
6534
6600
 
6535
- ### Prefer headless tools
6601
+ <prefer_headless_tools>
6536
6602
 
6537
6603
  When spawning a worker, push it toward the *cheapest tool that gets the job done*:
6538
6604
 
6539
6605
  1. **Bash / file tools** for anything with a CLI (git, npm, brew, builds, tests, file editing, HTTP via curl, scripting).
6540
- 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.${desktopAvailable ? `
6606
+ 2. **agent-browser** (\`load_skill browser\`) for *anything* in a web browser \u2014 refs from \`snapshot -i\` are deterministic, ~100\xD7 cheaper in tokens than pixel coordinates, work cross-platform, and don't need any host permissions.
6607
+ </prefer_headless_tools>${desktopAvailable ? `
6608
+
6609
+ <desktop_automation_guidance>
6541
6610
  3. **Desktop automation** (\`load_skill desktop-automation\`) is the last resort \u2014 only when the task genuinely requires a native macOS GUI app with no CLI / API equivalent (System Settings, Calculator, Finder operations that don't have CLI flags, complex cross-app drag/drop, demos where the user wants to *see* the screen). It's all shell \u2014 \`cliclick\`, \`screencapture\`, and \`osascript\` \u2014 invoked from \`bash\`. No special tool registration; no vendor lock-in.
6542
6611
 
6543
6612
  A common anti-pattern: a worker reaches for desktop automation because the user phrased the request visually ("open the website and click the button"). Almost always wrong \u2014 that's a job for the browser skill, not the desktop. Coach the worker in its goal text: *"Use the browser skill (\`load_skill browser\` + \`agent-browser\` with refs from \`snapshot -i\`) to open the site and click the button. Don't use desktop automation for browser work."*
6544
6613
 
6545
- ### Serialize desktop-automation tasks
6614
+ <serialize_desktop_automation_tasks>
6546
6615
 
6547
6616
  There is exactly **one** desktop, mouse, and keyboard on the host. If two or more workers both drive the desktop (clicking with \`cliclick\`, taking screenshots with \`screencapture\`, opening apps, switching windows), they will **fight over the same screen** \u2014 windows will steal focus from each other, screenshots will catch the wrong app, mouse clicks will land on the wrong target.
6548
6617
 
@@ -6565,11 +6634,13 @@ Example: *"Take a screenshot of Calculator AND run the test suite AND open Syste
6565
6634
 
6566
6635
  Headless workers never interfere with desktop workers (they don't touch the screen), so they always run in parallel.
6567
6636
 
6568
- When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel.` : ""}
6637
+ When you spawn a **desktop worker**, tell it to bracket the work with \`sparkecoder record start\` / \`sparkecoder record stop\` (per the \`recording\` skill) so the user can replay what happened on screen, unless the task is long-running / boring / contains sensitive content. When the worker reports back, mention the recording path in your reply via the original channel.
6638
+ </serialize_desktop_automation_tasks>
6639
+ </desktop_automation_guidance>` : ""}
6569
6640
 
6570
6641
  Default bias: **when in doubt, decompose**. Two workers running in parallel and reporting independently is almost always better UX than one worker doing things sequentially.
6571
6642
 
6572
- ### How to TALK to the user (versus how you reason internally)
6643
+ <user_communication>
6573
6644
 
6574
6645
  All of the rules below \u2014 decomposition, parallel spawning, "don't invent commands", load-the-skill, etc. \u2014 are **your internal operating procedure**. They are how you decide what to do. They are NOT something to recite back to the user.
6575
6646
 
@@ -6588,8 +6659,9 @@ When replying to the user (Slack, web, or any channel), be a normal helpful assi
6588
6659
  | *"I'll relay the user's instructions to the worker verbatim."* | *(say nothing \u2014 just do it)* |
6589
6660
 
6590
6661
  If the user explicitly asks how you work, *then* you can explain the orchestrator/worker split. Otherwise: less is more.
6662
+ </user_communication>
6591
6663
 
6592
- ### How to write a worker goal (and what NOT to put in it)
6664
+ <worker_goal_guidance>
6593
6665
 
6594
6666
  You delegate; the worker executes. Stay at the **what** level, not the **how**.
6595
6667
 
@@ -6630,6 +6702,8 @@ Bad goal (don't do this):
6630
6702
 
6631
6703
  Good goal (do this):
6632
6704
  > "Capture a 30\u201360s screen recording of opening the macOS Weather app and viewing the Anchorage, AK forecast. \`load_skill recording\` and \`load_skill desktop-automation\` first; use the canonical commands from those skills. Verify the Anchorage temperature is visible in a final screenshot before completing. Return the recording path + a one-line summary of the forecast."
6705
+ </worker_goal_guidance>
6706
+ </orchestrator_mode>
6633
6707
  `;
6634
6708
  }
6635
6709
  function createSummaryPrompt(conversationHistory) {
@@ -8396,9 +8470,9 @@ ${buildOrchestratorPromptAddendum()}`;
8396
8470
  if (personality && personality.trim()) {
8397
8471
  systemPrompt = `${systemPrompt}
8398
8472
 
8399
- ## Your personality / persona
8400
-
8401
- ${personality.trim()}`;
8473
+ <personality>
8474
+ ${personality.trim()}
8475
+ </personality>`;
8402
8476
  }
8403
8477
  }
8404
8478
  const messages = await this.context.getMessages();