Files
pi-map/openspec/changes/project-map-prompt-injection/design.md
T

8.5 KiB

Design: Project Map Prompt Injection

Status

Field Value
Phase Design
Based on Spec
Next Tasks

Design summary

This change adds a runtime guidance layer on top of the paired map/index artifact system. The implementation should not redesign map generation or retrieval. Instead, it should add a well-scoped injection pipeline that:

  • emits honest startup hints before init,
  • preloads the root pair after init,
  • expands under a hybrid budget,
  • avoids redundant reinjection by scanning real outgoing context,
  • varies guidance strength through explicit modes,
  • proves correctness with integration-heavy validation.

Affected areas

Source files likely to change

  • pi-extension.ts
  • shared config handling (src/config.ts or equivalent)
  • runtime helpers for map/index discovery and injection selection
  • tests covering extension lifecycle and per-turn behavior
  • docs/runtime guidance surfaces if needed

New modules likely to appear

  • src/prompt-injection.ts or equivalent runtime helper
  • optional helper for canonical marker construction / detection
  • optional helper for token-budget estimation across paired artifacts

Architecture changes

1. Injection policy helper

Centralize prompt-injection logic in one helper rather than scattering it across hooks.

Suggested responsibilities:

  • determine current mode (off / advisory / strong / strict),
  • detect whether artifacts exist,
  • build pre-init startup hint,
  • build post-init root-pair payload,
  • estimate expansion budget,
  • choose additional artifacts under the budget,
  • construct a canonical injected marker/block,
  • scan outgoing context or payload for that marker,
  • decide whether reinjection is required.

This helper is the main guard against drift between startup hints, context hooks, and strict-mode checks.

2. Injection surfaces

Use different extension surfaces for different responsibilities.

Pre-init / startup hint

Use before_agent_start for lightweight startup guidance before real artifacts exist.

Required behavior:

  • inject only a hint,
  • tell the agent to run project_map_init,
  • keep the hint visible and inspectable.

Post-init root-pair preload

Use before_agent_start to guarantee the initial post-init root-pair preload for a prompt.

Required behavior:

  • inject root .pi-map.index.md,
  • inject root .pi-map.md,
  • optionally append brief protocol text only if needed by the selected mode.

Relevant-turn reinjection

Use context for relevant-turn checks.

Required behavior:

  • inspect event.messages,
  • decide whether the canonical block is already present,
  • only add the root pair / budgeted expansion if absent,
  • avoid rescanning on every trivial turn in strong mode.

Payload fallback

Use before_provider_request only as a fallback or debugging surface when message-layer detection is insufficient.

3. Canonical marker design

Deduplication depends on stable canonical detection.

The implementation should stamp injected content with a canonical marker block.

Recommended v1 shape:

  • a deterministic wrapper such as <!-- PI_MAP_ROOT_PAIR_START --> / <!-- PI_MAP_ROOT_PAIR_END -->,
  • normalized artifact identity lines for root .pi-map.index.md and root .pi-map.md,
  • trust-boundary text within the same wrapped block when the active mode requires it.

Marker rules:

  • stable across turns,
  • independent of provider formatting quirks,
  • easy to scan in both event.messages and final provider payload,
  • robust enough that root-pair presence can be detected without brittle full-text matching.

4. Budgeting

Budgeting should be deterministic and layered.

Context-window discovery and fallback

  • Prefer active-model context-window metadata exposed by Pi runtime/model selection.
  • If context-window metadata is unavailable, fall back to the configured absolute cap.
  • The fallback path should be explicit in logs/debug behavior so budget decisions remain auditable.

Required order

  1. compute effective budget from relative percentage + optional absolute cap,
  2. reserve the root pair first,
  3. expand outward using a deterministic traversal order,
  4. stop when the budget would be exceeded.

Traversal strategy

The spec does not force exact traversal heuristics, but the design should prefer:

  • root pair first,
  • shallow structural coverage before deep leaves,
  • predictable order over opaque scoring.

This keeps automatic injection understandable and auditable.

5. Mode control surface

Expose a config/runtime setting for the four modes.

Because the current project config is loaded from flat JSON in .pi-project-map.json, v1 should prefer a flat compatible shape rather than forcing an immediate nested/YAML migration.

Suggested v1 config shape:

{
  "promptInjectionMode": "strong",
  "contextBudgetPercent": 15,
  "contextBudgetMaxTokens": 100000
}

Migration note:

  • keep existing flat JSON loading in src/config.ts,
  • treat these as new additive keys,
  • decide explicitly whether existing contextBudget is deprecated, ignored for injection, or retained only for older LLM-analysis paths.

Optional runtime UX may later mirror thinking-level controls, but v1 implementation can start with config-driven mode selection as long as the semantics are the same.

6. Mode semantics

off

  • no automatic artifact injection,
  • no startup/init hint beyond existing tool/docs discovery.

advisory

  • startup/init hints enabled,
  • optional root-pair preload,
  • light reminders,
  • weaker reinjection behavior.

strong

  • root-pair preload required,
  • budgeted expansion required,
  • relevant-turn reinjection checks required,
  • reminders before edits and architecture-sensitive reasoning.

strict

  • everything in strong, plus:
  • when protocol path is missing during sensitive actions, require explicit bypass justification.

7. Relevant-turn detection

strong mode should not rescan on every turn.

Relevant-turn triggers should be mapped to concrete runtime signals where possible:

  • agent start,
  • edit intent / edit tool preparation,
  • architecture-sensitive planning prompts,
  • compaction completion,
  • root-pair artifact change detection.

This will likely require some combination of:

  • hook-local heuristics,
  • observed tool calls,
  • file timestamp/hash checks for root artifacts,
  • compaction event handling.

8. Visibility model

The design should preserve mixed visibility.

  • startup hints: visible and inspectable,
  • raw injected artifact blocks: agent-visible by default,
  • the fact that automatic injection exists should remain discoverable.

The implementation may use hidden custom message types for artifact payloads, but should not make startup/init behavior opaque.

9. Validation strategy

This change is validation-heavy.

Unit tests alone are not enough, because the main risk is runtime interaction between hooks, message mutation, compaction, and reinjection.

Integration focus areas

  • startup before init,
  • startup after init,
  • root-pair marker insertion,
  • reinjection suppression when marker already exists,
  • reinjection after compaction,
  • reinjection after artifact mutation,
  • mode differences,
  • strict-mode bypass path,
  • mixed visibility expectations,
  • synthetic event-sequence coverage for relevant-turn heuristics such as edit-intent, architecture-sensitive reasoning, compaction, and artifact invalidation.

10. Documentation impact

Runtime guidance docs must align with the spec, but retrieval docs remain separate.

Docs should teach:

  • startup hint before init,
  • root-pair automatic preload after init,
  • trust boundary,
  • mode ladder,
  • relevant-turn reinjection behavior,
  • integration-test importance.

Risks

Risk Mitigation
Message-level scanning misses provider serialization quirks Add payload fallback via before_provider_request
Root-pair marker becomes brittle Use deterministic boundaries and normalized artifact identity lines
15% + 100k is too aggressive in some fleets Keep both knobs configurable and document the opinionated default
Relevant-turn detection becomes fuzzy Centralize detection heuristics and prove them with integration tests
strict mode causes friction Keep strong as default and isolate strict-only bypass behavior

Settled defaults

  • Root pair is always guaranteed after init.
  • Reinjection avoidance is based on canonical outgoing-context scanning.
  • Retrieval remains out of scope.
  • Mixed visibility is the intended baseline.
  • Four modes exist, with strong as default.
  • Default budget is 15% of active context window, capped at 100k tokens.