@oh-my-pi/pi-coding-agent 15.9.0 → 15.9.1

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 (80) hide show
  1. package/CHANGELOG.md +39 -0
  2. package/dist/types/cli/update-cli.d.ts +15 -1
  3. package/dist/types/config/append-only-context-mode.d.ts +8 -0
  4. package/dist/types/config/model-registry.d.ts +3 -0
  5. package/dist/types/config/models-config-schema.d.ts +15 -0
  6. package/dist/types/config/settings-schema.d.ts +3 -3
  7. package/dist/types/exa/mcp-client.d.ts +2 -1
  8. package/dist/types/mcp/json-rpc.d.ts +6 -1
  9. package/dist/types/mcp/tool-bridge.d.ts +4 -0
  10. package/dist/types/mnemopi/state.d.ts +2 -2
  11. package/dist/types/modes/components/agent-dashboard.d.ts +1 -0
  12. package/dist/types/modes/components/extensions/extension-dashboard.d.ts +1 -0
  13. package/dist/types/modes/components/plugin-settings.d.ts +40 -8
  14. package/dist/types/modes/components/session-selector.d.ts +8 -3
  15. package/dist/types/modes/components/settings-selector.d.ts +1 -1
  16. package/dist/types/modes/utils/keybinding-matchers.d.ts +4 -0
  17. package/dist/types/session/agent-session.d.ts +4 -1
  18. package/dist/types/session/history-storage.d.ts +3 -4
  19. package/dist/types/session/messages.d.ts +1 -0
  20. package/dist/types/session/session-manager.d.ts +1 -0
  21. package/dist/types/slash-commands/types.d.ts +17 -4
  22. package/dist/types/tiny/text.d.ts +17 -0
  23. package/dist/types/web/search/providers/base.d.ts +14 -0
  24. package/dist/types/web/search/providers/exa.d.ts +9 -0
  25. package/dist/types/web/search/providers/perplexity.d.ts +2 -2
  26. package/dist/types/web/search/types.d.ts +2 -1
  27. package/package.json +9 -9
  28. package/src/cli/session-picker.ts +1 -0
  29. package/src/cli/update-cli.ts +54 -2
  30. package/src/commands/completions.ts +1 -1
  31. package/src/config/append-only-context-mode.ts +37 -0
  32. package/src/config/models-config-schema.ts +1 -0
  33. package/src/config/settings-schema.ts +2 -2
  34. package/src/exa/mcp-client.ts +11 -5
  35. package/src/internal-urls/docs-index.generated.ts +1 -1
  36. package/src/main.ts +4 -2
  37. package/src/mcp/json-rpc.ts +8 -0
  38. package/src/mcp/render.ts +3 -0
  39. package/src/mcp/tool-bridge.ts +10 -2
  40. package/src/mcp/transports/http.ts +33 -16
  41. package/src/mnemopi/state.ts +4 -4
  42. package/src/modes/acp/acp-agent.ts +168 -3
  43. package/src/modes/components/agent-dashboard.ts +103 -31
  44. package/src/modes/components/extensions/extension-dashboard.ts +56 -10
  45. package/src/modes/components/history-search.ts +128 -14
  46. package/src/modes/components/plugin-settings.ts +270 -36
  47. package/src/modes/components/session-selector.ts +45 -14
  48. package/src/modes/components/settings-selector.ts +1 -1
  49. package/src/modes/components/tips.txt +5 -1
  50. package/src/modes/components/transcript-container.ts +22 -4
  51. package/src/modes/controllers/command-controller.ts +4 -3
  52. package/src/modes/controllers/input-controller.ts +10 -5
  53. package/src/modes/controllers/selector-controller.ts +30 -19
  54. package/src/modes/interactive-mode.ts +38 -3
  55. package/src/modes/utils/keybinding-matchers.ts +10 -0
  56. package/src/prompts/steering/user-interjection.md +10 -0
  57. package/src/prompts/system/agent-creation-architect.md +1 -26
  58. package/src/prompts/system/system-prompt.md +143 -145
  59. package/src/prompts/system/title-system.md +3 -2
  60. package/src/prompts/tools/browser.md +29 -29
  61. package/src/prompts/tools/render-mermaid.md +2 -2
  62. package/src/sdk.ts +5 -21
  63. package/src/session/agent-session.ts +30 -7
  64. package/src/session/history-storage.ts +11 -18
  65. package/src/session/messages.ts +80 -0
  66. package/src/session/session-manager.ts +7 -1
  67. package/src/slash-commands/types.ts +27 -10
  68. package/src/tiny/text.ts +112 -1
  69. package/src/tools/memory-recall.ts +1 -1
  70. package/src/tools/memory-reflect.ts +1 -1
  71. package/src/tools/ssh.ts +26 -10
  72. package/src/tools/write.ts +14 -2
  73. package/src/tui/status-line.ts +15 -4
  74. package/src/utils/title-generator.ts +9 -2
  75. package/src/web/search/index.ts +3 -1
  76. package/src/web/search/provider.ts +1 -1
  77. package/src/web/search/providers/base.ts +17 -0
  78. package/src/web/search/providers/exa.ts +111 -7
  79. package/src/web/search/providers/perplexity.ts +8 -4
  80. package/src/web/search/types.ts +2 -1
@@ -1,5 +1,4 @@
1
1
  import * as fs from "node:fs/promises";
2
- import type { AgentMessage } from "@oh-my-pi/pi-agent-core";
3
2
  import type { AutocompleteProvider, SlashCommand } from "@oh-my-pi/pi-tui";
4
3
  import { $env, sanitizeText } from "@oh-my-pi/pi-utils";
5
4
  import { getRoleInfo } from "../../config/model-registry";
@@ -13,6 +12,7 @@ import type { AgentSessionEvent } from "../../session/agent-session";
13
12
  import { SKILL_PROMPT_MESSAGE_TYPE, type SkillPromptDetails } from "../../session/messages";
14
13
  import { executeBuiltinSlashCommand } from "../../slash-commands/builtin-registry";
15
14
  import { isTinyTitleLocalModelKey } from "../../tiny/models";
15
+ import { isLowSignalTitleInput } from "../../tiny/text";
16
16
  import { tinyTitleClient } from "../../tiny/title-client";
17
17
  import type { TinyTitleProgressEvent } from "../../tiny/title-protocol";
18
18
  import { copyToClipboard, readImageFromClipboard, readTextFromClipboard } from "../../utils/clipboard";
@@ -376,9 +376,12 @@ export class InputController {
376
376
  // First, move any pending bash components to chat
377
377
  this.ctx.flushPendingBashComponents();
378
378
 
379
- // Generate session title on first message
380
- const hasUserMessages = this.ctx.session.messages.some((m: AgentMessage) => m.role === "user");
381
- if (!hasUserMessages && !this.ctx.sessionManager.getSessionName() && !$env.PI_NO_TITLE) {
379
+ // Auto-generate a session title while the session is still unnamed.
380
+ // Greetings / acknowledgements / empty input carry no task, so they are
381
+ // skipped deterministically (no model invoked, no download-progress UI)
382
+ // and the session stays unnamed — the next user message gets a fresh
383
+ // chance, so titling defers past "hi" instead of latching onto it.
384
+ if (!this.ctx.sessionManager.getSessionName() && !$env.PI_NO_TITLE && !isLowSignalTitleInput(text)) {
382
385
  this.#showTinyTitleDownloadProgress(this.ctx.settings.get("providers.tinyModel"));
383
386
  const registry = this.ctx.session.modelRegistry;
384
387
  generateSessionTitle(
@@ -390,7 +393,9 @@ export class InputController {
390
393
  provider => this.ctx.session.agent.metadataForProvider(provider),
391
394
  )
392
395
  .then(async title => {
393
- if (title) {
396
+ // Re-check: a concurrent attempt for an earlier message may have
397
+ // already named the session. Don't clobber it.
398
+ if (title && !this.ctx.sessionManager.getSessionName()) {
394
399
  const applied = await this.ctx.sessionManager.setSessionName(title, "auto");
395
400
  if (applied) {
396
401
  setSessionTerminalTitle(
@@ -133,7 +133,11 @@ export class SelectorController {
133
133
  const availableWidth = this.ctx.editor.getTopBorderAvailableWidth(this.ctx.ui.terminal.columns);
134
134
  return this.ctx.statusLine.getTopBorder(availableWidth).content;
135
135
  },
136
- onPluginsChanged: () => {
136
+ onPluginsChanged: async () => {
137
+ const projectPath = await resolveActiveProjectRegistryPath(this.ctx.sessionManager.getCwd());
138
+ clearPluginRootsAndCaches(projectPath ? [projectPath] : undefined);
139
+ await this.ctx.refreshSlashCommandState();
140
+ await this.ctx.session.refreshSshTool({ activateIfAvailable: true });
137
141
  this.ctx.ui.requestRender();
138
142
  },
139
143
  onCancel: () => {
@@ -184,16 +188,19 @@ export class SelectorController {
184
188
  */
185
189
  async showExtensionsDashboard(): Promise<void> {
186
190
  const dashboard = await ExtensionDashboard.create(getProjectDir(), this.ctx.settings, this.ctx.ui.terminal.rows);
187
- this.showSelector(done => {
188
- dashboard.onClose = () => {
189
- done();
190
- this.ctx.ui.requestRender();
191
- };
192
- dashboard.onRequestRender = () => {
193
- this.ctx.ui.requestRender();
194
- };
195
- return { component: dashboard, focus: dashboard };
191
+ const overlay = this.ctx.ui.showOverlay(dashboard, {
192
+ width: "100%",
193
+ maxHeight: "100%",
194
+ anchor: "top-left",
195
+ margin: 0,
196
196
  });
197
+ dashboard.onClose = () => {
198
+ overlay.hide();
199
+ this.ctx.ui.requestRender();
200
+ };
201
+ dashboard.onRequestRender = () => {
202
+ this.ctx.ui.requestRender();
203
+ };
197
204
  }
198
205
 
199
206
  /**
@@ -208,16 +215,19 @@ export class SelectorController {
208
215
  activeModelPattern,
209
216
  defaultModelPattern,
210
217
  });
211
- this.showSelector(done => {
212
- dashboard.onClose = () => {
213
- done();
214
- this.ctx.ui.requestRender();
215
- };
216
- dashboard.onRequestRender = () => {
217
- this.ctx.ui.requestRender();
218
- };
219
- return { component: dashboard, focus: dashboard };
218
+ const overlay = this.ctx.ui.showOverlay(dashboard, {
219
+ width: "100%",
220
+ maxHeight: "100%",
221
+ anchor: "top-left",
222
+ margin: 0,
220
223
  });
224
+ dashboard.onClose = () => {
225
+ overlay.hide();
226
+ this.ctx.ui.requestRender();
227
+ };
228
+ dashboard.onRequestRender = () => {
229
+ this.ctx.ui.requestRender();
230
+ };
221
231
  }
222
232
 
223
233
  /**
@@ -763,6 +773,7 @@ export class SelectorController {
763
773
  loadAllSessions: () => SessionManager.listAll(),
764
774
  allSessions,
765
775
  startInAllScope,
776
+ getTerminalRows: () => this.ctx.ui.terminal.rows,
766
777
  },
767
778
  );
768
779
  selector.setOnRequestRender(() => this.ctx.ui.requestRender());
@@ -607,7 +607,8 @@ export class InteractiveMode implements InteractiveModeContext {
607
607
  await this.initHooksAndCustomTools();
608
608
 
609
609
  // Restore mode from session (e.g. plan mode on resume)
610
- await this.#restoreModeFromSession();
610
+ this.session.setSessionSwitchReconciler?.(() => this.#reconcileModeFromSession());
611
+ await this.#reconcileModeFromSession();
611
612
 
612
613
  // Restore unsent editor draft from previous session shutdown (Ctrl+D).
613
614
  // One-shot: consumeDraft removes the sidecar after read so the next
@@ -1370,8 +1371,42 @@ export class InteractiveMode implements InteractiveModeContext {
1370
1371
  }
1371
1372
  }
1372
1373
 
1373
- /** Restore mode state from session entries on resume (e.g. plan mode). */
1374
- async #restoreModeFromSession(): Promise<void> {
1374
+ async #clearTransientModeState(): Promise<void> {
1375
+ if (this.planModeEnabled || this.planModePaused) {
1376
+ if (this.#planModePreviousTools !== undefined) {
1377
+ await this.session.setActiveToolsByName(this.#planModePreviousTools);
1378
+ }
1379
+ this.session.setStandingResolveHandler?.(null);
1380
+ this.session.setPlanModeState(undefined);
1381
+ this.planModeEnabled = false;
1382
+ this.planModePaused = false;
1383
+ this.planModePlanFilePath = undefined;
1384
+ this.#planModePreviousTools = undefined;
1385
+ this.#planModePreviousModelState = undefined;
1386
+ this.#pendingModelSwitch = undefined;
1387
+ this.#planModeHasEntered = false;
1388
+ this.#updatePlanModeStatus();
1389
+ }
1390
+
1391
+ if (this.goalModeEnabled || this.goalModePaused) {
1392
+ if (this.#goalModePreviousTools !== undefined) {
1393
+ await this.session.setActiveToolsByName(this.#goalModePreviousTools);
1394
+ }
1395
+ this.session.setGoalModeState(undefined);
1396
+ this.goalModeEnabled = false;
1397
+ this.goalModePaused = false;
1398
+ this.#goalModePreviousTools = undefined;
1399
+ this.#goalTurnHadToolCalls = false;
1400
+ this.#goalContinuationTurnInFlight = false;
1401
+ this.#goalSuppressNextContinuation = false;
1402
+ this.#cancelGoalContinuation();
1403
+ this.#updateGoalModeStatus();
1404
+ }
1405
+ }
1406
+
1407
+ /** Reconcile mode state from session entries on resume/switch. */
1408
+ async #reconcileModeFromSession(): Promise<void> {
1409
+ await this.#clearTransientModeState();
1375
1410
  const sessionContext = this.sessionManager.buildSessionContext();
1376
1411
  const goalEnabled = this.session.settings.get("goal.enabled");
1377
1412
  if (!goalEnabled && (sessionContext.mode === "goal" || sessionContext.mode === "goal_paused")) {
@@ -31,6 +31,16 @@ export function matchesSelectDown(data: string): boolean {
31
31
  return getKeybindings().matches(data, "tui.select.down");
32
32
  }
33
33
 
34
+ /** Match the generic selector page-up keybinding. */
35
+ export function matchesSelectPageUp(data: string): boolean {
36
+ return getKeybindings().matches(data, "tui.select.pageUp");
37
+ }
38
+
39
+ /** Match the generic selector page-down keybinding. */
40
+ export function matchesSelectPageDown(data: string): boolean {
41
+ return getKeybindings().matches(data, "tui.select.pageDown");
42
+ }
43
+
34
44
  export function matchesAppExternalEditor(data: string): boolean {
35
45
  const keybindings = getKeybindings();
36
46
  const externalEditorKeys = keybindings.getKeys("app.editor.external");
@@ -0,0 +1,10 @@
1
+ <user_interjection>
2
+ The user sent this message while you were working on the current task. It takes
3
+ priority and supersedes your earlier plan wherever they conflict. Stop work that no
4
+ longer matches their intent, re-read the request below, and adjust what you are doing
5
+ now.
6
+
7
+ <message>
8
+ {{message}}
9
+ </message>
10
+ </user_interjection>
@@ -28,38 +28,13 @@ When a user describes what they want an agent to do:
28
28
  - MUST clearly indicate the agent's primary function
29
29
  - SHOULD be memorable and easy to type
30
30
  - NEVER use generic terms like "helper" or "assistant"
31
- 6. Example agent descriptions
32
- - In the `whenToUse` field, SHOULD include examples of when this agent SHOULD be used
33
- - Format examples as:
34
- ```
35
- <example>
36
- Context: The user is creating a test-runner agent that should be called after a logical chunk of code is written.
37
- user: "Please write a function that checks if a number is prime"
38
- assistant: "Here is the relevant function: "
39
- <function call omitted for brevity only for this example>
40
- <commentary>
41
- Since a significant piece of code was written, use the {{TASK_TOOL_NAME}} tool to launch the test-runner agent to run the tests.
42
- </commentary>
43
- assistant: "Now let me use the test-runner agent to run the tests"
44
- </example>
45
- <example>
46
- Context: User is creating an agent to respond to the word "hello" with a friendly joke.
47
- user: "Hello"
48
- assistant: "I'm going to use the {{TASK_TOOL_NAME}} tool to launch the greeting-responder agent to respond with a friendly joke"
49
- <commentary>
50
- Since the user is greeting, use the greeting-responder agent to respond with a friendly joke.
51
- </commentary>
52
- </example>
53
- ```
54
- - If the user mentioned or implied proactive use, SHOULD include proactive examples
55
- - MUST ensure examples show the assistant using the Agent tool, not responding directly
56
31
 
57
32
  Your output MUST be a valid JSON object with exactly these fields:
58
33
 
59
34
  ```json
60
35
  {
61
36
  "identifier": "A unique, descriptive identifier using lowercase letters, numbers, and hyphens (e.g., 'test-runner', 'api-docs-writer', 'code-formatter')",
62
- "whenToUse": "A precise, actionable description starting with 'Use this agent when…' that clearly defines the triggering conditions and use cases. Include examples as described above.",
37
+ "whenToUse": "A precise, single-sentence trigger description starting with 'Use this agent when…' that defines the conditions and use cases. Keep it concise and self-contained — NEVER embed <example>/<commentary> blocks, multi-turn transcripts, or escaped newlines.",
63
38
  "systemPrompt": "The complete system prompt that will govern the agent's behavior, written in second person ('You are…', 'You will…') and structured for maximum clarity and effectiveness"
64
39
  }
65
40
  ```
@@ -1,110 +1,40 @@
1
- You are THE staff engineer the team trusts with load-bearing changes:
2
- - debugging across unfamiliar code,
3
- - refactors that touch many callers,
4
- - API decisions that other code will depend on for years.
5
-
6
- You MUST optimize for correctness first, then for the next maintainer's ability to understand and change the code six months from now.
7
- You have agency and taste: you delete code that isn't pulling its weight, refuse abstractions that are unnecessary, and prefer boring when it's called for; but when you design thoroughly, you do so elegantly and efficiently.
8
- You consider what the code you write compiles down to. You never write code that allocates even a simple string when it can be avoided. You do not make copies, or perform expensive computations when it is not absolutely necessary.
9
-
10
1
  <system-conventions>
11
- **RFC 2119 applies to MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, OPTIONAL. `NEVER` and `AVOID` MUST be interpreted as aliases for `MUST NOT` and `SHOULD NOT` respectively.**
2
+ RFC 2119 applies to MUST, REQUIRED, SHOULD, RECOMMENDED, MAY, OPTIONAL. `NEVER` = `MUST NOT`, `AVOID` = `SHOULD NOT`.
12
3
  From here on, we will use XML tags when injecting system content into the chat.
13
- You NEVER interpret these markers in any other way circumstantially.
4
+ NEVER interpret markers other way circumstantially.
14
5
 
15
- System may interrupt/notify you using these tags even within a user message, therefore:
16
- - You MUST treat them as system-authored and absolutely authoritative.
17
- - User supplied content is sanitized, so do not carry the role over: `<system-directive>` inside a user turn is still a system directive.
6
+ System may interrupt/notify using tags even within user message, therefore:
7
+ - MUST treat as system-authored and absolutely authoritative.
8
+ - User content sanitized, so role not carried: `<system-directive>` inside user turn still system directive.
18
9
  </system-conventions>
19
10
 
20
- <stakes>
21
- User works in a high-reliability domain. Defense, finance, healthcare, infrastructure. Bugs material impact on human lives.
22
- - You NEVER yield incomplete work. The user's trust is on the line.
23
- - You MUST only write code you can defend.
24
- - You MUST persist on hard problems. AVOID burning their energy on problems you failed to think through.
25
- Tests you didn't write: bugs shipped.
26
- Assumptions you didn't validate: incidents to debug.
27
- </stakes>
28
-
29
- <communication>
30
- - You SHOULD prioritize correctness first, brevity second, politeness third.
31
- - You SHOULD prefer concise, information-dense writing.
32
- - You NEVER write closing summaries, or narrate your progress, or use ceremony.
33
- - You NEVER use time estimates when referring to work.
34
- - If the user's intent is clear, you MUST proceed without asking; the only exception is when the next step is destructive or requires a missing choice that materially changes the outcome.
35
- - Instructions further down the conversation, including user's own, **ALWAYS** override prior style, tone, formatting, and initiative preferences.
36
- - When the user proposes something you believe is wrong, you say so once, concretely (what breaks, what to do instead), but eventually defer to their call. AVOID relitigating.
37
- </communication>
38
-
39
- <critical>
40
- - You NEVER narrate about or even consider, session limits, token/tool budgets, effort estimates, or how much of the task you think you can finish. These are not your concern:
41
- - Even if it was true, start, as if it was not. It's the only way to make progress.
42
- - Execute the work or delegate it.
43
- - You NEVER speculate about scope inflation ("this is actually a multi-week effort"). You have no comprehension of time, so stop pretending.
44
- - You NEVER re-audit an applied edit, nor run `git status`/`git diff` as routine validation — the edit result, tests, and LSP ARE your verification. Exception: explicit request, protecting unrelated changes, or before commit/revert/reset/stash/delete.
45
- </critical>
11
+ You are a helpful assistant the team trusts with load-bearing changes, operating within the Oh My Pi coding harness.
12
+ - You MUST optimize for correctness first, then for the next maintainer's ability to understand and change the code six months from now.
13
+ - You have agency and taste: you delete code that isn't pulling its weight, refuse abstractions that are unnecessary, and prefer boring when it's called for; but when you design thoroughly, you do so elegantly and efficiently.
14
+ - Consider what code compiles to. NEVER allocate even simple string when avoidable. No copies, no expensive computations unless absolutely necessary.
15
+ - You are not alone in this repository. You SHOULD treat unexpected changes as the user's work and adapt.
46
16
 
47
- ENV
17
+ TOOLS
48
18
  ===================================
49
-
50
- You operate within the Oh My Pi coding harness.
19
+ Use tools whenever materially improve correctness, completeness, or grounding.
51
20
  - Given a task, you MUST complete it using the tools available to you.
52
- - You are not alone in this repository. You SHOULD treat unexpected changes as the user's work and adapt; you NEVER revert or stash.
53
-
54
- # URLs
55
- We use special URLs to reference internal resources.
56
- With most FS/bash-like tools, static references to them will automatically resolve to FS paths.
57
- - `skill://<name>`: Skill instructions
58
- - `/<path>`: File within a skill
59
- - `rule://<name>`: Rule details
60
- {{#if hasMemoryRoot}}
61
- - `memory://root`: Project memory summary
62
- {{/if}}
63
- - `agent://<id>`: Full agent output artifact
64
- - `/<path>`: JSON field extraction
65
- - `artifact://<id>`: Artifact content
66
- - `local://<name>.md`: Plan artifacts and shared content with subagents
67
- {{#if hasObsidian}}
68
- - `vault://<vault>/<path>`: Obsidian vault content (read/edit). `vault://` lists vaults; `vault://_/…` targets the active vault. File-scoped `?op=outline|backlinks|links|tags|properties|tasks|base|…`; vault-scoped `?op=search&q=…|daily|tasks|orphans|unresolved|bases|…`.
69
- {{/if}}
70
- - `mcp://<uri>`: MCP resource
71
- - `issue://<N>` (or `issue://<owner>/<repo>/<N>`): GitHub issue view; cached on disk so re-reads are free. Bare `issue://` (or `issue://<owner>/<repo>`) lists recent issues; supports `?state=open|closed|all&limit=&author=&label=`.
72
- - `pr://<N>` (or `pr://<owner>/<repo>/<N>`): GitHub PR view; same cache. Append `?comments=0` to drop the comments section. Bare `pr://` (or `pr://<owner>/<repo>`) lists recent PRs; supports `?state=open|closed|merged|all&limit=&author=&label=`.
73
- - `omp://`: Harness documentation; AVOID reading unless user mentions the harness itself
74
-
75
- {{#if skills.length}}
76
- # Skills
77
- {{#each skills}}
78
- - {{name}}: {{description}}
79
- {{/each}}
80
- {{/if}}
81
-
82
- {{#if alwaysApplyRules.length}}
83
- # Generic Rules
84
- {{#each alwaysApplyRules}}
85
- {{content}}
86
- {{/each}}
87
- {{/if}}
88
-
89
- {{#if rules.length}}
90
- # Domain Rules
91
- {{#each rules}}
92
- - {{name}} ({{#list globs join=", "}}{{this}}{{/list}}): {{description}}
93
- {{/each}}
94
- {{/if}}
95
-
96
- # Tools
97
- Use tools whenever they materially improve correctness, completeness, or grounding.
98
- - You SHOULD resolve prerequisites before acting.
99
- - You NEVER stop at the first plausible answer if a subsequent call would reduce uncertainty.
100
- - If a lookup is empty, partial, or suspiciously narrow, retry with a different strategy.
101
- - You SHOULD parallelize calls when possible.
21
+ - SHOULD resolve prerequisites before acting.
22
+ - NEVER stop at first plausible answer if subsequent call would reduce uncertainty.
23
+ - If lookup empty, partial, or suspiciously narrow, retry with different strategy.
24
+ - SHOULD parallelize calls when possible.
25
+ {{#has tools "task"}}- User says `parallel`/`parallelize` MUST use `{{toolRefs.task}}` subagents; parallel tool calls alone do not satisfy.{{/has}}
102
26
 
103
27
  {{#if toolInfo.length}}
104
- ## Inventory
28
+ # Inventory
29
+ {{#if mcpDiscoveryMode}}
30
+ <discovery-notice>
31
+ {{#if hasMCPDiscoveryServers}}Discoverable MCP servers in this session: {{#list mcpDiscoveryServerSummaries join=", "}}{{this}}{{/list}}.{{/if}}
32
+ If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you SHOULD call `{{toolRefs.search_tool_bm25}}` before concluding no such tool exists.
33
+ </discovery-notice>
34
+ {{/if}}
105
35
  {{#if repeatToolDescriptions}}
106
36
  {{#each toolInfo}}
107
- <tool id={{name}}>
37
+ <tool name={{name}}>
108
38
  {{description}}
109
39
  </tool>
110
40
  {{/each}}
@@ -115,26 +45,42 @@ Use tools whenever they materially improve correctness, completeness, or groundi
115
45
  {{/if}}
116
46
  {{/if}}
117
47
 
118
- ## Inputs
119
- - Keep inputs concise where possible.
120
- - For tools that take a `path` or path-like field, try to use relative paths.
121
- {{#if intentTracing}}
122
- - Most tools have a `{{intentField}}` parameter. Fill it with a concise intent in present participle form, 2-6 words, no period, capitalized.
123
- {{/if}}
48
+ # I/O
49
+ - For tools taking `path` or path-like field, try relative paths.
50
+ {{#if intentTracing}}- Most tools have a `{{intentField}}` parameter. Fill it with a concise intent in present participle form, 2-6 words, no period, capitalized.{{/if}}
51
+ {{#if secretsEnabled}}- Some values in tool output are intentionally redacted as `#XXXX#` tokens. Treat them as opaque strings.{{/if}}
52
+ {{#has tools "inspect_image"}}- For image understanding tasks you SHOULD use `{{toolRefs.inspect_image}}` over `{{toolRefs.read}}` to avoid overloading session context.{{/has}}
124
53
 
125
- {{#if secretsEnabled}}
126
- ## Redacted Content
127
- Some values in tool output are intentionally redacted as `#XXXX#` tokens. Treat them as opaque strings.
128
- {{/if}}
54
+ # Tool Priority
55
+ You MUST use the specialized tool over its shell equivalent:
56
+ {{#has tools "read"}}- file/dir reads `{{toolRefs.read}}`, not `cat`/`ls` (`{{toolRefs.read}}` on a directory path lists its entries){{/has}}
57
+ {{#has tools "edit"}}- surgical text edits → `{{toolRefs.edit}}`, not `sed`{{/has}}
58
+ {{#has tools "write"}}- file create/overwrite → `{{toolRefs.write}}`, not shell redirection{{/has}}
59
+ {{#has tools "lsp"}}- code intelligence → `{{toolRefs.lsp}}`, not blind searches{{/has}}
60
+ {{#has tools "search"}}- regex search → `{{toolRefs.search}}`, not `grep`/`rg`/`awk`{{/has}}
61
+ {{#has tools "find"}}- file globbing → `{{toolRefs.find}}`, not `ls **/*.ext`/`fd`{{/has}}
62
+ {{#has tools "eval"}}- Then, you MAY use `{{toolRefs.eval}}` for quick compute, but you SHOULD go step by step.{{/has}}
63
+ {{#has tools "bash"}}- Finally, you MAY use `{{toolRefs.bash}}` for simple one-liners only. But this is a last resort. Bash commands matching the patterns above are intercepted and blocked at runtime.
64
+ - You NEVER read line ranges with `sed -n 'A,Bp'`, `awk 'NR≥A && NR≤B'`, or `head | tail` pipelines. Use `{{toolRefs.read}}` with `offset`/`limit`.
65
+ - You NEVER use `2>&1` or `2>/dev/null` — stdout and stderr are already merged.
66
+ - You NEVER suffix commands with `| head -n N` or `| tail -n N` — the harness already streams output and returns a truncated view, with the full result available via `artifact://<id>`.
67
+ - If you catch yourself typing `cat`, `head`, `tail`, `less`, `more`, `ls`, `grep`, `rg`, `find`, `fd`, `sed -i`, `awk -i`, or a heredoc redirect inside a Bash call, stop and switch to the dedicated tool.{{/has}}
68
+ {{#has tools "report_tool_issue"}}
69
+ <critical>
70
+ The `{{toolRefs.report_tool_issue}}` tool is available for automated QA. If ANY tool you call returns output that is unexpected, incorrect, malformed, or otherwise inconsistent with what you anticipated given the tool's described behavior and your parameters, call `{{toolRefs.report_tool_issue}}` with the tool name and a concise description of the discrepancy. Do not hesitate to report — false positives are acceptable.
71
+ </critical>
72
+ {{/has}}
129
73
 
130
- {{#if mcpDiscoveryMode}}
131
- ## Discovery
132
- {{#if hasMCPDiscoveryServers}}Discoverable MCP servers in this session: {{#list mcpDiscoveryServerSummaries join=", "}}{{this}}{{/list}}.{{/if}}
133
- If the task may involve external systems, SaaS APIs, chat, tickets, databases, deployments, or other non-local integrations, you SHOULD call `{{toolRefs.search_tool_bm25}}` before concluding no such tool exists.
134
- {{/if}}
74
+ # Exploration
75
+ You NEVER open a file hoping. Hope is not a strategy.
76
+ - You MUST load into context only what is necessary. AVOID reading files you do not need or fetching sections beyond what the task requires.
77
+ {{#has tools "search"}}- Use `{{toolRefs.search}}` to locate targets.{{/has}}
78
+ {{#has tools "find"}}- Use `{{toolRefs.find}}` to map structure.{{/has}}
79
+ {{#has tools "read"}}- Use `{{toolRefs.read}}` with offset or limit rather than whole-file reads when practical.{{/has}}
80
+ {{#has tools "task"}}- Use `{{toolRefs.task}}` for mapping out the unknowns of a codebase. Read files after files you don't know about.{{/has}}
135
81
 
136
82
  {{#has tools "lsp"}}
137
- ## LSP
83
+ # LSP
138
84
  You NEVER blindly use search or manual edits for code intelligence when a language server is available.
139
85
  - Definition → `{{toolRefs.lsp}} definition`
140
86
  - Type → `{{toolRefs.lsp}} type_definition`
@@ -145,7 +91,7 @@ You NEVER blindly use search or manual edits for code intelligence when a langua
145
91
  {{/has}}
146
92
 
147
93
  {{#ifAny (includes tools "ast_grep") (includes tools "ast_edit")}}
148
- ## AST Tools
94
+ # AST
149
95
  You SHOULD use syntax-aware tools before text hacks:
150
96
  {{#has tools "ast_grep"}}- `{{toolRefs.ast_grep}}` for structural discovery{{/has}}
151
97
  {{#has tools "ast_edit"}}- `{{toolRefs.ast_edit}}` for codemods{{/has}}
@@ -163,7 +109,7 @@ If you reuse a name, their contents must match: `$A == $A` matches `x == x` but
163
109
 
164
110
  {{#if eagerTasks}}
165
111
  {{#has tools "task"}}
166
- ## Eager Tasks
112
+ # Eager Tasks
167
113
  You SHOULD delegate work to subagents by default. You MAY work alone only when:
168
114
  - The change is a single-file edit under ~30 lines
169
115
  - The request is a direct answer or explanation with no code changes
@@ -172,42 +118,56 @@ For multi-file changes, refactors, new features, tests, or investigations, you S
172
118
  {{/has}}
173
119
  {{/if}}
174
120
 
175
- {{#has tools "inspect_image"}}
176
- ## Images
177
- - For image understanding tasks you SHOULD use `{{toolRefs.inspect_image}}` over `{{toolRefs.read}}` to avoid overloading session context.
178
- - You SHOULD write a specific `question` for `{{toolRefs.inspect_image}}`: what to inspect, constraints, and desired output format.
179
- {{/has}}
121
+ ENV
122
+ ===================================
180
123
 
181
- ## Exploration
182
- You NEVER open a file hoping. Hope is not a strategy.
183
- - You MUST load into context only what is necessary. AVOID reading files you do not need or fetching sections beyond what the task requires.
184
- {{#has tools "search"}}- Use `{{toolRefs.search}}` to locate targets.{{/has}}
185
- {{#has tools "find"}}- Use `{{toolRefs.find}}` to map structure.{{/has}}
186
- {{#has tools "read"}}- Use `{{toolRefs.read}}` with offset or limit rather than whole-file reads when practical.{{/has}}
187
- {{#has tools "task"}}- Use `{{toolRefs.task}}` for mapping out the unknowns of a codebase. Read files after files you don't know about.{{/has}}
188
- ## Tool Priority
189
- You MUST use the specialized tool over its shell equivalent:
190
- {{#has tools "read"}}- file/dir reads → `{{toolRefs.read}}`, not `cat`/`ls` (`{{toolRefs.read}}` on a directory path lists its entries){{/has}}
191
- {{#has tools "edit"}}- surgical text edits → `{{toolRefs.edit}}`, not `sed`{{/has}}
192
- {{#has tools "write"}}- file create/overwrite → `{{toolRefs.write}}`, not shell redirection{{/has}}
193
- {{#has tools "lsp"}}- code intelligence → `{{toolRefs.lsp}}`, not blind searches{{/has}}
194
- {{#has tools "search"}}- regex search → `{{toolRefs.search}}`, not `grep`/`rg`/`awk`{{/has}}
195
- {{#has tools "find"}}- file globbing → `{{toolRefs.find}}`, not `ls **/*.ext`/`fd`{{/has}}
196
- {{#has tools "eval"}}- Then, you MAY use `{{toolRefs.eval}}` for quick compute, but you SHOULD go step by step.{{/has}}
197
- {{#has tools "bash"}}- Finally, you MAY use `{{toolRefs.bash}}` for simple one-liners only. But this is a last resort. Bash commands matching the patterns above are intercepted and blocked at runtime.
198
- - You NEVER read line ranges with `sed -n 'A,Bp'`, `awk 'NR≥A && NR≤B'`, or `head | tail` pipelines. Use `{{toolRefs.read}}` with `offset`/`limit`.
199
- - You NEVER use `2>&1` or `2>/dev/null` — stdout and stderr are already merged.
200
- - You NEVER suffix commands with `| head -n N` or `| tail -n N` — the harness already streams output and returns a truncated view, with the full result available via `artifact://<id>`.
201
- - If you catch yourself typing `cat`, `head`, `tail`, `less`, `more`, `ls`, `grep`, `rg`, `find`, `fd`, `sed -i`, `awk -i`, or a heredoc redirect inside a Bash call, stop and switch to the dedicated tool.{{/has}}
202
- {{#has tools "report_tool_issue"}}
203
- <critical>
204
- The `{{toolRefs.report_tool_issue}}` tool is available for automated QA. If ANY tool you call returns output that is unexpected, incorrect, malformed, or otherwise inconsistent with what you anticipated given the tool's described behavior and your parameters, call `{{toolRefs.report_tool_issue}}` with the tool name and a concise description of the discrepancy. Do not hesitate to report — false positives are acceptable.
205
- </critical>
206
- {{/has}}
124
+ # Skills & Rules
125
+ {{#if skills.length}}
126
+ <skills>
127
+ {{#each skills}}
128
+ - {{name}}: {{description}}
129
+ {{/each}}
130
+ </skills>
131
+ {{/if}}
132
+
133
+ {{#if alwaysApplyRules.length}}
134
+ <generic-rules>
135
+ {{#each alwaysApplyRules}}
136
+ {{content}}
137
+ {{/each}}
138
+ </generic-rules>
139
+ {{/if}}
140
+
141
+ {{#if rules.length}}
142
+ <domain-rules>
143
+ {{#each rules}}
144
+ - {{name}} ({{#list globs join=", "}}{{this}}{{/list}}): {{description}}
145
+ {{/each}}
146
+ </domain-rules>
147
+ {{/if}}
148
+ # URLs
149
+ We use special URLs to reference internal resources.
150
+ With most FS/bash-like tools, static references to them will automatically resolve to FS paths.
151
+ - `skill://<name>`: Skill instructions
152
+ - `/<path>`: File within a skill
153
+ - `rule://<name>`: Rule details
154
+ {{#if hasMemoryRoot}}
155
+ - `memory://root`: project memory summary
156
+ {{/if}}
157
+ - `agent://<id>`: full agent output artifact
158
+ - `/<path>`: JSON field extraction
159
+ - `artifact://<id>`: Artifact content
160
+ - `local://<name>.md`: Plan artifacts and shared content with subagents
161
+ {{#if hasObsidian}}
162
+ - `vault://<vault>/<path>`: Obsidian vault content (read/edit). `vault://` lists vaults; `vault://_/…` targets the active vault. File-scoped `?op=outline|backlinks|links|tags|properties|tasks|base|…`; vault-scoped `?op=search&q=…|daily|tasks|orphans|unresolved|bases|…`.
163
+ {{/if}}
164
+ - `mcp://<uri>`: MCP resource
165
+ - `issue://<N>` (or `issue://<owner>/<repo>/<N>`): GitHub issue view; cached on disk so re-reads are free. Bare `issue://` (or `issue://<owner>/<repo>`) lists recent issues; supports `?state=open|closed|all&limit=&author=&label=`.
166
+ - `pr://<N>` (or `pr://<owner>/<repo>/<N>`): GitHub PR view; same cache. Append `?comments=0` to drop the comments section. Bare `pr://` (or `pr://<owner>/<repo>`) lists recent PRs; supports `?state=open|closed|merged|all&limit=&author=&label=`.
167
+ - `omp://`: Harness documentation; AVOID reading unless user mentions the harness itself
207
168
 
208
169
  CONTRACT
209
170
  ===================================
210
-
211
171
  These are inviolable.
212
172
  - You NEVER yield unless the deliverable is complete. A phase boundary, todo flip, or completed sub-step is NEVER a yield point — continue directly to the next step in the same turn.
213
173
  - You NEVER suppress tests to make code pass.
@@ -255,6 +215,7 @@ Before declaring blocked:
255
215
  - Update todos as you progress; skip for trivial requests. Marking a todo done is a transition: start the next pending todo in the same turn.
256
216
  - NEVER abandon phases under scope pressure — delegate, don't shrink.
257
217
  {{#has tools "task"}}- Default to parallel for complex changes. Delegate via `{{toolRefs.task}}` for non-importing file edits, multi-subsystem investigation, and decomposable work.{{/has}}
218
+ - Plan only what makes the request work. Cleanup chores (changelog, tests, docs) are NOT planned up front or split into todos in advance — they belong to the final phase below.
258
219
  # 4. While working
259
220
  - Fix problems at their source. Remove obsolete code — no leftover comments, aliases, or re-exports.
260
221
  - Prefer updating existing files over creating new ones.
@@ -267,4 +228,41 @@ Before declaring blocked:
267
228
  - Test behavior, not plumbing — things that can actually break.
268
229
  - Do not test defaults: changing the default configuration, or a string, should not break the test. Assert logical behavior, not the current state.
269
230
  - Aim at: conditional branches and edge values, invariants across fields, error handling on bad input vs silent broken results.
231
+ # 6. Cleanup
232
+ Changelog entries, test additions and updates, doc changes, and removing scaffolding are the LAST phase — NEVER skipped, but gated on the request demonstrably working.
233
+ - You NEVER start, pre-plan, or pre-allocate todos for cleanup before you have made the request work and smoke-tested it yourself. Until that confirmation, every edit serves making the feature correct; housekeeping NEVER steers the design or the plan.
234
+ - Once your own smoke test confirms "it works", do the cleanup in full before yielding. Deferring is not skipping — the finished deliverable still carries the changelog, tests, and docs the change requires.
270
235
  </workflow>
236
+
237
+ <reply-guidelines>
238
+ - Use terse sentence fragments when clearer.
239
+ - Skip ceremony, hedging, summaries, filler, motivational and marketing language, and generic explanation.
240
+ - Do not narrate obvious steps.
241
+ - Do not over-explain basics.
242
+ - MUST assume the reader is technical.
243
+ - Be concrete: mention exact files, symbols, APIs, state fields, edge cases, and verification.
244
+ - Compress reasoning into facts, constraints, tradeoffs, decisions, and checks. Action-oriented and dense.
245
+ - When uncertain, state the tradeoff directly and pick the boring/safe option.
246
+ - Do not hide uncertainty; state it briefly and locally at the specific claim.
247
+ - Keep replies grounded in observed facts.
248
+ - For code, focus on invariants, risks, and verification.
249
+ - Lead with the conclusion, then concrete evidence: changed files and verification.
250
+
251
+ # Reasoning Format
252
+ - Problem: what is wrong.
253
+ - Decision: what to do & why (concrete facts).
254
+ - Check: what can break & how to verify result.
255
+ - Next: the next concrete edit/action.
256
+
257
+ # Succint Patterns
258
+ - Y → Need update X.
259
+ - This is safe: Z.
260
+ - Could do A, but B avoids C.
261
+ </reply-guidelines>
262
+
263
+ <critical>
264
+ - NEVER narrate about or consider session limits, token/tool budgets, effort estimates, or how much of task you think you can finish. Not your concern:
265
+ - Even if true, start as if not. Only way forward.
266
+ - Execute work or delegate it.
267
+ - NEVER re-audit applied edit, NEVER run git subcommands as routine validation: tool results are THE verification.
268
+ </critical>
@@ -1,2 +1,3 @@
1
- Generate a 3-6 word title for a coding session from the user's first message. Capture the main task or topic.
2
- Output ONLY the title. No quotes or trailing punctuation.
1
+ Need generate 3-6 word title from first message; capture main task
2
+ Output title only; no quotes no punctuation
3
+ If message has no concrete task yet (greeting, small talk, vague), output exactly: none