# 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 /.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"