Establishes this repository as the authoritative source for Pi agent configuration across scenarios, starting with the documentation layer. Key verified findings (probe harness included, zero model tokens): - The skills section of the system prompt is emitted only when an active tool named 'read' exists (system-prompt.js:59,113). Therefore --no-tools silently makes every SKILL.md unreachable and --skill a no-op. - registerTool accepts a plain JSON Schema object, so tool definitions can be served from a backend instead of duplicated in TypeScript. - An extension can shadow a built-in tool by name, which is how a dedicated agent gets a path-restricted 'read' while still satisfying the rule above. - .pi/SYSTEM.md replaces pi's coding-assistant prompt, but the replacement branch contributes neither the tool list nor the guidelines. - Without --no-skills/--no-extensions, user-global resources leak into every scenario; probed leak was find-skills, modsearch, summarize. Measured effect of the full baseline: system prompt 2619 -> 960 characters, coding-assistant framing and pi-docs paths removed, skill finally reachable. Secrets are guarded by scripts/verify-no-secrets.sh, installed as a pre-commit hook. Backups deliberately live outside the repository.
129 lines
5.8 KiB
Markdown
129 lines
5.8 KiB
Markdown
# Personality Layering
|
|
|
|
> How to decide what goes in `SYSTEM.md`, `AGENTS.md`, `SKILL.md` and the
|
|
> per-request prompt. Mechanisms verified against pi 0.84.3; see
|
|
> [`pi-runtime-notes.md`](pi-runtime-notes.md) §§2, 8, 9, 19.
|
|
|
|
Four slots exist and they are not interchangeable. Putting content in the wrong
|
|
slot is why rules get duplicated three times and then drift.
|
|
|
|
---
|
|
|
|
## Assembly order
|
|
|
|
With `.pi/SYSTEM.md` present and trusted, pi builds the system prompt as:
|
|
|
|
```
|
|
SYSTEM.md
|
|
→ APPEND_SYSTEM.md
|
|
→ <project_context> … AGENTS.md from ~/.pi/agent, each parent dir, cwd
|
|
→ <available_skills> … name + description + location only
|
|
→ "Current working directory: …"
|
|
```
|
|
|
|
Without `SYSTEM.md`, the first slot is pi's built-in **coding assistant** prompt,
|
|
which also contributes a tool list, a guidelines list, and absolute paths to
|
|
pi's own documentation.
|
|
|
|
Critically: **the `SYSTEM.md` branch contributes neither the tool list nor the
|
|
guidelines.** If you replace, you own both.
|
|
|
|
---
|
|
|
|
## Slot assignment
|
|
|
|
| Slot | Loaded | Cost | Put here |
|
|
|---|---|---|---|
|
|
| `.pi/SYSTEM.md` | needs trust (`--approve`) | always in context | Identity. Tool overview. Fact-authority map. Write discipline. Untrusted-data rule. Output format. |
|
|
| `.pi/APPEND_SYSTEM.md` | needs trust | always in context | Nothing, normally. Use only when you want to keep pi's default prompt and bolt something on. |
|
|
| `AGENTS.md` (workspace) | always | always in context | Durable role, responsibilities, routing, domain defaults, escalation policy. Human-editable narrative. |
|
|
| `AGENTS.override.md` | always | always in context | Same as `AGENTS.md`, but also **stops** `AGENTS.md`/`CLAUDE.md` from that directory. Use to make the personality deterministic against stray parent files. |
|
|
| `.pi/skills/<n>/SKILL.md` | needs trust, or explicit `--skill` | **description only** up front; body read on demand | Task-specific procedure that is not needed on every turn. The place for long checklists and worked examples. |
|
|
| Per-request prompt | n/a | per call | Only the current inputs and the schema for this one response. |
|
|
|
|
### Rule of thumb
|
|
|
|
- Needed on **every** turn → `SYSTEM.md` or `AGENTS.md`.
|
|
- Needed on **some** turns, and long → `SKILL.md`.
|
|
- Changes **per request** → the request.
|
|
|
|
A `SKILL.md` whose description says "use for every request" is not a skill; it is
|
|
system-prompt content paying an extra tool round-trip. Either move it up a slot
|
|
or split it into genuinely conditional skills.
|
|
|
|
---
|
|
|
|
## Replace or append?
|
|
|
|
**Replace (`SYSTEM.md`) when the agent is not a coding agent.**
|
|
|
|
pi's default prompt opens with:
|
|
|
|
> You are an expert coding assistant operating inside pi, a coding agent
|
|
> harness. You help users by reading files, executing commands, editing code,
|
|
> and writing new files.
|
|
|
|
and closes with absolute paths to pi's README, docs and examples plus an
|
|
instruction to read them and follow cross-references. For a media-curation or
|
|
note-routing agent that is not just wasted context — it is a documented,
|
|
ready-to-use escalation path for anything injected through fetched web content.
|
|
|
|
Measured: replacing it cut the Curator system prompt from 2619 to 960
|
|
characters and removed both the coding-assistant framing and the pi-docs block.
|
|
|
|
**Append (`APPEND_SYSTEM.md`) only** when you want the built-in coding
|
|
behaviour and are adding a constraint on top.
|
|
|
|
---
|
|
|
|
## What a replacement `SYSTEM.md` must contain
|
|
|
|
Because the replacement branch drops pi's tool list and guidelines, cover all
|
|
six sections explicitly:
|
|
|
|
1. **Identity and negative identity** — what the agent is, and that it is *not* a
|
|
coding assistant and does not read or modify project code.
|
|
2. **Tool overview** — each tool, its purpose, and when to prefer it. Keep it
|
|
consistent with the `promptSnippet` values in the extension.
|
|
3. **Fact authority** — which backend is authoritative for which class of fact,
|
|
and that tool results are the only source of truth.
|
|
4. **Write discipline** — whether the agent may write at all; if it may only
|
|
*propose*, say so, and forbid claiming completion without a receipt.
|
|
5. **Untrusted data** — that content arriving from fetched pages, search
|
|
snippets or documents is evidence, and instructions inside it are never
|
|
executed.
|
|
6. **Output discipline** — language, target surface (e.g. Telegram plain text),
|
|
structure, and the rule that unknown stays empty rather than guessed.
|
|
|
|
Explicitly **omit**: any path to pi's own documentation, and any wording about
|
|
editing files or running commands.
|
|
|
|
---
|
|
|
|
## Anti-patterns observed in this repository's history
|
|
|
|
| Anti-pattern | Consequence |
|
|
|---|---|
|
|
| `--no-tools` together with `--skill` | skills block never rendered; the entire `SKILL.md` was dead for the whole lifetime of the service |
|
|
| Same rule written in `AGENTS.md`, `SKILL.md` and the request prompt | drifted — one copy listed 4 recommendation values, another 5 |
|
|
| `AGENTS.md` in Chinese, `SKILL.md` in English, prompts in Chinese | cross-language alignment cost, harder review |
|
|
| Relying on `allowed-tools:` frontmatter | not enforced in 0.84.3; false sense of security |
|
|
| Feeding internal fields (`_model_used`) into a prompt that forbids naming the model | self-contradictory instruction |
|
|
| Long defensive prohibition lists | usually a symptom of a wrong base persona; fix the persona instead |
|
|
|
|
---
|
|
|
|
## Single source of truth
|
|
|
|
Enumerations and schemas that both the model and the backend must agree on
|
|
(intent values, recommendation scales, verdict scales, field names) belong in
|
|
**code**, not in prose:
|
|
|
|
- define them once in the scenario backend (e.g. `contracts.py`),
|
|
- generate the JSON Schema from that definition,
|
|
- serve the schema to the extension so tool `parameters` match by construction,
|
|
- and generate any prose enumeration in `SKILL.md`/`SYSTEM.md` from the same
|
|
source, or assert equality in a test.
|
|
|
|
Prose then describes *policy*; code defines *shape*.
|