The prompt composer¶
Grounding any coding prompt in minimized code context + remembered project conventions — in one shot.
compose_task_prompt is an MCP prompt that, given a task description, assembles a single grounded,
well-structured prompt by combining two things Sankshep already produces: relevance-ranked,
AST-minimized code (via get_context) and remembered project conventions (via recall). It
returns that prompt in one shot, for the model to act on.
The framing that governs this whole page: the composer grounds a prompt in minimized-context + memory — it does not generate the prompt's intent, and it never generates the answer.
Three claims, and they are not equally well supported — see Benchmarks:
- Fewer roundtrips — a grounded first prompt is meant to remove the "let me look around the codebase first" turns. Not measured. A single-shot harness cannot see roundtrips; it needs an agent simulation, which does not exist yet. Treat this as the design intent, not a result.
- Higher accuracy — grounding in the actual code and conventions is meant to stop the model
inventing patterns the project does not use. Measured, and the honest answer is parity, not a
gain. The composer is a wrapper around
get_context, and it scored 0.51 mean key-point recall against that engine's 0.66 on the same questions at the same budgets, because it was spending part of the caller's token budget on remembered conventions. That is fixed — it now reaches 0.66–0.68, level with the engine. Against an uncapped dump of every raw file it is 0.66 against 1.00. - Less token waste — measured: 72.6% fewer tokens than dumping the raw whole files, at 0.66 recall against that baseline's 1.00.
The composer's case is therefore token cost, not accuracy: it delivers roughly a third of the tokens for roughly two thirds of the facts, in one grounded prompt instead of several exploratory turns.
Positioning vs. GitHub Copilot prompt files¶
"Isn't this just Copilot's .prompt.md files?" No — they operate at different layers and compose.
Copilot prompt files are the template layer (author-time, static). Sankshep is the grounding
layer (request-time, dynamic).
Copilot prompt files (.prompt.md) |
Sankshep composer (compose_task_prompt) |
|
|---|---|---|
| Who writes the body | You, at author-time (a reusable template) | Assembled at request-time from your one-line task |
| Where code context comes from | Placeholders / #file / untuned @workspace |
Relevance-ranked, AST-minimized code from get_context |
| Where conventions come from | A hand-maintained copilot-instructions.md |
Cross-session recall memory |
| Static vs. dynamic | Static until you edit the file | Dynamic — reflects the code + memory now |
| Layer | Template layer (the prompt's shape) | Grounding layer (the prompt's substance) |
A Copilot .prompt.md can call Sankshep's grounding tools via its tools: front-matter, and Copilot
merges the result into its context. Sankshep does not reinvent the template/slash-command layer.
The naive flow it replaces¶
Without grounding, an assistant discovers the codebase by spending roundtrips — asking for files, reading too much, guessing conventions, correcting itself:
flowchart TB
U["You: 'add rate limiting to the login endpoint'"]
M1["Model: which files?"]
T1["reads whole AuthController.cs + Program.cs"]
M2["Model: invents a [RateLimit] attribute"]
M3["Model: proposes code (wrong pattern)"]
U2["You: 'no, we use the RateLimiting middleware'"]
M4["Model: corrected answer"]
U --> M1 --> T1 --> M2 --> M3 --> U2 --> M4
The composed one-shot flow¶
The composer collapses that exploration into a single deterministic assembly step before the model reasons:
flowchart TB
U["You: /compose_task_prompt<br/>task: 'add rate limiting to the login endpoint'<br/>paths: src/Api/Auth, src/Api/Program.cs"]
subgraph S["Sankshep — deterministic, no LLM"]
GC["get_context → minimized Login endpoint + middleware"]
RC["recall → 'use RateLimiting middleware, 429 + Retry-After'"]
CMP["composer: pack under budget<br/>Task / Code / Conventions / Constraints"]
end
P["One grounded prompt"]
M["Model: correct answer, first try"]
U --> GC --> CMP
U --> RC --> CMP
CMP --> P --> M
Interop: a Copilot prompt file calling Sankshep¶
flowchart LR
PF[".github/prompts/feature.prompt.md<br/>front-matter: tools: [sankshep]"]
CP["Copilot Chat (template layer)"]
SK["Sankshep grounding: get_context + recall"]
MO["Model acts on template + grounding"]
PF --> CP
CP -->|invokes grounding via tools:| SK
SK -->|minimized code + conventions| CP
CP -->|merged context| MO
Anatomy of a composed prompt¶
Four labelled sections, assembled deterministically under a token budget that bounds the code, with conventions:
- Task — your one-line intent, verbatim.
- Relevant code — AST-minimized, ranked snippets from
get_context, each with its file path. - Project conventions — facts remembered under the
conventioncategory, branch-scoped, deduped, most-recent-first. Only that category: a fact filed asdecision,gotchaor anything else is never injected here, however relevant it looks. When the section is empty it says so, and names the categories your facts are actually under, so a mis-filed rule is visible rather than silently ignored. - Constraints — guardrails (stay within the shown code, don't add dependencies, follow conventions).
Worked example — "add rate limiting to the login endpoint":
# Task
add rate limiting to the login endpoint
# Relevant code (minimized)
// src/Api/Auth/AuthController.cs:42-58 Login
[HttpPost("login")]
public async Task<IResult> Login(LoginRequest req, CancellationToken ct) { /* … issues JWT … */ }
// src/Api/Program.cs:18-24
builder.Services.AddRateLimiter(/* … existing FixedWindow limiter … */);
app.UseRateLimiter();
# Project conventions
- Rate limiting uses ASP.NET's built-in RateLimiting middleware, never a custom attribute.
- Limits are bound from RateLimitingOptions in appsettings, not hard-coded.
- Throttled requests return 429 with a Retry-After header.
# Constraints
- Work within the code shown above; do not invent new packages or patterns.
- Follow the recalled conventions exactly. If information is missing, say so rather than guessing.
The model receives that — grounded, minimized, convention-correct — so its first response uses the middleware pattern and the 429/Retry-After contract, with no exploratory roundtrips.
The boundary: a prompt, not an answer¶
The composer is deterministic assembly of retrieved material. It does not generate code, call an
LLM, or orchestrate a solution — and it takes no dependency on any model client (a build-time test
enforces this, so the boundary can't erode). Given fixed inputs it produces byte-identical output: the
retrieved material (Relevant code / Project conventions) traces back to get_context / recall, while
Task is your input verbatim and Constraints are fixed guardrails — so the whole prompt is deterministic and
auditable.
Using it¶
Arguments
compose_task_prompt takes task (your one-line intent) and paths — the file or directory
paths to draw code context from, comma- or newline-separated. paths is required; with none
supplied there is no code to minimize and the Relevant code section comes back empty. tokenBudget
is optional and defaults to 4000, and bounds the code. Remembered conventions are additive,
with their own budget of 600 tokens, so the prompt you get back is larger than the number you
passed — by the conventions section plus the template's own text. Changed in 3.0.0; before that the
budget was split ~70/30, which cost the composer 0.15 of key-point recall against get_context at
the same number.
- As Sankshep's MCP prompt: clients that surface prompts expose
compose_task_promptas a slash-command — supply the task and the paths, get the grounded prompt. - Under a Copilot prompt file: a committed
.github/prompts/*.prompt.mdreferences Sankshep's grounding tools viatools:, and Copilot merges the result — the template layer calling the grounding layer.