The curator application code has moved from codex-workspace/server-management/deploy/curator to /home/claw/pi-workspaces/curator (starting its own git repo with the preserved history). Update profile.toml's backend and the plan's working-directory references to match.
134 lines
6.2 KiB
TOML
134 lines
6.2 KiB
TOML
# curator — Pi scenario profile
|
|
#
|
|
# This file describes the configuration that is DEPLOYED.
|
|
#
|
|
# Current state: plan phase 3. The agent has five read/propose tools served over a
|
|
# loopback bridge, and one long-lived pi process per Telegram chat.
|
|
#
|
|
# The enforcement point is PiLaunchConfig in
|
|
# pi-agent-config/shared/lib/py/pi_rpc.py, built by curator/pi_session.py. The
|
|
# flags below are asserted by
|
|
# test_pi_isolation_flags_match_the_deployed_contract, so this file and the code
|
|
# cannot drift silently.
|
|
|
|
[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 beside the agent's .pi workspace in its own git repo
|
|
# at /home/claw/pi-workspaces/curator. The agent itself reads only .pi/ and its
|
|
# extensions, never this repository's Python code (no `read` tool).
|
|
backend = "/home/claw/pi-workspaces/curator"
|
|
deploy = "managed"
|
|
|
|
[model]
|
|
provider = "zenmux"
|
|
primary = "openai/gpt-5.6-luna"
|
|
fallback = "x-ai/grok-4.6"
|
|
|
|
[model.thinking]
|
|
# Split by role. The conversation turn has to reason about tool results, so it
|
|
# keeps "high". Intent classification and extraction produce JSON for a parser and
|
|
# run at the front of every message, where they were the dominant p50 contributor.
|
|
conversation = "high"
|
|
structured = "medium"
|
|
|
|
[session]
|
|
# One long-lived `pi --mode rpc` process per Telegram chat, keyed by a uuid5 of
|
|
# the chat id, plus one shared toolless process for structured tasks. A stable
|
|
# prompt prefix across turns is what makes provider prompt caching effective;
|
|
# a process per message paid for the whole prompt every time.
|
|
strategy = "long-lived-rpc"
|
|
rotate_after_prompts = 24
|
|
rotate_after_messages = 60
|
|
|
|
[isolation]
|
|
# Enforced in curator/pi_agent.py::_isolation_args. Verified effect is recorded
|
|
# in docs/evidence/2026-08-27-curator-phase0-prompt.md.
|
|
no_tools = false # the agent has tools now
|
|
no_builtin_tools = true # bash / edit / write stay unreachable, extension
|
|
# tools stay reachable. An explicit `--tools`
|
|
# allowlist is deliberately NOT used: it filters the
|
|
# registry and would stop the extension registering
|
|
# anything at all.
|
|
no_extensions = true # ...except the one named under [resources]
|
|
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
|
|
|
|
[personality]
|
|
# Both are system-prompt files, so --no-context-files does not affect them.
|
|
#
|
|
# SYSTEM.md contains a GENERATED tool list. It has to: pi omits its own tool list
|
|
# when --system-prompt is used, because the customPrompt branch returns before
|
|
# `toolsList` is assembled, so promptSnippet and promptGuidelines never reach the
|
|
# model. Measured effect of not having it: the agent called a tool in one run out
|
|
# of four and answered from memory in the other three.
|
|
# Regenerate with scripts/verify-generated.sh --fix.
|
|
system_prompt = ".pi/SYSTEM.md" # conversation, with tools
|
|
# A separate prompt for the toolless structured turns. Handing them the
|
|
# tool-bearing prompt would tell the model it can query the library when it
|
|
# cannot.
|
|
structured_system_prompt = ".pi/SYSTEM.structured.md"
|
|
append_system_prompt = ".pi/APPEND_SYSTEM.md" # durable domain policy
|
|
context_files = [] # deliberately none
|
|
|
|
[resources]
|
|
extensions = [".pi/extensions/curator-tools.ts"]
|
|
# Vendored into .pi/extensions/_shared/ by deploy-scenario.sh, because a tracked
|
|
# extension cannot resolve an import from shared/ once installed outside the repo.
|
|
shared_extensions = ["pi-guard-base.ts"]
|
|
# Deliberately empty, and it is not an oversight. pi emits the skills section only
|
|
# when a tool named `read` is active; Curator's tools are all domain-specific, so
|
|
# every --skill argument would be discarded in silence. Measured: with tools
|
|
# [query_library, lookup_online, counts] the prompt contained no skills section
|
|
# and no skill names, with and without --system-prompt. The media policy lives in
|
|
# APPEND_SYSTEM.md, which is unconditional.
|
|
skills = []
|
|
|
|
[tools]
|
|
# Served by the backend at /tools from curator/contracts.py, so the tool the model
|
|
# sees and the endpoint that answers it are the same object. Listed here for
|
|
# review only; this file is not the source.
|
|
allow = ["query_library", "lookup_online", "book_reviews", "counts", "propose_write"]
|
|
|
|
[budget]
|
|
# One deadline per user turn, enforced with the RPC abort command rather than by
|
|
# killing the process, so the session survives a slow answer and the next message
|
|
# does not pay to start up. The old per-invocation timeout did not compose: a
|
|
# single message could run interpret + query + answer and take three times the
|
|
# configured value.
|
|
turn_deadline_seconds = 180
|
|
startup_timeout_seconds = 60
|
|
|
|
[env]
|
|
# Explicit allowlist, enforced in pi_agent.ENV_ALLOWLIST. Notably absent: every
|
|
# CURATOR_* credential, including the Telegram bot token and the Radarr, Sonarr,
|
|
# Plex and Tavily keys. The provider key is read by pi itself from
|
|
# ~/.pi/agent/models.json and does not travel through the environment.
|
|
minimal = true
|
|
allowlist = [
|
|
"PATH", "HOME", "LANG", "LC_ALL", "LC_CTYPE", "TZ",
|
|
"NODE_OPTIONS", "SSL_CERT_FILE", "SSL_CERT_DIR", "NO_PROXY", "no_proxy",
|
|
]
|
|
# The bridge URL and a per-conversation token, generated at start and passed only
|
|
# through the child's environment. The token grants access to this service's read
|
|
# tools and to propose_write, which the policy engine still adjudicates; it grants
|
|
# nothing else and outlives nothing.
|
|
extra = ["CURATOR_BRIDGE_URL", "CURATOR_BRIDGE_TOKEN"]
|
|
|
|
[bridge]
|
|
# Ephemeral loopback port, chosen by the kernel. Not configurable and not
|
|
# predictable; the agent's only route to the library.
|
|
bind = "127.0.0.1"
|
|
port = 0
|
|
auth = "per-conversation token, compared with compare_digest"
|
|
|
|
[secrets]
|
|
env_file = "/home/claw/.config/curator/curator.env"
|