#11921: feat(hooks): support systemPrompt injection in before_agent_start hook
agents
stale
## Summary
- Allow `before_agent_start` hooks to return a `systemPrompt` field that gets injected into the agent's system prompt, in addition to the existing `prependContext` field
- System prompt patches are wrapped in XML tags and idempotently replaced each turn — no accumulation across compaction boundaries
- Both `prependContext` (8K chars) and `systemPrompt` (4K chars) are size-capped to prevent hooks from bloating context
## Motivation
Plugins can already inject context into user messages via `prependContext`, but some use cases (mission directives, persistent constraints, role instructions) belong in the system prompt where they carry higher authority and don't duplicate across message history. Unlike `prependContext` which accumulates in every turn's user message until compaction, system prompt content exists once and is rebuilt fresh each turn.
## Test plan
- [x] `pnpm build` passes
- [x] All 158 tests in `src/agents/pi-embedded-runner/` pass
- [x] Existing `prependContext` behavior preserved (with added size cap)
- [ ] Manual: verify plugin returning `systemPrompt` from `before_agent_start` hook injects into system prompt
🤖 Generated with [Claude Code](https://claude.com/claude-code)
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This PR extends the `before_agent_start` hook handling in `src/agents/pi-embedded-runner/run/attempt.ts` to support an additional `systemPrompt` return field alongside the existing `prependContext`. It introduces size caps for both hook-provided strings and wraps `systemPrompt` patches in an XML-tagged block that is intended to be replaced idempotently (by stripping any prior patch block before re-appending).
Overall, the change fits into the embedded runner’s pre-prompt phase: hooks can now modify the effective user prompt and/or override the agent session’s system prompt before `activeSession.prompt(...)` is invoked.
<h3>Confidence Score: 3/5</h3>
- This PR is mostly safe to merge, but has a couple of correctness/robustness issues around system-prompt patching semantics that should be addressed first.
- The core flow (cap + apply override) is straightforward, but the patch stripping approach can delete unintended content if the payload contains the chosen delimiters, and internal run tracking can diverge from the actual system prompt used after patching.
- src/agents/pi-embedded-runner/run/attempt.ts
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#14602: fix(plugins): hook systemPrompt gets collected then thrown away (#1...
by yinghaosang · 2026-02-12
87.5%
#8178: feat: allow before_agent_start to override the prompt
by richardfogaca · 2026-02-03
86.8%
#6017: feat(hooks): add systemPrompt and tools to before_agent_start event
by yajatns · 2026-02-01
85.1%
#22705: fix(agents): merge before_agent_start hook systemPrompt into sessio...
by mushuiyu422 · 2026-02-21
81.7%
#11732: feat(plugins): add injectMessages to before_agent_start hook
by antra-tess · 2026-02-08
80.7%
#10327: Fix: persist original prompt to transcript, not plugin-modified pro...
by GodsBoy · 2026-02-06
80.2%
#7091: feat: add pre-answer hooks system for automatic context injection
by dizhaky · 2026-02-02
77.6%
#20426: feat: make llm_input/llm_output modifying hooks for middleware patt...
by chandika · 2026-02-18
77.1%
#21954: Prevent bootstrap hook truncation crash in prompt report
by graysurf · 2026-02-20
77.0%
#22624: feat(plugins): add before_context_send hook and model routing via b...
by davidrudduck · 2026-02-21
76.8%