zenox 1.4.2 → 1.5.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
@@ -25,6 +25,7 @@ Zenox supercharges [OpenCode](https://opencode.ai) with specialized AI agents th
25
25
  - **Keyword Triggers** — `ultrawork`, `deep research`, `explore codebase`
26
26
  - **Session History** — Query past sessions to learn from previous work
27
27
  - **Code Intelligence** — Search symbols via LSP
28
+ - **Project Guidelines Auto-Update** — Automatically keeps AGENTS.md and CLAUDE.md up-to-date
28
29
  - **Todo Continuation** — Auto-reminds when tasks are incomplete
29
30
  - **Auto-Updates** — Toast notification when new version available
30
31
 
@@ -165,6 +166,43 @@ Zenox automatically reminds you to continue working when:
165
166
 
166
167
  This keeps you on track without manual intervention. The agent will be prompted to continue until all todos are complete or blocked.
167
168
 
169
+ ## Project Guidelines Auto-Update
170
+
171
+ Zenox automatically keeps your `AGENTS.md` and `CLAUDE.md` files up-to-date with important decisions, patterns, and conventions.
172
+
173
+ ### The Problem
174
+
175
+ Developers forget to update documentation. Important decisions get lost. Team members repeat the same questions. Next session, the agent has no context.
176
+
177
+ ### The Solution
178
+
179
+ Zenox detects important decisions and automatically documents them:
180
+
181
+ ```
182
+ You: "In this project, always use Zustand for state management"
183
+ → Agent checks AGENTS.md — not documented yet
184
+ → Agent saves: "- State Management: Use Zustand, not Redux"
185
+ → Future sessions automatically know this
186
+ ```
187
+
188
+ ### What Gets Documented
189
+
190
+ | Trigger | Example |
191
+ |---------|---------|
192
+ | User decision | "Always use Tailwind", "We use this API pattern" |
193
+ | Architecture choice | Agent decides between approaches after analysis |
194
+ | Reusable code | Agent creates a utility worth reusing |
195
+ | Convention discovered | Agent notices consistent patterns in codebase |
196
+
197
+ ### How It Works
198
+
199
+ 1. Agent recognizes something important
200
+ 2. Reads `AGENTS.md` / `CLAUDE.md` to check if already documented
201
+ 3. If not there → calls `save_project_guideline` to add it
202
+ 4. Both files get updated (or `AGENTS.md` created if neither exists)
203
+
204
+ **Zero manual work** — your project documentation stays current automatically.
205
+
168
206
  ## Configuration
169
207
 
170
208
  ### Custom Models
@@ -5,4 +5,4 @@
5
5
  */
6
6
  export { BackgroundManager } from "./manager";
7
7
  export { createBackgroundTools, type BackgroundTools } from "./tools";
8
- export type { BackgroundTask, TaskStatus, LaunchInput, CompletionNotification, } from "./types";
8
+ export type { BackgroundTask, TaskStatus, LaunchInput, CompletionNotification, ParentModel, } from "./types";
@@ -3,6 +3,10 @@
3
3
  * Minimal interfaces for fire-and-forget parallel agent execution
4
4
  */
5
5
  export type TaskStatus = "running" | "completed" | "failed" | "cancelled";
6
+ export interface ParentModel {
7
+ providerID: string;
8
+ modelID: string;
9
+ }
6
10
  export interface BackgroundTask {
7
11
  id: string;
8
12
  sessionID: string;
@@ -14,6 +18,7 @@ export interface BackgroundTask {
14
18
  completedAt?: Date;
15
19
  error?: string;
16
20
  parentAgent?: string;
21
+ parentModel?: ParentModel;
17
22
  }
18
23
  export interface LaunchInput {
19
24
  agent: string;
@@ -21,6 +26,7 @@ export interface LaunchInput {
21
26
  description: string;
22
27
  parentSessionID: string;
23
28
  parentAgent?: string;
29
+ parentModel?: ParentModel;
24
30
  }
25
31
  export interface CompletionNotification {
26
32
  allComplete: boolean;
@@ -28,4 +34,5 @@ export interface CompletionNotification {
28
34
  completedTasks: BackgroundTask[];
29
35
  runningCount: number;
30
36
  parentAgent?: string;
37
+ parentModel?: ParentModel;
31
38
  }
package/dist/index.js CHANGED
@@ -822,6 +822,51 @@ The system automatically reminds you if you go idle with incomplete tasks.
822
822
  - You have pending or in-progress todos
823
823
  - The session goes idle
824
824
  - There's been sufficient time since the last reminder
825
+
826
+ ---
827
+
828
+ ## Project Guidelines Auto-Documentation
829
+
830
+ You have \`save_project_guideline\` to keep AGENTS.md and CLAUDE.md automatically updated.
831
+
832
+ ### When to Use
833
+
834
+ | Trigger | Example |
835
+ |---------|---------|
836
+ | User states a decision | "Always use Zustand", "We use Tailwind here" |
837
+ | You create reusable code | A utility function, hook, or pattern worth reusing |
838
+ | Architecture decision made | After analyzing options and choosing an approach |
839
+ | User corrects your approach | "No, do it this way instead" |
840
+ | Convention discovered | You notice a consistent pattern in the codebase |
841
+
842
+ ### How to Use
843
+
844
+ 1. **Read first**: Check AGENTS.md and CLAUDE.md to see if the info already exists
845
+ 2. **If not there**: Call \`save_project_guideline({ content: "..." })\`
846
+ 3. **The tool**: Appends to both files (or creates AGENTS.md if neither exists)
847
+
848
+ ### Example
849
+
850
+ \`\`\`
851
+ // User says: "In this project, always use Zustand for state"
852
+ // 1. Read AGENTS.md - check if Zustand is mentioned
853
+ // 2. If not mentioned:
854
+ save_project_guideline({ content: "- State Management: Use Zustand, not Redux" })
855
+ \`\`\`
856
+
857
+ ### What to Document
858
+
859
+ - Technology choices (frameworks, libraries, tools)
860
+ - Code patterns (how to structure components, API calls, etc.)
861
+ - Reusable utilities you create (hooks, helpers, formatters)
862
+ - Conventions (naming, folder structure, coding style)
863
+ - Important decisions that affect future work
864
+
865
+ ### What NOT to Document
866
+
867
+ - One-off decisions ("use blue for this button")
868
+ - Things obvious from the code itself
869
+ - Temporary workarounds
825
870
  `;
826
871
  function getOrchestrationPrompt(agent) {
827
872
  switch (agent) {
@@ -835,18 +880,26 @@ function getOrchestrationPrompt(agent) {
835
880
  }
836
881
 
837
882
  // src/orchestration/session-agent-tracker.ts
838
- var sessionAgentMap = new Map;
839
- function setSessionAgent(sessionID, agent) {
840
- if (agent) {
841
- sessionAgentMap.set(sessionID, agent);
842
- }
883
+ var sessionContextMap = new Map;
884
+ function setSessionContext(sessionID, context) {
885
+ const existing = sessionContextMap.get(sessionID) ?? {};
886
+ sessionContextMap.set(sessionID, {
887
+ agent: context.agent ?? existing.agent,
888
+ model: context.model ?? existing.model
889
+ });
890
+ }
891
+ function getSessionContext(sessionID) {
892
+ return sessionContextMap.get(sessionID);
843
893
  }
844
894
  function getSessionAgent(sessionID) {
845
- return sessionAgentMap.get(sessionID);
895
+ return sessionContextMap.get(sessionID)?.agent;
896
+ }
897
+ function getSessionModel(sessionID) {
898
+ return sessionContextMap.get(sessionID)?.model;
846
899
  }
847
900
  function clearSessionAgent(sessionID) {
848
901
  if (sessionID) {
849
- sessionAgentMap.delete(sessionID);
902
+ sessionContextMap.delete(sessionID);
850
903
  }
851
904
  }
852
905
  function getOrchestrationAgentType(agent) {
@@ -4995,7 +5048,8 @@ class BackgroundManager {
4995
5048
  prompt: input.prompt,
4996
5049
  status: "running",
4997
5050
  startedAt: new Date,
4998
- parentAgent: input.parentAgent
5051
+ parentAgent: input.parentAgent,
5052
+ parentModel: input.parentModel
4999
5053
  };
5000
5054
  this.tasks.set(task.id, task);
5001
5055
  if (this.toastManager) {
@@ -5134,12 +5188,14 @@ ${runningTasks.length} task(s) still running. Continue working.
5134
5188
  </system-reminder>`;
5135
5189
  }
5136
5190
  const parentAgent = completedTasks[0]?.parentAgent;
5191
+ const parentModel = completedTasks[0]?.parentModel;
5137
5192
  return {
5138
5193
  allComplete,
5139
5194
  message,
5140
5195
  completedTasks,
5141
5196
  runningCount: runningTasks.length,
5142
- parentAgent
5197
+ parentAgent,
5198
+ parentModel
5143
5199
  };
5144
5200
  }
5145
5201
  listActiveTasks() {
@@ -17490,12 +17546,14 @@ Use for independent research tasks that benefit from parallelism.`,
17490
17546
  },
17491
17547
  async execute(args, context) {
17492
17548
  try {
17549
+ const parentModel = getSessionModel(context.sessionID);
17493
17550
  const task = await manager.launch(client, {
17494
17551
  agent: args.agent,
17495
17552
  description: args.description,
17496
17553
  prompt: args.prompt,
17497
17554
  parentSessionID: context.sessionID,
17498
- parentAgent: context.agent
17555
+ parentAgent: context.agent,
17556
+ parentModel
17499
17557
  });
17500
17558
  const activeTasks = manager.listActiveTasks();
17501
17559
  return `Background task launched successfully.
@@ -17930,12 +17988,15 @@ Current incomplete tasks:
17930
17988
  ${todoList}
17931
17989
 
17932
17990
  ${statusLine}`;
17933
- const sendPrompt = async (omitAgent = false) => {
17991
+ const sessionContext = getSessionContext(sessionID);
17992
+ const model = sessionContext?.model;
17993
+ const sendPrompt = async (omitContext = false) => {
17934
17994
  await ctx.client.session.prompt({
17935
17995
  path: { id: sessionID },
17936
17996
  body: {
17937
17997
  noReply: false,
17938
- ...omitAgent || !agent ? {} : { agent },
17998
+ ...omitContext || !agent ? {} : { agent },
17999
+ ...omitContext || !model ? {} : { model },
17939
18000
  parts: [{ type: "text", text: prompt }]
17940
18001
  }
17941
18002
  });
@@ -17944,7 +18005,7 @@ ${statusLine}`;
17944
18005
  await sendPrompt();
17945
18006
  } catch (err) {
17946
18007
  const errorMsg = err instanceof Error ? err.message : String(err);
17947
- if (errorMsg.includes("agent") || errorMsg.includes("undefined")) {
18008
+ if (errorMsg.includes("agent") || errorMsg.includes("model") || errorMsg.includes("undefined")) {
17948
18009
  try {
17949
18010
  await sendPrompt(true);
17950
18011
  } catch {
@@ -18281,6 +18342,87 @@ Shows which LSP servers are running and their status.`,
18281
18342
  lsp_status: lspStatus
18282
18343
  };
18283
18344
  }
18345
+ // src/tools/project-guidelines/tools.ts
18346
+ import * as fs2 from "fs/promises";
18347
+ import * as path2 from "path";
18348
+ var GUIDELINE_FILES = ["AGENTS.md", "CLAUDE.md"];
18349
+ async function fileExists(filePath) {
18350
+ try {
18351
+ await fs2.access(filePath);
18352
+ return true;
18353
+ } catch {
18354
+ return false;
18355
+ }
18356
+ }
18357
+ async function appendToFile(filePath, content) {
18358
+ const exists = await fileExists(filePath);
18359
+ if (exists) {
18360
+ const existing = await fs2.readFile(filePath, "utf-8");
18361
+ const separator = existing.endsWith(`
18362
+ `) ? "" : `
18363
+ `;
18364
+ await fs2.writeFile(filePath, existing + separator + content + `
18365
+ `);
18366
+ } else {
18367
+ await fs2.writeFile(filePath, content + `
18368
+ `);
18369
+ }
18370
+ }
18371
+ function createProjectGuidelinesTools(projectDir) {
18372
+ const saveProjectGuideline = tool({
18373
+ description: `Save important project decisions, patterns, or conventions to AGENTS.md and CLAUDE.md.
18374
+ Use this to document:
18375
+ - Important decisions (technology choices, architecture decisions)
18376
+ - Reusable code patterns or utilities you created
18377
+ - Conventions discovered or agreed upon
18378
+ - Guidelines that should persist across sessions
18379
+
18380
+ IMPORTANT: Before calling this tool, read AGENTS.md and CLAUDE.md first to check if the information already exists. Only call this tool if the guideline is NOT already documented.
18381
+
18382
+ The tool appends to both files if they exist, or creates AGENTS.md if neither exists.`,
18383
+ args: {
18384
+ content: tool.schema.string().describe("The guideline, decision, or pattern to document")
18385
+ },
18386
+ async execute(args) {
18387
+ try {
18388
+ const content = args.content.trim();
18389
+ if (!content) {
18390
+ return "Error: Content cannot be empty";
18391
+ }
18392
+ const updatedFiles = [];
18393
+ let createdFile = false;
18394
+ const existingFiles = [];
18395
+ for (const fileName of GUIDELINE_FILES) {
18396
+ const filePath = path2.join(projectDir, fileName);
18397
+ if (await fileExists(filePath)) {
18398
+ existingFiles.push(fileName);
18399
+ }
18400
+ }
18401
+ if (existingFiles.length === 0) {
18402
+ const agentsPath = path2.join(projectDir, "AGENTS.md");
18403
+ await appendToFile(agentsPath, content);
18404
+ updatedFiles.push("AGENTS.md");
18405
+ createdFile = true;
18406
+ } else {
18407
+ for (const fileName of existingFiles) {
18408
+ const filePath = path2.join(projectDir, fileName);
18409
+ await appendToFile(filePath, content);
18410
+ updatedFiles.push(fileName);
18411
+ }
18412
+ }
18413
+ const fileList = updatedFiles.join(" and ");
18414
+ const action = createdFile ? "Created" : "Updated";
18415
+ return `${action} ${fileList} with: "${content.substring(0, 100)}${content.length > 100 ? "..." : ""}"`;
18416
+ } catch (err) {
18417
+ const errorMsg = err instanceof Error ? err.message : "Unknown error";
18418
+ return `Failed to save guideline: ${errorMsg}`;
18419
+ }
18420
+ }
18421
+ });
18422
+ return {
18423
+ save_project_guideline: saveProjectGuideline
18424
+ };
18425
+ }
18284
18426
  // src/shared/agent-variant.ts
18285
18427
  function resolveAgentVariant(config2, agentName) {
18286
18428
  if (!agentName)
@@ -18334,6 +18476,7 @@ var ZenoxPlugin = async (ctx) => {
18334
18476
  const todoEnforcerHook = createTodoEnforcerHook(ctx);
18335
18477
  const sessionTools = createSessionTools(ctx.client);
18336
18478
  const codeIntelligenceTools = createCodeIntelligenceTools(ctx.client);
18479
+ const projectGuidelinesTools = createProjectGuidelinesTools(ctx.directory);
18337
18480
  const firstMessageVariantGate = createFirstMessageVariantGate();
18338
18481
  const applyModelOverride = (agentName, baseAgent) => {
18339
18482
  const override = pluginConfig.agents?.[agentName];
@@ -18346,10 +18489,11 @@ var ZenoxPlugin = async (ctx) => {
18346
18489
  tool: {
18347
18490
  ...backgroundTools,
18348
18491
  ...sessionTools,
18349
- ...codeIntelligenceTools
18492
+ ...codeIntelligenceTools,
18493
+ ...projectGuidelinesTools
18350
18494
  },
18351
18495
  "chat.message": async (input, output) => {
18352
- setSessionAgent(input.sessionID, input.agent);
18496
+ setSessionContext(input.sessionID, { agent: input.agent, model: input.model });
18353
18497
  const message = output.message;
18354
18498
  if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
18355
18499
  const variant = resolveAgentVariant(pluginConfig, input.agent);
@@ -18402,19 +18546,20 @@ var ZenoxPlugin = async (ctx) => {
18402
18546
  if (notification) {
18403
18547
  const mainSessionID = backgroundManager.getMainSession();
18404
18548
  if (mainSessionID) {
18405
- const sendNotification = async (omitAgent = false) => {
18549
+ const sendNotification = async (omitContext = false) => {
18406
18550
  try {
18407
18551
  await ctx.client.session.prompt({
18408
18552
  path: { id: mainSessionID },
18409
18553
  body: {
18410
18554
  noReply: !notification.allComplete,
18411
- ...omitAgent ? {} : { agent: notification.parentAgent },
18555
+ ...omitContext ? {} : { agent: notification.parentAgent },
18556
+ ...omitContext ? {} : { model: notification.parentModel },
18412
18557
  parts: [{ type: "text", text: notification.message }]
18413
18558
  }
18414
18559
  });
18415
18560
  } catch (err) {
18416
18561
  const errorMsg = err instanceof Error ? err.message : String(err);
18417
- if (!omitAgent && (errorMsg.includes("agent.name") || errorMsg.includes("undefined"))) {
18562
+ if (!omitContext && (errorMsg.includes("agent") || errorMsg.includes("model") || errorMsg.includes("undefined"))) {
18418
18563
  return sendNotification(true);
18419
18564
  }
18420
18565
  }
@@ -2,5 +2,5 @@
2
2
  * Orchestration prompt to inject into Build and Plan agents.
3
3
  * This teaches the primary agents how to delegate to specialized subagents using the Task tool.
4
4
  */
5
- export declare const ORCHESTRATION_PROMPT = "\n\n---\n\n## Sub-Agent Delegation\n\nYou have specialized subagents. Use the **Task tool** to delegate work proactively.\n\n### Available Agents\n\n| Agent | Use For | subagent_type |\n|-------|---------|---------------|\n| **Explorer** | Codebase grep - fast pattern matching, \"Where is X?\" | `explorer` |\n| **Librarian** | External grep - docs, GitHub, OSS examples | `librarian` |\n| **Oracle** | Strategic advisor - architecture, debugging, decisions | `oracle` |\n| **UI Planner** | Designer-developer - visual design, CSS, animations | `ui-planner` |\n\n### Quick Rule: Background vs Synchronous\n\n| Agent | Default Execution | Why |\n|-------|-------------------|-----|\n| Explorer | `background_task` | It's codebase grep - fire and continue |\n| Librarian | `background_task` | It's external grep - fire and continue |\n| Oracle | `Task` (sync) | Need strategic answer before proceeding |\n| UI Planner | `Task` (sync) | Implements changes, needs write access |\n\n**Mental Model**: Explorer & Librarian = **grep commands**. You don't wait for grep, you fire it and continue thinking.\n\n### When to Delegate (Fire Immediately)\n\n| Trigger | subagent_type | Why |\n|---------|---------------|-----|\n| \"Where is X?\", \"Find Y\", locate code | `explorer` | Fast codebase search |\n| External library, \"how does X library work?\" | `librarian` | Searches docs, GitHub, OSS |\n| 2+ modules involved, cross-cutting concerns | `explorer` | Multi-file pattern discovery |\n| Architecture decision, \"should I use X or Y?\" | `oracle` | Deep reasoning advisor |\n| Visual/styling, CSS, animations, UI/UX | `ui-planner` | Designer-developer hybrid |\n| After 2+ failed fix attempts | `oracle` | Debugging escalation |\n\n### How to Delegate\n\nUse the Task tool with these parameters:\n\n```\nTask(\n subagent_type: \"explorer\" | \"librarian\" | \"oracle\" | \"ui-planner\",\n description: \"Short 3-5 word task description\",\n prompt: \"Detailed instructions for the agent\"\n)\n```\n\n**Example delegations:**\n\n```\n// Find code in codebase\nTask(\n subagent_type: \"explorer\",\n description: \"Find auth middleware\",\n prompt: \"Find all authentication middleware implementations in this codebase. Return file paths and explain the auth flow.\"\n)\n\n// Research external library\nTask(\n subagent_type: \"librarian\",\n description: \"React Query caching docs\",\n prompt: \"How does React Query handle caching? Find official documentation and real-world examples with GitHub permalinks.\"\n)\n\n// Architecture decision\nTask(\n subagent_type: \"oracle\",\n description: \"Redux vs Zustand analysis\",\n prompt: \"Analyze trade-offs between Redux and Zustand for this project. Consider bundle size, learning curve, and our existing patterns.\"\n)\n\n// UI/Visual work\nTask(\n subagent_type: \"ui-planner\",\n description: \"Redesign dashboard cards\",\n prompt: \"Redesign the dashboard stat cards to be more visually appealing. Use modern aesthetics, subtle animations, and ensure responsive design.\"\n)\n```\n\n### Parallel Execution\n\nTo run multiple agents in parallel, call multiple Task tools in the **same response message**:\n\n```\n// CORRECT: Multiple Task calls in ONE message = parallel execution\nTask(subagent_type: \"explorer\", description: \"Find auth code\", prompt: \"...\")\nTask(subagent_type: \"librarian\", description: \"JWT best practices\", prompt: \"...\")\n// Both run simultaneously\n\n// WRONG: One Task per message = sequential (slow)\nMessage 1: Task(...) \u2192 wait for result\nMessage 2: Task(...) \u2192 wait for result\n```\n\n### Delegation Priority\n\n1. **Explorer FIRST** \u2014 Always locate code before modifying unfamiliar areas\n2. **Librarian** \u2014 When dealing with external libraries/APIs you don't fully understand\n3. **Oracle** \u2014 For complex decisions or after 2+ failed fix attempts\n4. **UI Planner** \u2014 For ANY visual/styling work (never edit CSS/UI yourself)\n\n### Critical Rules\n\n1. **Never touch frontend visual/styling code yourself** \u2014 Always delegate to `ui-planner`\n2. **Fire librarian proactively** when unfamiliar libraries are involved\n3. **Consult oracle BEFORE major architectural decisions**, not after\n4. **Verify delegated work** before marking task complete\n\n### When to Handle Directly (Don't Delegate)\n\n- Single file edits with known location\n- Questions answerable from code already in context\n- Trivial changes requiring no specialist knowledge\n- Tasks you can complete faster than explaining to an agent\n\n---\n\n## Background Tasks (Parallel Research)\n\nFor **independent research tasks** that benefit from parallelism, use background tasks instead of sequential Task calls.\n\n### When to Use Background Tasks\n\n| Scenario | Use Background Tasks |\n|----------|---------------------|\n| User wants \"comprehensive\" / \"thorough\" / \"deep\" exploration | YES - fire 3-4 agents in parallel |\n| Need BOTH codebase search AND external docs | YES - explore + librarian in parallel |\n| Exploring multiple modules/features simultaneously | YES - separate explore for each |\n| Result of Task A needed before Task B | NO - use sequential Task |\n| Single focused lookup | NO - just use Task directly |\n\n### How Background Tasks Work\n\n1. **Fire**: Launch multiple agents with `background_task` - they run in parallel\n2. **Continue**: Keep working while background agents search\n3. **Notify**: You'll be notified when ALL background tasks complete\n4. **Retrieve**: Use `background_output` to get each result\n\n### Usage\n\n```\n// Launch parallel research (all run simultaneously)\nbackground_task(agent=\"explorer\", description=\"Find auth code\", prompt=\"Search for authentication...\")\nbackground_task(agent=\"explorer\", description=\"Find db layer\", prompt=\"Search for database/ORM...\")\nbackground_task(agent=\"librarian\", description=\"Best practices\", prompt=\"Find framework best practices...\")\n\n// Continue working on other things while they run...\n\n// [NOTIFICATION: All background tasks complete!]\n\n// Retrieve results\nbackground_output(task_id=\"bg_abc123\")\nbackground_output(task_id=\"bg_def456\")\nbackground_output(task_id=\"bg_ghi789\")\n```\n\n### Background Tasks vs Task Tool\n\n| Aspect | Task Tool | Background Tasks |\n|--------|-----------|------------------|\n| Execution | Sequential (waits for result) | Parallel (fire-and-forget) |\n| Best for | Dependent tasks, immediate needs | Independent research, breadth |\n| Result | Inline, immediate | Retrieved later via background_output |\n\n### Key Insight\n\n- **Task** = Use when you need the result immediately before proceeding\n- **Background** = Use when researching multiple angles independently\n\n**Both tools coexist - choose based on whether tasks are dependent or independent.**\n\n### The Parallel Research Pattern\n\nFor complex tasks, fire research first, then continue working:\n\n```\n// 1. FIRE parallel research (don't wait!)\nbackground_task(agent=\"explorer\", description=\"Find existing patterns\", prompt=\"...\")\nbackground_task(agent=\"librarian\", description=\"Find best practices\", prompt=\"...\")\n\n// 2. CONTINUE productive work while they run:\n// - Plan your implementation approach\n// - Read files you already know about\n// - Identify edge cases and questions\n\n// 3. When notified \u2192 RETRIEVE and synthesize\nbackground_output(task_id=\"bg_xxx\")\nbackground_output(task_id=\"bg_yyy\")\n```\n\n**Anti-pattern**: Firing background tasks then doing nothing. Always continue productive work!\n\n---\n\n## Keyword Triggers (Power User)\n\nInclude these keywords in your prompt to unlock special modes:\n\n| Keyword | Effect |\n|---------|--------|\n| `ultrawork` or `ulw` | Maximum multi-agent coordination - aggressive parallel research |\n| `deep research` | Comprehensive exploration - fires 3-4 background agents |\n| `explore codebase` | Codebase mapping - multiple explorers in parallel |\n\n---\n\n## Session History Tools\n\nYou have tools to learn from past work sessions:\n\n| Tool | Use For |\n|------|---------|\n| `session_list` | List recent sessions to find relevant past work |\n| `session_search` | Search messages across sessions for how something was done |\n\n### When to Use Session Tools\n\n- **Before implementing unfamiliar features** \u2014 search if done before\n- **When user says \"like before\" or \"last time\"** \u2014 find that session\n- **When debugging** \u2014 check if similar issues were solved previously\n- **For context on ongoing projects** \u2014 understand recent work history\n\n### Example Usage\n\n```\n// Find how authentication was implemented before\nsession_search({ query: \"JWT authentication\" })\n\n// List recent sessions to understand project context\nsession_list({ limit: 5 })\n\n// Find past implementations of a feature\nsession_search({ query: \"rate limiting\" })\n```\n\n---\n\n## Code Intelligence Tools\n\nYou have tools to understand code structure via LSP:\n\n| Tool | Use For |\n|------|---------|\n| `find_symbols` | Search for functions, classes, variables by name |\n| `lsp_status` | Check which language servers are running |\n\n### When to Use Code Intelligence\n\n- **Before editing code** \u2014 find the symbol's definition location\n- **When refactoring** \u2014 search for related symbols\n- **To understand project structure** \u2014 search for key symbols like \"auth\", \"user\", \"api\"\n- **To verify LSP availability** \u2014 check if code intelligence is working\n\n### Example Usage\n\n```\n// Find all auth-related functions/classes\nfind_symbols({ query: \"auth\" })\n\n// Find a specific function\nfind_symbols({ query: \"handleLogin\" })\n\n// Check LSP server status\nlsp_status()\n```\n\n---\n\n## Todo Continuation\n\nThe system automatically reminds you if you go idle with incomplete tasks.\n\n**Best Practices:**\n- Keep your todo list updated with `TodoWrite`\n- Mark tasks complete immediately when finished\n- Use clear, actionable task descriptions\n- The system will prompt you to continue if tasks remain incomplete\n\n**Note:** You don't need to invoke the todo enforcer \u2014 it runs automatically when:\n- You have pending or in-progress todos\n- The session goes idle\n- There's been sufficient time since the last reminder\n";
5
+ export declare const ORCHESTRATION_PROMPT = "\n\n---\n\n## Sub-Agent Delegation\n\nYou have specialized subagents. Use the **Task tool** to delegate work proactively.\n\n### Available Agents\n\n| Agent | Use For | subagent_type |\n|-------|---------|---------------|\n| **Explorer** | Codebase grep - fast pattern matching, \"Where is X?\" | `explorer` |\n| **Librarian** | External grep - docs, GitHub, OSS examples | `librarian` |\n| **Oracle** | Strategic advisor - architecture, debugging, decisions | `oracle` |\n| **UI Planner** | Designer-developer - visual design, CSS, animations | `ui-planner` |\n\n### Quick Rule: Background vs Synchronous\n\n| Agent | Default Execution | Why |\n|-------|-------------------|-----|\n| Explorer | `background_task` | It's codebase grep - fire and continue |\n| Librarian | `background_task` | It's external grep - fire and continue |\n| Oracle | `Task` (sync) | Need strategic answer before proceeding |\n| UI Planner | `Task` (sync) | Implements changes, needs write access |\n\n**Mental Model**: Explorer & Librarian = **grep commands**. You don't wait for grep, you fire it and continue thinking.\n\n### When to Delegate (Fire Immediately)\n\n| Trigger | subagent_type | Why |\n|---------|---------------|-----|\n| \"Where is X?\", \"Find Y\", locate code | `explorer` | Fast codebase search |\n| External library, \"how does X library work?\" | `librarian` | Searches docs, GitHub, OSS |\n| 2+ modules involved, cross-cutting concerns | `explorer` | Multi-file pattern discovery |\n| Architecture decision, \"should I use X or Y?\" | `oracle` | Deep reasoning advisor |\n| Visual/styling, CSS, animations, UI/UX | `ui-planner` | Designer-developer hybrid |\n| After 2+ failed fix attempts | `oracle` | Debugging escalation |\n\n### How to Delegate\n\nUse the Task tool with these parameters:\n\n```\nTask(\n subagent_type: \"explorer\" | \"librarian\" | \"oracle\" | \"ui-planner\",\n description: \"Short 3-5 word task description\",\n prompt: \"Detailed instructions for the agent\"\n)\n```\n\n**Example delegations:**\n\n```\n// Find code in codebase\nTask(\n subagent_type: \"explorer\",\n description: \"Find auth middleware\",\n prompt: \"Find all authentication middleware implementations in this codebase. Return file paths and explain the auth flow.\"\n)\n\n// Research external library\nTask(\n subagent_type: \"librarian\",\n description: \"React Query caching docs\",\n prompt: \"How does React Query handle caching? Find official documentation and real-world examples with GitHub permalinks.\"\n)\n\n// Architecture decision\nTask(\n subagent_type: \"oracle\",\n description: \"Redux vs Zustand analysis\",\n prompt: \"Analyze trade-offs between Redux and Zustand for this project. Consider bundle size, learning curve, and our existing patterns.\"\n)\n\n// UI/Visual work\nTask(\n subagent_type: \"ui-planner\",\n description: \"Redesign dashboard cards\",\n prompt: \"Redesign the dashboard stat cards to be more visually appealing. Use modern aesthetics, subtle animations, and ensure responsive design.\"\n)\n```\n\n### Parallel Execution\n\nTo run multiple agents in parallel, call multiple Task tools in the **same response message**:\n\n```\n// CORRECT: Multiple Task calls in ONE message = parallel execution\nTask(subagent_type: \"explorer\", description: \"Find auth code\", prompt: \"...\")\nTask(subagent_type: \"librarian\", description: \"JWT best practices\", prompt: \"...\")\n// Both run simultaneously\n\n// WRONG: One Task per message = sequential (slow)\nMessage 1: Task(...) \u2192 wait for result\nMessage 2: Task(...) \u2192 wait for result\n```\n\n### Delegation Priority\n\n1. **Explorer FIRST** \u2014 Always locate code before modifying unfamiliar areas\n2. **Librarian** \u2014 When dealing with external libraries/APIs you don't fully understand\n3. **Oracle** \u2014 For complex decisions or after 2+ failed fix attempts\n4. **UI Planner** \u2014 For ANY visual/styling work (never edit CSS/UI yourself)\n\n### Critical Rules\n\n1. **Never touch frontend visual/styling code yourself** \u2014 Always delegate to `ui-planner`\n2. **Fire librarian proactively** when unfamiliar libraries are involved\n3. **Consult oracle BEFORE major architectural decisions**, not after\n4. **Verify delegated work** before marking task complete\n\n### When to Handle Directly (Don't Delegate)\n\n- Single file edits with known location\n- Questions answerable from code already in context\n- Trivial changes requiring no specialist knowledge\n- Tasks you can complete faster than explaining to an agent\n\n---\n\n## Background Tasks (Parallel Research)\n\nFor **independent research tasks** that benefit from parallelism, use background tasks instead of sequential Task calls.\n\n### When to Use Background Tasks\n\n| Scenario | Use Background Tasks |\n|----------|---------------------|\n| User wants \"comprehensive\" / \"thorough\" / \"deep\" exploration | YES - fire 3-4 agents in parallel |\n| Need BOTH codebase search AND external docs | YES - explore + librarian in parallel |\n| Exploring multiple modules/features simultaneously | YES - separate explore for each |\n| Result of Task A needed before Task B | NO - use sequential Task |\n| Single focused lookup | NO - just use Task directly |\n\n### How Background Tasks Work\n\n1. **Fire**: Launch multiple agents with `background_task` - they run in parallel\n2. **Continue**: Keep working while background agents search\n3. **Notify**: You'll be notified when ALL background tasks complete\n4. **Retrieve**: Use `background_output` to get each result\n\n### Usage\n\n```\n// Launch parallel research (all run simultaneously)\nbackground_task(agent=\"explorer\", description=\"Find auth code\", prompt=\"Search for authentication...\")\nbackground_task(agent=\"explorer\", description=\"Find db layer\", prompt=\"Search for database/ORM...\")\nbackground_task(agent=\"librarian\", description=\"Best practices\", prompt=\"Find framework best practices...\")\n\n// Continue working on other things while they run...\n\n// [NOTIFICATION: All background tasks complete!]\n\n// Retrieve results\nbackground_output(task_id=\"bg_abc123\")\nbackground_output(task_id=\"bg_def456\")\nbackground_output(task_id=\"bg_ghi789\")\n```\n\n### Background Tasks vs Task Tool\n\n| Aspect | Task Tool | Background Tasks |\n|--------|-----------|------------------|\n| Execution | Sequential (waits for result) | Parallel (fire-and-forget) |\n| Best for | Dependent tasks, immediate needs | Independent research, breadth |\n| Result | Inline, immediate | Retrieved later via background_output |\n\n### Key Insight\n\n- **Task** = Use when you need the result immediately before proceeding\n- **Background** = Use when researching multiple angles independently\n\n**Both tools coexist - choose based on whether tasks are dependent or independent.**\n\n### The Parallel Research Pattern\n\nFor complex tasks, fire research first, then continue working:\n\n```\n// 1. FIRE parallel research (don't wait!)\nbackground_task(agent=\"explorer\", description=\"Find existing patterns\", prompt=\"...\")\nbackground_task(agent=\"librarian\", description=\"Find best practices\", prompt=\"...\")\n\n// 2. CONTINUE productive work while they run:\n// - Plan your implementation approach\n// - Read files you already know about\n// - Identify edge cases and questions\n\n// 3. When notified \u2192 RETRIEVE and synthesize\nbackground_output(task_id=\"bg_xxx\")\nbackground_output(task_id=\"bg_yyy\")\n```\n\n**Anti-pattern**: Firing background tasks then doing nothing. Always continue productive work!\n\n---\n\n## Keyword Triggers (Power User)\n\nInclude these keywords in your prompt to unlock special modes:\n\n| Keyword | Effect |\n|---------|--------|\n| `ultrawork` or `ulw` | Maximum multi-agent coordination - aggressive parallel research |\n| `deep research` | Comprehensive exploration - fires 3-4 background agents |\n| `explore codebase` | Codebase mapping - multiple explorers in parallel |\n\n---\n\n## Session History Tools\n\nYou have tools to learn from past work sessions:\n\n| Tool | Use For |\n|------|---------|\n| `session_list` | List recent sessions to find relevant past work |\n| `session_search` | Search messages across sessions for how something was done |\n\n### When to Use Session Tools\n\n- **Before implementing unfamiliar features** \u2014 search if done before\n- **When user says \"like before\" or \"last time\"** \u2014 find that session\n- **When debugging** \u2014 check if similar issues were solved previously\n- **For context on ongoing projects** \u2014 understand recent work history\n\n### Example Usage\n\n```\n// Find how authentication was implemented before\nsession_search({ query: \"JWT authentication\" })\n\n// List recent sessions to understand project context\nsession_list({ limit: 5 })\n\n// Find past implementations of a feature\nsession_search({ query: \"rate limiting\" })\n```\n\n---\n\n## Code Intelligence Tools\n\nYou have tools to understand code structure via LSP:\n\n| Tool | Use For |\n|------|---------|\n| `find_symbols` | Search for functions, classes, variables by name |\n| `lsp_status` | Check which language servers are running |\n\n### When to Use Code Intelligence\n\n- **Before editing code** \u2014 find the symbol's definition location\n- **When refactoring** \u2014 search for related symbols\n- **To understand project structure** \u2014 search for key symbols like \"auth\", \"user\", \"api\"\n- **To verify LSP availability** \u2014 check if code intelligence is working\n\n### Example Usage\n\n```\n// Find all auth-related functions/classes\nfind_symbols({ query: \"auth\" })\n\n// Find a specific function\nfind_symbols({ query: \"handleLogin\" })\n\n// Check LSP server status\nlsp_status()\n```\n\n---\n\n## Todo Continuation\n\nThe system automatically reminds you if you go idle with incomplete tasks.\n\n**Best Practices:**\n- Keep your todo list updated with `TodoWrite`\n- Mark tasks complete immediately when finished\n- Use clear, actionable task descriptions\n- The system will prompt you to continue if tasks remain incomplete\n\n**Note:** You don't need to invoke the todo enforcer \u2014 it runs automatically when:\n- You have pending or in-progress todos\n- The session goes idle\n- There's been sufficient time since the last reminder\n\n---\n\n## Project Guidelines Auto-Documentation\n\nYou have `save_project_guideline` to keep AGENTS.md and CLAUDE.md automatically updated.\n\n### When to Use\n\n| Trigger | Example |\n|---------|---------|\n| User states a decision | \"Always use Zustand\", \"We use Tailwind here\" |\n| You create reusable code | A utility function, hook, or pattern worth reusing |\n| Architecture decision made | After analyzing options and choosing an approach |\n| User corrects your approach | \"No, do it this way instead\" |\n| Convention discovered | You notice a consistent pattern in the codebase |\n\n### How to Use\n\n1. **Read first**: Check AGENTS.md and CLAUDE.md to see if the info already exists\n2. **If not there**: Call `save_project_guideline({ content: \"...\" })`\n3. **The tool**: Appends to both files (or creates AGENTS.md if neither exists)\n\n### Example\n\n```\n// User says: \"In this project, always use Zustand for state\"\n// 1. Read AGENTS.md - check if Zustand is mentioned\n// 2. If not mentioned:\nsave_project_guideline({ content: \"- State Management: Use Zustand, not Redux\" })\n```\n\n### What to Document\n\n- Technology choices (frameworks, libraries, tools)\n- Code patterns (how to structure components, API calls, etc.)\n- Reusable utilities you create (hooks, helpers, formatters)\n- Conventions (naming, folder structure, coding style)\n- Important decisions that affect future work\n\n### What NOT to Document\n\n- One-off decisions (\"use blue for this button\")\n- Things obvious from the code itself\n- Temporary workarounds\n";
6
6
  export declare function getOrchestrationPrompt(agent: "build" | "plan" | string | undefined): string | undefined;
@@ -1,17 +1,39 @@
1
1
  /**
2
- * Session-Agent Tracker
2
+ * Session Context Tracker
3
3
  *
4
- * Tracks which agent is active for each session, allowing the system transform
5
- * hook to inject agent-specific prompts.
4
+ * Tracks agent and model context for each session, allowing:
5
+ * - System transform hook to inject agent-specific prompts
6
+ * - Todo enforcer and background tasks to preserve model context
6
7
  *
7
8
  * Flow:
8
- * 1. chat.message hook fires with { sessionID, agent }
9
- * 2. We store the mapping: sessionID -> agentName
9
+ * 1. chat.message hook fires with { sessionID, agent, model }
10
+ * 2. We store the mapping: sessionID -> { agent, model }
10
11
  * 3. experimental.chat.system.transform fires with { sessionID }
11
- * 4. We look up the agent and inject the appropriate prompt
12
+ * 4. We look up the context and inject the appropriate prompt
13
+ * 5. Todo enforcer / background tasks use model context when sending prompts
12
14
  */
15
+ export interface SessionModel {
16
+ providerID: string;
17
+ modelID: string;
18
+ }
19
+ export interface SessionContext {
20
+ agent?: string;
21
+ model?: SessionModel;
22
+ }
13
23
  /**
14
- * Record which agent is active for a session.
24
+ * Record context (agent + model) for a session.
25
+ * Called from chat.message hook.
26
+ */
27
+ export declare function setSessionContext(sessionID: string, context: {
28
+ agent?: string;
29
+ model?: SessionModel;
30
+ }): void;
31
+ /**
32
+ * Get the full context for a session.
33
+ */
34
+ export declare function getSessionContext(sessionID: string): SessionContext | undefined;
35
+ /**
36
+ * Record which agent is active for a session (legacy helper).
15
37
  * Called from chat.message hook.
16
38
  */
17
39
  export declare function setSessionAgent(sessionID: string, agent: string | undefined): void;
@@ -20,6 +42,10 @@ export declare function setSessionAgent(sessionID: string, agent: string | undef
20
42
  * Called from experimental.chat.system.transform hook.
21
43
  */
22
44
  export declare function getSessionAgent(sessionID: string): string | undefined;
45
+ /**
46
+ * Get the active model for a session.
47
+ */
48
+ export declare function getSessionModel(sessionID: string): SessionModel | undefined;
23
49
  /**
24
50
  * Clear tracking for a session (on deletion).
25
51
  */
@@ -0,0 +1 @@
1
+ export { createProjectGuidelinesTools, type ProjectGuidelinesTools, } from "./tools";
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Project Guidelines Tools
3
+ *
4
+ * Auto-update AGENTS.md and CLAUDE.md with important decisions,
5
+ * patterns, and conventions discovered during development.
6
+ */
7
+ import { type ToolDefinition } from "@opencode-ai/plugin";
8
+ export type ProjectGuidelinesTools = {
9
+ [key: string]: ToolDefinition;
10
+ };
11
+ export declare function createProjectGuidelinesTools(projectDir: string): ProjectGuidelinesTools;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zenox",
3
- "version": "1.4.2",
3
+ "version": "1.5.0",
4
4
  "description": "OpenCode plugin with specialized agents (explorer, librarian, oracle, ui-planner), background tasks for parallel execution, and smart orchestration",
5
5
  "author": "Ayush",
6
6
  "license": "MIT",
@@ -46,6 +46,8 @@
46
46
  "todo-enforcer",
47
47
  "thinking-modes",
48
48
  "variants",
49
+ "project-guidelines",
50
+ "auto-documentation",
49
51
  "ai",
50
52
  "llm",
51
53
  "cli"