pi-context-engine 0.1.0 → 0.1.2

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
@@ -58,6 +58,20 @@ Ten tools the agent can call, plus three slash commands.
58
58
 
59
59
  Commands: `/context-index [--full]`, `/context-status`, `/context-savings`.
60
60
 
61
+ **Shipped guidance.** The package also injects a ~900-token guidance section
62
+ into the system prompt while `context_search` is active: how to formulate
63
+ queries, when *not* to search, how to read confidence and overflow markers,
64
+ and the index lifecycle.
65
+
66
+ - **Why it ships:** retrieval only saves tokens when queries are good, and
67
+ these rules describe this package's own semantics. Keeping them in the tool
68
+ description alone would leave every user guessing.
69
+ - **Cost-aware gate:** the section appears only while the tool is selected, and
70
+ `guidance.enabled: false` turns it off entirely for prompt-lean setups.
71
+ - **Structured, not forced:** it is written to `systemPromptOptions.sections`,
72
+ so pi replays and diffs it like any other section instead of freezing the
73
+ whole prompt.
74
+
61
75
  ## How it works
62
76
 
63
77
  1. **Chunk**: tree-sitter parses source into functions, classes and modules.
@@ -93,6 +107,8 @@ retrieval:
93
107
  top_k: 20
94
108
  confidence_threshold: 0.2
95
109
  marginal_ratio: 0.75 # stop adding chunks below this fraction of the top score
110
+ guidance:
111
+ enabled: true # inject context_search guidance into the system prompt
96
112
  compression:
97
113
  level: standard # minimal | standard | full
98
114
  ollama_url: http://localhost:11434
@@ -26,6 +26,7 @@ pi session
26
26
  | `indexer/embedder.ts` | Ollama + local ONNX backends, selection | `indexer/embedder.py` |
27
27
  | `indexer/secrets.ts` | Secret filename skip, content redaction, PII scrub | `indexer/secrets.py` |
28
28
  | `retrieval/retriever.ts` | RRF merge, confidence blend, graph expansion | `retrieval/retriever.py` |
29
+ | `guidance.ts` | Query-formulation system-prompt section (config-gated) | upstream's session-start tool instructions |
29
30
  | `compression/compressor.ts` | Truncation signatures, Ollama summaries, quality gate | `compression/*` |
30
31
  | `memory/db.ts` | Schema, vec recall, savings ledger, retention | `memory/db.py` |
31
32
  | `memory/grammar.ts` | Deterministic prose compression | `memory/grammar.py` |
@@ -71,6 +72,11 @@ contending with embedding writes. Upstream made the same split.
71
72
  - **Best-effort everywhere it must not crash.** Savings accounting, audit logs,
72
73
  session capture and shutdown all swallow their own errors: an instrumentation
73
74
  problem must never break a tool response.
75
+ - **Guidance pays for its tokens or does not ship.** The ~900-token section is
76
+ injected only when `context_search` is in the run's selected tools *and*
77
+ `guidance.enabled` is true, through `sections` (replayable, diffable) rather
78
+ than a forced prompt replacement. Users who count prompt tokens opt out with
79
+ one config line.
74
80
 
75
81
  ## Degradation paths
76
82
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-context-engine",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Semantic code context for pi: tree-sitter index + hybrid vector/BM25 retrieval + cross-session memory, all local. Port of code-context-engine (MIT, elara-labs) as a native pi extension.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -29,7 +29,8 @@
29
29
  "check": "npm run typecheck && npm run test",
30
30
  "smoke:env": "node scripts/smoke-env.mjs",
31
31
  "smoke:loader": "node scripts/smoke-loader.mjs",
32
- "smoke:real-world": "tsx scripts/smoke-real-world.mjs"
32
+ "smoke:real-world": "tsx scripts/smoke-real-world.mjs",
33
+ "prepublishOnly": "node -e \"if(!process.env.CI)throw new Error('publish via release.yml CI: push a v* tag. Manual npm publish is blocked to guarantee provenance + version sync.')\""
33
34
  },
34
35
  "pi": {
35
36
  "extensions": [
package/src/config.ts CHANGED
@@ -51,6 +51,12 @@ export interface Config {
51
51
  ollamaUrl: string;
52
52
  embeddingModel: string;
53
53
  ollamaEmbedModel: string;
54
+ /**
55
+ * Inject the query-formulation guidance section into the system prompt
56
+ * while `context_search` is active. Default true: retrieval quality depends
57
+ * on how queries are written. Set false for the leanest possible prompt.
58
+ */
59
+ guidanceEnabled: boolean;
54
60
  retrievalConfidenceThreshold: number;
55
61
  retrievalTopK: number;
56
62
  retrievalMarginalRatio: number;
@@ -74,6 +80,7 @@ export function defaultConfig(): Config {
74
80
  ollamaUrl: "http://localhost:11434",
75
81
  embeddingModel: "local",
76
82
  ollamaEmbedModel: "nomic-embed-text",
83
+ guidanceEnabled: true,
77
84
  retrievalConfidenceThreshold: 0.2,
78
85
  retrievalTopK: 20,
79
86
  retrievalMarginalRatio: 0.75,
@@ -96,6 +103,7 @@ const MAPPING: Record<string, keyof Config> = {
96
103
  "compression.level": "compressionLevel",
97
104
  "compression.model": "compressionModel",
98
105
  "compression.ollama_url": "ollamaUrl",
106
+ "guidance.enabled": "guidanceEnabled",
99
107
  "embedding.model": "embeddingModel",
100
108
  "embedding.ollama_model": "ollamaEmbedModel",
101
109
  "retrieval.confidence_threshold": "retrievalConfidenceThreshold",
package/src/extension.ts CHANGED
@@ -11,6 +11,7 @@ import { Type } from "typebox";
11
11
  import fs from "node:fs";
12
12
  import path from "node:path";
13
13
  import { ContextEngine, isPceConfig } from "./engine.js";
14
+ import { applyContextSearchGuidance } from "./guidance.js";
14
15
 
15
16
  /** Tools whose payloads are worth capturing for session timelines. */
16
17
  const CAPTURED_TOOLS = new Set(["bash", "read", "edit", "write", "grep", "find", "ls"]);
@@ -305,6 +306,12 @@ export default function contextEngineExtension(pi: ExtensionAPI) {
305
306
  promptNumber = eng.recordPrompt(event.prompt ?? "");
306
307
  eng.enqueueTurnCompression(promptNumber);
307
308
 
309
+ // Query-formulation guidance for context_search: gated on the tool being
310
+ // active and on `guidance.enabled` (config), so prompt-lean setups pay
311
+ // nothing. Section, not a forced prompt override: pi diffs it like any
312
+ // other section and the transcript stays stable.
313
+ applyContextSearchGuidance(event.systemPromptOptions, eng.config.guidanceEnabled);
314
+
308
315
  // First prompt of the session: inject a compact "where you left off"
309
316
  // block as a non-displayed custom message (upstream's SessionStart hook).
310
317
  if (!bootstrapSent) {
@@ -0,0 +1,114 @@
1
+ /**
2
+ * System-prompt guidance for the package's own tools.
3
+ *
4
+ * Why this ships with the package: retrieval quality depends on how the query
5
+ * is written, and the tool's `promptSnippet`/`promptGuidelines` only say "use
6
+ * this instead of grep/read". Everything specific to *this* package's
7
+ * semantics (confidence scores, overflow references, `/context-index`, the
8
+ * empty-index background build) has to travel with the package, or it drifts
9
+ * the moment a tool parameter changes.
10
+ *
11
+ * Injection is gated on three conditions so the ~900-token block never lands
12
+ * where it does not pay for itself:
13
+ * 1. `context_search` must be in the run's selected tools
14
+ * 2. `guidance.enabled` must be true in config (default true)
15
+ * 3. only runs that start from a user prompt get the bootstrap message;
16
+ * guidance itself applies to every run while the tool is active
17
+ *
18
+ * Registered through `systemPromptOptions.sections` rather than a forced
19
+ * `systemPrompt`: pi replays and diffs structured sections like any other, so
20
+ * the transcript stays stable instead of freezing a whole-prompt override.
21
+ */
22
+
23
+ export const CONTEXT_SEARCH_SECTION_KEY = "context_search_guidelines";
24
+
25
+ /** Minimal shape of the mutable prompt options this module touches. */
26
+ export interface GuidanceTarget {
27
+ selectedTools: string[];
28
+ sections: Record<string, string>;
29
+ }
30
+
31
+ export const CONTEXT_SEARCH_GUIDELINES = `You have context_search, a semantic code search over this project's index (tree-sitter chunks, hybrid vector + BM25, confidence-scored). Use it well.
32
+
33
+ ### When to search vs. when not to
34
+
35
+ SEARCH when:
36
+ - Starting a new task and you need to understand the relevant code area
37
+ - You need to find where a concept, pattern, or feature is implemented
38
+ - Before editing code you haven't recently read
39
+ - You need cross-file relationships (callers, imports, dependents)
40
+
41
+ SKIP the search when:
42
+ - You already have the file contents in context from a recent read
43
+ - You were given an exact file path and line numbers
44
+ - You need a simple exact-string match (use bash with grep/rg instead)
45
+ - You are editing a file you just read in the current turn
46
+
47
+ ### Writing effective queries
48
+
49
+ GOOD queries - specific, scoped, with concrete symbols or behaviour:
50
+ - "How does the AuthenticationMiddleware validate JWT tokens? Show the verify method and its error handling"
51
+ - "Where is the UserService.createUser method defined? Show the full implementation and parameters"
52
+ - "Find all HTTP route handlers that accept file uploads"
53
+ - "How does the EventBus dispatch events to subscribers?"
54
+
55
+ POOR queries - vague, broad, or just a symbol dump:
56
+ - "Show me the codebase"
57
+ - "Authentication"
58
+ - "Find UserService"
59
+
60
+ RULES:
61
+ 1. Describe WHAT you want in natural language - the index is semantic, prose works better than keywords
62
+ 2. Include CONTEXT: what it is for (implementation? debugging? refactoring?)
63
+ 3. Ask for the LEVEL OF DETAIL: "full method", "the interface and its implementors", "the call chain"
64
+ 4. Combine related lookups into ONE query instead of several calls
65
+
66
+ ### Reading the results
67
+
68
+ - Each hit is a compressed chunk: \`[path:start] (confidence: 0.xx)\` followed by the code
69
+ - A "\`expand_chunk\`" reference list means results were cut by the token budget - expand only the ones you actually need, never every entry
70
+ - Confidence below ~0.5 usually means the index has nothing better; rephrase rather than trusting a weak hit
71
+ - Results come from the index, not the live file: before editing, open the file with \`read\` to see its current state
72
+
73
+ ### Before editing code
74
+
75
+ Search once with a query covering ALL of:
76
+ - The function/method/class you are modifying (full implementation)
77
+ - Its types and constants
78
+ - Callers that could break
79
+
80
+ Example: "I need to add a retry parameter to HttpClient.request. Show the HttpClient class with the request method, HttpClientConfig, every caller of request(), and error types it throws."
81
+
82
+ ### Iterative search
83
+
84
+ If the first search misses:
85
+ 1. REPHRASE - the codebase may use different names than you expect
86
+ 2. BROADEN - add surroundings ("and the module that defines it")
87
+ 3. NARROW - add specifics ("the async version returning a Promise")
88
+ 4. Change ANGLE - search for tests, the type definition, or a usage example
89
+
90
+ ### Combining with other tools
91
+
92
+ - \`related_context\` - walk import/defines edges from a hit to reach neighbouring code
93
+ - \`read\` - full current file contents when you are about to edit (search returns excerpts)
94
+ - \`bash\` with grep/rg - exact strings (TODO markers, error messages, literal identifiers)
95
+ - \`bash\` with git - history: \`git log -p -- path/to/file\`
96
+
97
+ ### Index lifecycle
98
+
99
+ - If a search says the index is empty, a background index is already running - retry shortly, or run \`/context-index\` for a synchronous build
100
+ - After large refactors, \`reindex\` (or \`/context-index\`) keeps results current; \`index_status\` reports freshness and measured token savings
101
+ - Incremental re-index only re-reads changed files, so it is cheap
102
+ `;
103
+
104
+ /**
105
+ * Apply the guidance section to mutable prompt options.
106
+ * No-op (and safe to call on every run) when the tool is inactive or the
107
+ * user turned guidance off. Returns whether it injected, for tests.
108
+ */
109
+ export function applyContextSearchGuidance(options: GuidanceTarget, enabled: boolean): boolean {
110
+ if (!enabled) return false;
111
+ if (!options.selectedTools.includes("context_search")) return false;
112
+ options.sections[CONTEXT_SEARCH_SECTION_KEY] = CONTEXT_SEARCH_GUIDELINES;
113
+ return true;
114
+ }