feat(curator): deploy the phase-0 system prompt, and correct a misleading README figure

The workspace now holds .pi/SYSTEM.md and .pi/APPEND_SYSTEM.md and nothing else.

SYSTEM.md is rewritten for what is actually deployed. The version committed in
07dd648 described five tools that will not exist until phase 3; shipping it would
have invited the model to call tools it does not have. The capability section now
states plainly that the agent has no tools and that every fact arrives in the
request. The phase-3 target, including the full tool-bearing launch contract, is
recorded in the plan as §4b together with why each part cannot be enabled sooner.

profile.toml likewise describes the deployed configuration rather than the target,
so that deploy-scenario.sh validates against reality and the path check means
something.

Recovered from the retired SKILL.md and folded into SYSTEM.md: the rule that the
current request's schema and length limits override everything else, and that a
JSON task returns exactly one JSON value with no fences. Phase 0's four prompt
types all depend on it, and it was the one part of that file not already covered.

Measured before and after on the real workspace, with flags read from the code
rather than transcribed (docs/evidence/2026-08-27-curator-phase0-prompt.md):

- expert coding assistant framing: present -> gone
- pointer to pi's own documentation: present -> gone
- the 64-line media policy: absent -> present
- workspace AGENTS.md: loaded -> blocked
- parent-directory AGENTS.md: LEAKED -> blocked
- <available_skills>: absent both times

Two things this confirms on the production configuration rather than a synthetic
probe. --skill was genuinely a no-op: it pointed at a real 64-line SKILL.md and
the skills block was still absent, because pi emits it only when a tool named
read is active and --no-tools deactivates everything. And --no-context-files is
the only switch that stops parent-directory pollution: a marker planted in
/home/claw/pi-workspaces/AGENTS.md reached the prompt before and not after.

Deleting the now-dead AGENTS.md and SKILL.md from the workspace changed the
prompt length by zero bytes, which is the proof that they were dead.

README corrected. Its table cited 960 characters as Curator's system prompt after
the change; that figure came from a few-line stub SYSTEM.md in the isolation
probe, and the real prompt is 3539 -- larger, not smaller. Presenting the stub
measurement as Curator's was misleading, and "72% smaller" was wrong. The prompt
grew because roughly 1.9 KB of pi scaffolding was replaced by domain policy that
had never loaded at all. The mechanism claim is unaffected.
This commit is contained in:
Kai
2026-08-27 23:09:20 -07:00
parent f25082223e
commit cf61a72bd2
7 changed files with 347 additions and 111 deletions
@@ -303,6 +303,154 @@ Telegram ──► TelegramGateway(薄适配器)
---
## 4b. 阶段 3 目标启动契约
`scenarios/curator/profile.toml` 始终描述**已部署**的配置,因此阶段 0 期间它是
无工具形态。下面是阶段 3 完成后它应当变成的样子,逐项理由见 §3 阶段 3。
阶段 0 与目标的差异,以及为什么现在不能直接上:
| 项 | 阶段 0 现状 | 阶段 3 目标 | 为什么不能提前 |
|---|---|---|---|
| 工具 | `--no-tools` | `--no-builtin-tools` + 6 个自有工具 | `curator-tools.ts``agent_api.py` 尚不存在 |
| skills | `--no-skills`,策略在系统提示里 | 三个自有 skill 目录 | skills 段落只在有激活的 `read` 工具时生成,无工具即为死代码 |
| 事实获取 | Python 取好放进 prompt | agent 自己调工具 | 方向 B 的前提是工具存在 |
| 会话 | 每条消息新起进程 | 长驻 RPC + 轮转 | 依赖 `shared/lib/py/pi_rpc.py` 接入 |
| thinking | 单一 `high` | 按角色三档 | 依赖 RPC 的 `set_thinking_level` |
| 写操作 | Python 直接写 | `propose_write` + 策略引擎 | 依赖阶段 2 的 `service.py` |
```toml
# curator — Pi scenario profile
#
# STATUS: target configuration. The live service does NOT yet run this; it is
# still on the pre-refactor launch parameters. Switching over happens in plan
# phase 3 (docs/plans/2026-08-curator-agent-refactor.md).
#
# This file is the single source of truth for the launch contract.
# scripts/deploy-scenario.sh renders it into <workspace>/.pi/launch.json, and
# curator/pi_agent.py MUST read that file and fail closed if it is missing:
# silently running without --no-extensions would widen the agent's reach.
[scenario]
name = "curator"
description = "Personal book / film / TV / music curation agent for the Curator service."
workspace = "/home/claw/pi-workspaces/curator"
session_dir = "/home/claw/.local/share/pi-curator/sessions"
service = "curator.service"
# Application code lives in a separate repository and is intentionally outside
# the agent's workspace.
backend = "/home/claw/codex-workspace/server-management/deploy/curator"
[model]
provider = "zenmux"
primary = "openai/gpt-5.6-luna"
fallback = "x-ai/grok-4.6"
# One global thinking level was the dominant p50 latency contributor: intent
# classification ran at "high" at the front of every message. Differentiate.
[model.thinking]
conversation = "high"
extraction = "low"
synthesis = "medium"
[session]
# Per Telegram chat. The client appends a rotation counter, so history stays
# greppable on disk instead of being summarised away.
id_prefix = "curator-tg"
rotate_after_prompts = 20
rotate_after_messages = 50
strategy = "session-id"
[isolation]
# Verified combination — see docs/evidence/. Result: no coding-assistant
# framing, no pi-docs block, no parent-directory context pollution, only this
# scenario's own skills, only this scenario's own tools.
no_builtin_tools = true # not --tools: a registry allowlist would block
# tools registered dynamically from the backend
no_extensions = true
no_skills = true
no_prompt_templates = true
no_themes = true
no_context_files = true # the ONLY switch that stops parent-dir AGENTS.md;
# AGENTS.override.md does not (verified)
approve = true # required to load .pi/SYSTEM.md and .pi/settings.json
[personality]
# Both are system-prompt files, so --no-context-files does not affect them.
system_prompt = ".pi/SYSTEM.md" # replaces pi's default prompt
append_system_prompt = ".pi/APPEND_SYSTEM.md" # durable domain responsibilities
context_files = [] # deliberately none
[resources]
extensions = [".pi/extensions/curator-tools.ts"]
skills = [
".pi/skills/curator-core",
".pi/skills/video-arr",
".pi/skills/books-ingest",
]
[tools]
# Enforced twice: setActiveTools plus a tool_call block, both inside
# curator-tools.ts. The CLI is not the security boundary.
#
# `read` is a restricted override from shared/extensions/pi-guard-base.ts. It is
# mandatory, not optional: pi emits the skills section only when a tool named
# `read` is active, and skill bodies load through it.
allow = [
"read",
"curator_query_library",
"curator_lookup_online",
"curator_book_reviews",
"curator_counts",
"curator_propose_write",
]
# Structured-output tools, used only by the stateless extraction/synthesis calls
# (--no-session). They carry constrainedSampling + terminate.
structured_output = ["emit_extraction", "emit_reviews"]
# The agent cannot write. curator_propose_write only records a planned Plan and
# echoes the resolved identity; the deterministic policy engine in
# curator/service.py decides whether it executes. Receipts are harvested from
# tool_execution_end, never phrased by the model.
receipt_tools = []
[tools.read_policy]
# Must include the skill directories or skill bodies become unloadable.
roots = [".pi/skills"]
extensions = [".md"]
max_chars = 40000
[bridge]
# Loopback only, with a secret generated at service start and passed through env.
# pi-guard-base asserts the host is loopback and refuses anything else.
host = "127.0.0.1"
port = 8767
# The backend serves tool definitions as JSON Schema at /tools so that the schema
# has exactly one owner; registerTool accepts a plain JSON Schema object.
spec_endpoint = "/tools"
[budget]
# Per-invocation timeouts do not compose: the old configuration could spend
# 4 x 120 s on a single message with no overall bound. One deadline per user
# message, enforced with RPC abort.
turn_deadline_seconds = 180
extraction_deadline_seconds = 120
startup_timeout_seconds = 60
[env]
# Explicit allowlist. Notably absent: every CURATOR_* credential. The provider
# key is read by pi itself from ~/.pi/agent/models.json.
minimal = true
allowlist = ["PATH", "HOME", "LANG", "LC_ALL", "TZ", "SSL_CERT_FILE", "SSL_CERT_DIR"]
extra = ["PI_TOOL_BRIDGE_URL", "PI_TOOL_BRIDGE_TOKEN"]
[secrets]
env_file = "/home/claw/.config/curator/curator.env"
```
---
## 5. 实施者硬约束
1. 阶段 −1 检查点未全绿前禁止改任何源码。**已完成,可继续。**