Feature #1550
openFeature #1513: Implémenter des agents conversationnels spécialisés pour la qualification des demandes sur claude code
API: mode-aware persona composition, security rules and credential guard
0%
docs/superpowers/specs/2026-08-03-specialized-intake-agents-design.md
Description
**Surface:** backend (`api/`)
**Depends on:** #1549
**Blocks:** nothing
This is the actual "specialized agent" of #1513: make the streamed persona depend on the conversation's mode.
In `application/stream_assistant_reply.py`, compose the system prompt as `SYSTEM_PERSONA + MODE_MODULE[request_type]` instead of `SYSTEM_PERSONA` alone. **Do not fork the persona into three copies.** The no-code rule and the `[[REQUEST_READY]]` protocol — including the `safe_emit_len` partial-marker streaming guard (`:68`) — are load-bearing; three standalone personas means three places for them to drift. One shared base, three appended modules.
A **null `request_type` must reproduce today's prompt byte-for-byte**. That is the regression guard on every conversation that already exists.
Each module instructs the agent to cover its mode's slots before emitting `[[REQUEST_READY]]`. This **informs** readiness — it never blocks filing (epic AC #8).
The `security` module carries two rules that no other mode has:
1. **Never invite the client to probe further.** No "can you try to reproduce it", no "what happens if you...". We do not direct a client to test a live vulnerability.
2. **Credential guard.** If the client pastes something token/key/password-shaped, the agent tells them not to share it here, does **not** repeat it back, and does not carry it into the draft. The repo's standing "never print secrets" rule, applied to the one path where a client is most likely to volunteer one.
Also: the `bug` module proactively offers the screenshot upload. `useStagedAttachments` already exists — this is prompt work, not a new capability.
## Acceptance criteria
- [ ] The composed system prompt for each mode contains that mode's module; a `bug` conversation and a `feature` conversation produce **different** prompts.
- [ ] `request_type=None` produces a prompt **identical to today's** (byte-for-byte assertion against the current `SYSTEM_PERSONA` composition).
- [ ] `SYSTEM_PERSONA` remains a single definition — a test asserts there is exactly one persona constant and the modules are appended, not substituted.
- [ ] The `[[REQUEST_READY]]` marker and `safe_emit_len` behaviour are unchanged in every mode, including the partial-marker-never-streamed guarantee.
- [ ] The `security` module contains no instruction that invites reproduction or further probing (asserted against the module text).
- [ ] Given a transcript containing a token-shaped string, the security module's credential rule is present in the prompt; a unit test covers the rule text, and the pasted value is not echoed into the persisted assistant message.
- [ ] The `bug` module mentions the screenshot/attachment offer.
- [ ] Language selection still wins: the module text does not override the "always respond in {language}" system turn.
- [ ] Gates green: `python -m pytest -q` (**run serially**), `ruff check .`, `mypy src`. TDD: failing test first.
No data to display