feat: inject decision tool instruction into system prompt
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 76/100
- Issue type
- Feature
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- javascript
- Domain
- ai
Research direction
Start in src/memory/prompts.js at loadSystemPrompt(), which already loads config and reads prompts/SYSTEM_PROMPT.md (frontmatter stripped) — that is the single place for the token swap. Insert an unnumbered <!-- DECISION_TOOL_INSTRUCTION --> placeholder near the IDENTITY/OPERATING PRINCIPLES top of prompts/SYSTEM_PROMPT.md, and mirror the enable gate used by the decision case in buildToolConfig() in src/tools/index.js (config.agent.decision.baseUrl non-empty). Add tests in tests/unit/prompts.test.js for both enabled (instruction present, token gone) and disabled (token and instruction absent) cases, then run npm run test, npm run lint, npm run coverage. Note the OpenSpec note: the author asks for approval before implementing, so confirm ownership first.
Written by the indexing model from the issue text.
Description
Summary
When the decision tool is enabled (config agent.decision.baseUrl is set), inject a conditional instruction block into the system prompt so the agent knows the tool exists and how to use it. When the tool is disabled, the instruction is removed entirely.
Motivation
The decision tool is config-gated: it only registers when agent.decision.baseUrl is set (see src/tools/index.js). But the system prompt (prompts/SYSTEM_PROMPT.md) never mentions it. So when the tool IS enabled, the agent has no guidance on when or how to use it — it may not reach for it at all, or may misuse it. Conversely, when the tool is disabled, the prompt must not reference it (a dangling mention of a tool that doesn't exist is noise and can mislead the model).
The fix is to make the system prompt conditional on config: inject the instruction when enabled, remove it when disabled.
Proposed Solution
Use a string-replace token in prompts/SYSTEM_PROMPT.md that loadSystemPrompt() swaps for either the instruction text (when the decision tool is enabled) or an empty string (when disabled).
- Add a placeholder token in
prompts/SYSTEM_PROMPT.mdnear the top of the prompt (e.g., in the IDENTITY or OPERATING PRINCIPLES area). - In
src/memory/prompts.js,loadSystemPrompt()reads the config, checks whether the decision tool is enabled (config.agent.decision.baseUrlis non-empty), and replaces the token with the instruction or removes it. - The instruction must NOT be a numbered directive. If it were numbered (e.g., "41. Use the decision tool..."), disabling the tool would leave a gap in the numbered list (e.g., 40, 42). It should be a standalone, unnumbered block that sits near the top.
Example token and replacement:
<!-- DECISION_TOOL_INSTRUCTION -->
When enabled, replace with a short block like:
**Decision tool:** A `decision` tool is available for fast, structured classification (routing, policy checks, rubric scoring). It accepts a `state` and a `questions` record, where each question has a `type` (`choice`, `noul`, or `score`), `instructions`, and optional `criteria`. Use it when you need a quick, deterministic judgment from a local model rather than reasoning it out yourself.
When disabled, replace with an empty string so no trace remains.
Alternatives Considered
- Hardcode the instruction always — Rejected: references a tool that may not be registered, misleading the model and adding noise.
- Inject via a separate prompt file — Rejected: adds indirection; a single token in the existing prompt is simpler and keeps the prompt self-contained.
- Numbered directive — Rejected: creates gaps in the numbered list when the tool is disabled.
OpenSpec Note
This project uses OpenSpec for feature development. If this request is approved, I will:
- Run
/opsx:proposeto generate a full proposal with specs and tasks - Iterate on the design before any code is written
- Follow the task-driven implementation workflow
Additional Context
Relevant files:
prompts/SYSTEM_PROMPT.md— the system prompt that needs the token.src/memory/prompts.js—loadSystemPrompt()reads the prompt and appends memory context; this is where the token replacement belongs.src/tools/index.js— thedecisioncase inbuildToolConfig()gates registration onruntimeOptions.decisionConfig?.baseUrl.src/config/schemas/agent.js—DecisionSchemadefinesbaseUrl(default""),model,temperature.config.yaml—agent.decision.baseUrlis""by default (tool not registered).tests/unit/prompts.test.js— existing tests forloadSystemPrompt(); new tests should cover token replacement when enabled and disabled.
Audit Findings (for Issue #1316)
- File:
prompts/SYSTEM_PROMPT.md— the system prompt is 149 lines. The IDENTITY block (top) and OPERATING PRINCIPLES section are the natural home for a conditional instruction. A good insertion point is near the top, after the IDENTITY block or as a standalone block in OPERATING PRINCIPLES, so it is not buried in a numbered list. src/memory/prompts.js—loadSystemPrompt(baseDir = cwd)readsprompts/SYSTEM_PROMPT.md, strips YAML frontmatter, then appends memory context. This is the single place to do the token replacement. It already importsloadConfig()(used forcwd), so the config is available.src/tools/index.js— thedecisioncase inbuildToolConfig()registers the tool only whenruntimeOptions.decisionConfig?.baseUrlis truthy.decisionConfigis set fromconfig?.agent?.decision. This is the exact same gate the prompt injection must mirror: enabled iffconfig.agent.decision.baseUrlis non-empty.src/config/schemas/agent.js—DecisionSchemadefinesbaseUrl(default""),model(default"tev1:4b"),temperature(default0).agent.decisiondefaults to{}, soconfig.agent.decision.baseUrlisundefined/""when unset.config.yaml—agent.decision.baseUrlis""by default (tool not registered). Setting it to a real Ollama URL enables the tool.src/agent/deepAgents.js—createDeepAgentsOrchestrator()callsloadSystemPrompt()at line 304 and appends AGENTS.md. The token replacement happens insideloadSystemPrompt(), so this caller needs no change.tests/unit/prompts.test.js— existing tests cover frontmatter stripping, context appending, and missing-file handling. New tests should cover: (a) token replaced with instruction whenagent.decision.baseUrlis set, (b) token removed (empty) whenagent.decision.baseUrlis empty/unset.
Fix Steps
- Add the token — In
prompts/SYSTEM_PROMPT.md, insert a placeholder token (e.g.,<!-- DECISION_TOOL_INSTRUCTION -->) near the top of the prompt, as a standalone unnumbered block. Do NOT make it a numbered directive — a numbered entry would leave a gap in the list when the tool is disabled. - Add the instruction text — Define the instruction block (the text that replaces the token when the tool is enabled). Keep it concise and unnumbered. It should describe what the
decisiontool does and when to use it. - Wire the replacement — In
src/memory/prompts.js, insideloadSystemPrompt(), readconfig.agent.decision.baseUrl. If it is non-empty, replace the token with the instruction; otherwise replace it with an empty string. UseString.prototype.replaceAll()or a regex to swap the token. - Add unit tests — In
tests/unit/prompts.test.js, add tests that:- Mock config with
agent.decision.baseUrlset → assert the instruction text is present and the token is gone. - Mock config with
agent.decision.baseUrlempty/unset → assert the token is removed and no instruction text remains.
- Mock config with
- Verify — Run
npm run test,npm run lint, andnpm run coverageto confirm everything passes and coverage is maintained.
- Dominant language
- JavaScript
- Stars
- 2
- Forks
- 0
- Avg merge
- 1h 15m
- Merged PRs (30d)
- 249
Getting set up
- Ships a Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from avoidwork/madz
-
feature
Difficulty 5/5 Over a week Newbie friendliness 35/100
Maintainers usually reply within 1 day
Similar issues
-
ci-install-db-tools stall-case tests flake: stalled apt-get can be killed before it logs its callOpeneffort:low model:light plan planner:opus-5-5 tests
Difficulty 2/5 1-3 hours Newbie friendliness 86/100
Maintainers usually reply within 1 day
-
Bug 🐞
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
mozilla-mobile/firefox-ios#35986 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
-
component:sight
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
agentic-os-org/ANOLISA#6738 · 2 comments ·
Maintainers usually reply within 1 day
-
bug Durable Agents Observability (AI Telemetry) status: needs triage
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
mastra-ai/mastra#26470 · 1 comment ·
Maintainers usually reply within 1 day