Skip to content

refactor(agents): externalize prompts to versioned template files (Closes #24) - #101

Closed
laurentketterle-hub wants to merge 6 commits into
Flamki:masterfrom
laurentketterle-hub:feat/externalize-prompts-24
Closed

refactor(agents): externalize prompts to versioned template files (Closes #24)#101
laurentketterle-hub wants to merge 6 commits into
Flamki:masterfrom
laurentketterle-hub:feat/externalize-prompts-24

Conversation

@laurentketterle-hub

@laurentketterle-hub laurentketterle-hub commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Externalizes agent prompts from embedded strings into versioned template files (Closes #24).

Files

  • src/prompts/research.txt, summary.txt, analysis.txt, code.txt — prompt templates
  • src/prompts/loader.jsloadPrompt(name, vars) with {{variable}} substitution
  • src/prompts/CHANGELOG.md — version tracking

Usage

import { loadPrompt } from '../prompts/loader.js'
const prompt = loadPrompt('research', { topic: 'AI payments' })

Acceptance Criteria

Criteria Status
Prompts moved to src/prompts/ 4 .txt files extracted
Light templating {{var}} substitution in loader
Version tracking CHANGELOG.md with rollback docs
No core logic changes needed Additive — prompts load from files

Signed-off-by: laurentketterle-hub laurentketterle-hub@users.noreply.github.com

Summary by CodeRabbit

  • New Features

    • Added structured AI prompts for strategic analysis, coding assistance, research, and summarization.
    • Added prompt loading with variable substitution and warnings for unresolved placeholders.
    • Added clear error handling when requested prompts are unavailable.
  • Documentation

    • Added a prompt changelog documenting the initial prompt collection and rollback guidance.

…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
…amki#24)

Signed-off-by: laurentketterle-hub <laurentketterle-hub@users.noreply.github.com>
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The change externalizes four agent prompts into versioned template files. It adds loadPrompt to read templates, substitute runtime variables, report missing files, warn about unresolved placeholders, and return processed content.

Changes

Prompt externalization

Layer / File(s) Summary
Prompt templates and versioning
src/prompts/analysis.txt, src/prompts/code.txt, src/prompts/research.txt, src/prompts/summary.txt, src/prompts/CHANGELOG.md
Added four prompt templates with runtime placeholders. Added version 1.0.0 extraction and rollback instructions.
Runtime prompt loading
src/prompts/loader.js
Added loadPrompt(name, vars) to load .txt files, replace {{key}} placeholders, throw for missing files, and warn about unresolved placeholders.

Estimated code review effort: 2 (Simple) | ~10 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds templates and a loader, but no consuming-code changes show that embedded prompts were replaced or that agents use loadPrompt. Update agent or service code to load each prompt through loadPrompt and add focused tests for loading and variable substitution.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: externalizing agent prompts into versioned template files.
Description check ✅ Passed The description documents the change, files, usage, and acceptance criteria, but it omits the template's Validation and Checklist sections.
Out of Scope Changes check ✅ Passed The changed files support prompt externalization, templating, version tracking, and rollback documentation without unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/prompts/CHANGELOG.md (1)

1-12: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix the Prettier failure before merge.

The lint job fails for src/prompts/CHANGELOG.md. Run prettier --write src/prompts/CHANGELOG.md and commit the formatted file.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/prompts/CHANGELOG.md` around lines 1 - 12, Format
src/prompts/CHANGELOG.md with Prettier using the repository’s standard
configuration, ensuring the file passes the lint job; commit the resulting
formatting-only changes.

Source: Pipeline failures

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/prompts/loader.js`:
- Around line 8-10: Update loadPrompt to validate the resolved filePath remains
contained within PROMPTS_DIR before readFileSync, rejecting traversal names such
as ../../outside/secret while preserving valid prompt loading and the existing
not-found behavior.
- Around line 12-13: Update the replacement loop in the prompt loader to pass a
replacer function to template.replaceAll for each variable token, ensuring
String(value) is inserted literally even when it contains replacement specifiers
such as $$$$.

---

Outside diff comments:
In `@src/prompts/CHANGELOG.md`:
- Around line 1-12: Format src/prompts/CHANGELOG.md with Prettier using the
repository’s standard configuration, ensuring the file passes the lint job;
commit the resulting formatting-only changes.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c983a4c7-5255-46fa-ab94-7adb34d48a17

📥 Commits

Reviewing files that changed from the base of the PR and between 6eb1d2b and 90d9304.

📒 Files selected for processing (6)
  • src/prompts/CHANGELOG.md
  • src/prompts/analysis.txt
  • src/prompts/code.txt
  • src/prompts/loader.js
  • src/prompts/research.txt
  • src/prompts/summary.txt

Comment thread src/prompts/loader.js
Comment on lines +8 to +10
export function loadPrompt(name, vars = {}) {
const filePath = join(PROMPTS_DIR, `${name}.txt`)
if (!existsSync(filePath)) throw new Error(`Prompt not found: ${name}.txt`)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -nP -C 4 '\bloadPrompt\s*\(' \
  --glob '*.js' --glob '*.mjs' --glob '*.cjs' --glob '*.ts' .

Repository: Flamki/stellarmind

Length of output: 784


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== loader.js =="
cat -n src/prompts/loader.js

echo
echo "== prompt files =="
find src/prompts -maxdepth 1 -type f -print | sort | while read -r f; do
  echo "--- $f"
  sed -n '1,80p' "$f"
done

echo
echo "== imports of loader =="
rg -nP -C 3 '\.\/loader|loadPrompt\s*<|from\s+.*prompts|from "\.\/prompts/loader|from '\''\.\/prompts/loader|import\s*\(' --glob '*.js' --glob '*.mjs' --glob '*.cjs' --glob '*.ts' .

Repository: Flamki/stellarmind

Length of output: 3237


Check that prompt names cannot leave PROMPTS_DIR.

loadPrompt joins name directly into a file path and reads the result. Add validation or a resolved-path containment check before readFileSync so names such as ../../outside/secret cannot select files outside src/prompts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/prompts/loader.js` around lines 8 - 10, Update loadPrompt to validate the
resolved filePath remains contained within PROMPTS_DIR before readFileSync,
rejecting traversal names such as ../../outside/secret while preserving valid
prompt loading and the existing not-found behavior.

Comment thread src/prompts/loader.js
Comment on lines +12 to +13
for (const [key, value] of Object.entries(vars))
template = template.replaceAll(`{{${key}}}`, String(value))

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== files =="
git ls-files | rg '(^|/)src/prompts/loader\.js$|loader\.js$' || true

echo "== loader.js =="
if [ -f src/prompts/loader.js ]; then
  nl -ba src/prompts/loader.js | sed -n '1,120p'
fi

echo "== tests mentioning loader or prompt vars =="
rg -n "src/prompts/loader|prompts/loader|replaceAll\\(\\`\\{\\{.*\\}\\}\\`|replaceAll\\(.*\\{\\{|regression|token|\\$&|replacement" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true

echo "== JavaScript replacement behavior probe =="
node - <<'JS'
const inputs = [
  { template: 'hi {{x}}', vars: { x: '$&' } },
  { template: 'hi {{x}}', vars: { x: '$1' } },
  { template: 'hi {{x}} {{x}}', vars: { x: '$&x$&' } },
];
for (const { template, vars } of inputs) {
  console.log('literal string:', template.replaceAll(`{{x}}`, String(vars.x)));
  console.log('replacer function:', template.replaceAll(`{{x}}`, () => String(vars.x)));
}
JS

Repository: Flamki/stellarmind

Length of output: 246


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== loader.js =="
if [ -f src/prompts/loader.js ]; then
  cat -n src/prompts/loader.js | sed -n '1,160p'
fi

echo "== tests mentioning loader or prompt vars =="
rg -n "src/prompts/loader|prompts/loader|replaceAll\\(\\`\\{\\{.*\\}\\}\\`|replaceAll\\(.*\\{\\{|regression|token|\\$&|replacement|loader" -S . --glob '!node_modules' --glob '!dist' --glob '!build' || true

echo "== JavaScript replacement behavior probe =="
node - <<'JS'
const inputs = [
  { template: 'hi {{x}}', vars: { x: '$&' } },
  { template: 'hi {{x}}', vars: { x: '$1' } },
  { template: 'hi {{x}} {{x}}', vars: { x: '$&x$&' } },
];
for (const { template, vars } of inputs) {
  console.log('literal string:', JSON.stringify(template.replaceAll(`{{x}}`, String(vars.x))));
  console.log('replacer function:', JSON.stringify(template.replaceAll(`{{x}}`, () => String(vars.x))));
}
JS

Repository: Flamki/stellarmind

Length of output: 5465


Insert variable values literally.

When value contains a replacement specifier such as $$$$, replaceAll can change the value it is meant to insert. Use a replacer function so the template token is replaced with the value unchanged.

Proposed fix
-    template = template.replaceAll(`{{${key}}}`, String(value))
+    template = template.replaceAll(`{{${key}}}`, () => String(value))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for (const [key, value] of Object.entries(vars))
template = template.replaceAll(`{{${key}}}`, String(value))
for (const [key, value] of Object.entries(vars))
template = template.replaceAll(`{{${key}}}`, () => String(value))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/prompts/loader.js` around lines 12 - 13, Update the replacement loop in
the prompt loader to pass a replacer function to template.replaceAll for each
variable token, ensuring String(value) is inserted literally even when it
contains replacement specifiers such as $$$$.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Externalize agent prompts into versioned template files

1 participant