Files
pi-agent-config/docs/personality-layering.md
T
Kai 07dd648b5f feat: scenarios for curator/memo-inbox/pi-grok, deploy and backup tooling
Scenarios
- memo-inbox: mirrored by copying; the live directory was not moved or modified
  and the service was not restarted. All four tracked files match byte for byte
  (pi-diff.sh reports SAME). Marked deploy = "mirror" so deploy-scenario.sh
  refuses --apply: applying a mirror would invert the direction of truth and
  could change a service in daily use.
- curator: target configuration, not yet deployed. .pi/SYSTEM.md replaces pi's
  coding-assistant prompt; durable role text is in .pi/APPEND_SYSTEM.md;
  profile.toml is the single source of truth for the launch contract.
- pi-grok: registered only. It is genuinely a coding agent, so the isolation
  baseline does not apply in full.

Corrections to the documentation, found by testing rather than by reading
- AGENTS.override.md does NOT block parent-directory context files; it only
  shadows its own directory. Verified: with an override file in the workspace, a
  marker in /tmp/AGENTS.md still reached the system prompt. The only effective
  switch is --no-context-files, so durable role text must live in
  .pi/APPEND_SYSTEM.md, which is a system-prompt file and unaffected by -nc.
  Verified end state: no coding-assistant framing, no pi-docs block, own
  identity and role text present, no parent pollution, only own skills/tools.
- PI_CODING_AGENT_DIR isolates settings/models/auth/trust/extensions/skills/
  prompts/themes under the agent directory -- stronger than the --no-* flags
  because it also repoints credentials -- but does NOT cover ~/.agents/skills.
  Measured: find-skills, modsearch and summarize still leak. So it complements
  --no-skills rather than replacing it.
- --append-system-prompt accepts a file path, which pi-grok relies on.
- cwd is what anchors .pi discovery: a probe that forgot cwd silently lost
  .pi/SYSTEM.md and kept the coding-assistant persona.

Tooling (all dry-run by default; none of them restarts a service)
- pi-diff.sh: compares tracked config against the live install in both
  directions, with a key-redacted comparison for models.json
- deploy-scenario.sh: installs a workspace and renders profile.toml into
  .pi/launch.json, then checks that every referenced path exists
- deploy-runtime.sh: renders models.json from its template, refusing placeholder
  or missing keys. Verified byte-identical to the live file
- pi-backup.sh / pi-restore.sh: archives outside the repo, sha256 manifest
  verified before any restore, live paths preserved rather than overwritten

Fixed while testing: pi-backup.sh compared the destination against the repo root
literally, so a relative --dest ./backups wrote credential archives into the work
tree. Now canonicalised with realpath; ./backups, an absolute in-repo path and
./docs/../backups are all refused.
2026-08-26 23:17:12 -07:00

6.9 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 shadows AGENTS.md/CLAUDE.md in its own directory only. It does not stop parent directories — verified. Rarely the right tool.
.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.

Deterministic personality requires -nc

Context files layer from ~/.pi/agent/AGENTS.md and from every parent directory of the working directory. AGENTS.override.md shadows only its own directory, so it cannot protect you: with an override file present in the workspace, a marker placed in /tmp/AGENTS.md still reached the system prompt.

The only switch that stops the upward walk is --no-context-files (-nc), and it drops the workspace's own file too. So for an agent whose personality must be reproducible:

  • pass -nc;
  • put identity in .pi/SYSTEM.md;
  • put durable role text in .pi/APPEND_SYSTEM.md;
  • keep no AGENTS.md in the workspace at all.

Both SYSTEM.md and APPEND_SYSTEM.md are system-prompt files, not context files, so -nc does not affect them. Verified: identity and role text present, parent marker absent.

AGENTS.md remains the right slot for a shared, layered convention — for example a repository-wide instruction that every agent working in a source tree should honour. It is the wrong slot for a single-purpose service agent.

Rule of thumb

  • Needed on every turn → SYSTEM.md or APPEND_SYSTEM.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.