Files
pi-agent-config/scenarios/curator/profile.toml
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

128 lines
4.9 KiB
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"