diff --git a/.gitignore b/.gitignore index 7f9f69ea..7717a5e2 100644 --- a/.gitignore +++ b/.gitignore @@ -18,3 +18,6 @@ test-results/ # VitePress dev cache (build output goes to .vitepress/dist, covered by dist/) docs/.vitepress/cache/ + +# Generated from packages/framework/prompts/**/*.md by its gen-prompts script (#551). +packages/framework/src/prompts.generated.ts diff --git a/packages/framework/package.json b/packages/framework/package.json index 6d5fddcf..79872b6c 100644 --- a/packages/framework/package.json +++ b/packages/framework/package.json @@ -50,12 +50,13 @@ } }, "scripts": { - "build": "tsc -p tsconfig.build.json", - "dev": "tsc -p tsconfig.build.json --watch", - "typecheck": "tsc --noEmit", - "test": "tsc -p tsconfig.test.json && cd dist-test && node --test", + "build": "node scripts/gen-prompts.mjs && tsc -p tsconfig.build.json", + "dev": "node scripts/gen-prompts.mjs && tsc -p tsconfig.build.json --watch", + "typecheck": "node scripts/gen-prompts.mjs && tsc --noEmit", + "test": "node scripts/gen-prompts.mjs && tsc -p tsconfig.test.json && cd dist-test && node --test", "bundle:dashboard": "node scripts/bundle-dashboard.mjs", - "clean": "rm -rf dist dist-test" + "clean": "rm -rf dist dist-test src/prompts.generated.ts", + "gen:prompts": "node scripts/gen-prompts.mjs" }, "dependencies": { "@gemstack/ai-autopilot": "workspace:^", diff --git a/packages/framework/prompts/README.md b/packages/framework/prompts/README.md new file mode 100644 index 00000000..cd8cfc1f --- /dev/null +++ b/packages/framework/prompts/README.md @@ -0,0 +1,34 @@ +# Prompts + +Every prompt the framework sends an agent lives here as markdown (#551). Nothing agent-facing +is written in TypeScript any more, so prompting can change without touching the code. + +| file | what it is | +|---|---| +| `system_prompt.md` | The built-in system prompt (#326). Rom's doc. | +| `protocols/await.md` | How to emit an awaited choice so the turn-boundary gate can detect it (#337/#339). | +| `protocols/signal.md` | How to emit `setSessionName()` / `setReadyForMerge()` (#326). | +| `presets/*.md` | One file per preset button: research (#331), readability (#360), maintainability (#361), security_audit (#461), ux (#472). | + +## Editing + +Edit the markdown, then `pnpm build`. `scripts/gen-prompts.mjs` compiles this directory into +`src/prompts.generated.ts` (git-ignored, rebuilt by `build` / `test` / `typecheck`), which is +what the code imports. The markdown is the only source of truth. + +Adding `foo/bar.md` exports `FOO_BAR`. A file's exact bytes become the string, minus one +trailing newline. + +## Why generated instead of read from disk + +`@gemstack/ai-autopilot` reads its `prompts/*.md` with `node:fs` at run time. That does not work +here: the system prompt and the presets are reachable from `src/client.ts`, which the dashboard +imports **in the browser** to show the user the prompt before a run (#520). A `node:fs` edge +there breaks the browser bundle, and `client.test.ts` fails the build over it. Generating a +module of plain strings crosses that boundary for free and keeps the package `files: ["dist"]`. + +## Two rules + +- **The system prompt is Rom's** (#500/#547). Change it on #326 first, then sync the markdown. +- **Prompts get a review round before they land in production** (#547). The point of this + directory is that a prompt change is a readable markdown diff. diff --git a/packages/framework/prompts/presets/maintainability.md b/packages/framework/prompts/presets/maintainability.md new file mode 100644 index 00000000..64584b49 --- /dev/null +++ b/packages/framework/prompts/presets/maintainability.md @@ -0,0 +1,2 @@ +Refactor to make it as maintainable as possible: +- Look for maintainability red flags, and fix them. diff --git a/packages/framework/prompts/presets/readability.md b/packages/framework/prompts/presets/readability.md new file mode 100644 index 00000000..b2e5ef0b --- /dev/null +++ b/packages/framework/prompts/presets/readability.md @@ -0,0 +1,16 @@ +Refactor to make it as easy as possible for humans to read: +- Pinnacle architectural split + - Does each file and each represent a sensible and natural abstraction? + - Rate the *seams*, not just the boxes: for each call site, ask whether the responsibility sits on the right side of the boundary — should a caller's wrapper move down into the callee (or vice versa)? A can be clean, DRY and well-tested in isolation yet still be in the wrong place. "Well-factored" is not "well-located". +- Linearity (for humans) + - Put yourself in the shoes of a human reader who reads everything in a linear fashion + - Top to bottom: place callers above callees so readers encounter high-level logic before implementation details (humans think high-level first) + - Altitude pass: for each entry-point / orchestration , read it top-to-bottom as prose. Flag any line that drops the reader into lower-level mechanism (a flag, a thunk, a log verb, error plumbing) in the middle of what should be a high-level narrative. For each, ask: can that mechanism move down into the callee so the caller reads at one consistent altitude? Prioritize the reading path of all the a reader hits first. +- Before starting to work: list *ALL* files and *ALL* in this chat, rate them all (0: convoluted abstraction, hard to read, wrong place — 10: perfect), and give a reason for your rating + - DON'T skip any file nor any in your rating list — write an extra separated list in this chat of all files and all and put a ✅ tick to each entry to double check whether you forgot to rate something. So two lists: one list of ratings & explanation, and a second confirmation list. +- Separate commit for each refactor +- Work until it's exceptionally good. We as an expert team will check against every little detail. + - If we see that you gave mostly a 10/10 rating, that's a sign you've been lazy... so make sure you scrutinize everything and spend a substantial amount of time. We don't want to prompt you again and again to achieve quality — autonomously strive for quality on your own without us pushing you. +- Give summary of what you worked on: print the lists again with old rating => new rating with link to commit(s) + +FUNCTION: an actual function or a class, procedure, etc. (anything that represents a unit of logic) diff --git a/packages/framework/prompts/presets/research.md b/packages/framework/prompts/presets/research.md new file mode 100644 index 00000000..0aa11d03 --- /dev/null +++ b/packages/framework/prompts/presets/research.md @@ -0,0 +1,13 @@ +Measure "problem variability" of +- List all high-level flows the code implements, i.e. the list of all "problems" the code solves +- Give a rating for each problem (from 0 to 10) following this criteria: does the code solves the problem in an obviously optimal way (10), or is it highly unclear whether the problem can be solved in a better way (0)? +- Write down the ratings in a new file +- Show the list to the user and enable him to select problems via `showMultiSelect()`, + - Set default to `true` for entries with low rating +- For all problems the user selected, add a new entry to + - The entry: "Deep-dive research for alternative solutions, see " + +AWAIT: Stop, await user answer before resuming +REVIEW_FILE: `REVIEW-PROBLEMS_.agent.md` +TODO_FILE: `TODO_.agent.md` +SESSION_NAME: the name of the current Git branch — sanitize it to be a SLUG, if name is generic (e.g. `main`) then create a succinct SLUG diff --git a/packages/framework/prompts/presets/security_audit.md b/packages/framework/prompts/presets/security_audit.md new file mode 100644 index 00000000..5cfc918c --- /dev/null +++ b/packages/framework/prompts/presets/security_audit.md @@ -0,0 +1,5 @@ +Security audit +- Scrutinize the entire code for potential security issues +- Make it exhaustive (100% coverage) +- List every aspect you considered and, for each aspect, include a verdict as well as an explanation for non-obvious verdicts +- If you see any security issue, fix each security issue in a separate commit diff --git a/packages/framework/prompts/presets/ux.md b/packages/framework/prompts/presets/ux.md new file mode 100644 index 00000000..e70dee66 --- /dev/null +++ b/packages/framework/prompts/presets/ux.md @@ -0,0 +1,6 @@ +Thoroughly review UX of and make proposals to improve. Focus your review from a usability perspective: is using the UI and all the functionalities a nice user experience? +1. Enumerate *all* your findings (in a sensible order and categorized), with reference numbers (so that it's easy to reference each point in follow up conversations), and make it a list of choices shown via `showChoices()` +2. +3. Work on all accepted proposals + +AWAIT: Stop, await user answer before resuming diff --git a/packages/framework/prompts/protocols/await.md b/packages/framework/prompts/protocols/await.md new file mode 100644 index 00000000..08154adb --- /dev/null +++ b/packages/framework/prompts/protocols/await.md @@ -0,0 +1,24 @@ +## Awaiting a choice +When these instructions tell you to showChoices() / showMultiSelect() / showMarkdown() and then AWAIT, do not decide for the user. +End your turn with one fenced code block, then stop. +For a single choice (showChoices, pick one), tag it `await-choices`: +```await-choices +{ "title": "", "options": [{ "label": "