Files
pi-agent-config/docs/personality-layering.md
T
Kai cbba8faabc docs: pi 0.84.3 runtime mechanics, isolation baseline, personality layering, gateway patterns
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.
2026-08-26 22:47:53 -07:00

5.8 KiB

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 §§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.