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.
This commit is contained in:
@@ -19,8 +19,8 @@ four independent layers. Use all four; each one covers a different failure mode.
|
||||
│ --no-prompt-templates / --no-themes / -nc / project trust │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ L2 Personality who the agent is │
|
||||
│ .pi/SYSTEM.md (replace) · APPEND_SYSTEM.md · AGENTS.md │
|
||||
│ AGENTS.override.md · --system-prompt │
|
||||
│ .pi/SYSTEM.md (replace) · .pi/APPEND_SYSTEM.md · -nc │
|
||||
│ AGENTS.md only if parent-dir layering is acceptable │
|
||||
├──────────────────────────────────────────────────────────────┤
|
||||
│ L3 Capability which tools exist and are active │
|
||||
│ --no-builtin-tools · --tools · --exclude-tools │
|
||||
@@ -142,8 +142,11 @@ capable, because the skill is finally reachable.
|
||||
2. **`env` discipline is the only secret boundary.** Without an explicit `env=`
|
||||
allowlist the node process inherits every `*_API_KEY` in the unit file.
|
||||
3. **Parent-directory context files.** Nothing prevents a future
|
||||
`~/AGENTS.md` from layering into every scenario. Mitigate with `-nc` plus
|
||||
`SYSTEM.md`, or an `AGENTS.override.md` in the workspace.
|
||||
`~/AGENTS.md` from layering into every scenario, and `AGENTS.override.md`
|
||||
does **not** prevent it -- it only shadows its own directory (verified: a
|
||||
marker in `/tmp/AGENTS.md` still reached the prompt). The only effective
|
||||
switch is `-nc`, which means durable role text must live in
|
||||
`.pi/APPEND_SYSTEM.md` rather than `AGENTS.md`.
|
||||
4. **Workspace should be read-only to the service.** `--approve` trusts
|
||||
everything project-local, so a writable `.pi/` is a code-execution path.
|
||||
Enforce with systemd `ReadOnlyPaths=`.
|
||||
|
||||
@@ -37,13 +37,37 @@ guidelines.** If you replace, you own both.
|
||||
| `.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 also **stops** `AGENTS.md`/`CLAUDE.md` from that directory. Use to make the personality deterministic against stray parent files. |
|
||||
| `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 `AGENTS.md`.
|
||||
- Needed on **every** turn → `SYSTEM.md` or `APPEND_SYSTEM.md`.
|
||||
- Needed on **some** turns, and long → `SKILL.md`.
|
||||
- Changes **per request** → the request.
|
||||
|
||||
|
||||
@@ -156,17 +156,48 @@ Probe evidence:
|
||||
| isolation flags only | true | true | false | 2619 |
|
||||
| `+ .pi/SYSTEM.md + --approve` | **false** | **false** | **true** | **960** |
|
||||
|
||||
## 9. Context files are loaded from every parent directory
|
||||
## 9. Context files are loaded from every parent directory, and `AGENTS.override.md` does not stop that
|
||||
|
||||
Load order: `~/.pi/agent/AGENTS.md`, then each parent directory walking up from
|
||||
cwd, then cwd. `AGENTS.override.md` replaces `AGENTS.md`/`CLAUDE.md` **for that
|
||||
directory only**; other directories still layer normally.
|
||||
cwd, then cwd.
|
||||
|
||||
`AGENTS.override.md` replaces `AGENTS.md`/`CLAUDE.md` **for its own directory
|
||||
only**. Parent directories still layer normally — the docs say so explicitly
|
||||
("Context files from other directories still layer normally") and it is easy to
|
||||
get this wrong.
|
||||
|
||||
Probed: with `AGENTS.override.md` present in the workspace and a marker file at
|
||||
`/tmp/AGENTS.md`, the marker **still appeared** in the system prompt.
|
||||
|
||||
| Configuration | parent `/tmp/AGENTS.md` in prompt |
|
||||
|---|---|
|
||||
| workspace has `AGENTS.override.md` | **yes** |
|
||||
| `--no-context-files` (`-nc`) | no |
|
||||
|
||||
So a stray `~/AGENTS.md` or `~/pi-workspaces/AGENTS.md` silently contaminates
|
||||
every scenario rooted below it. Neither existed on this host as of 2026-08-27,
|
||||
but nothing prevents one from appearing. Use `-nc` plus an explicit
|
||||
`SYSTEM.md`, or an `AGENTS.override.md` in the workspace, to make the
|
||||
personality deterministic. Probed: `-nc` removes the AGENTS.md marker.
|
||||
every scenario rooted below it, and an override file will not save you. Neither
|
||||
existed on this host as of 2026-08-27, but nothing prevents one from appearing.
|
||||
|
||||
**The only way to make the personality deterministic is `-nc`.** Since that also
|
||||
drops the workspace's own context file, the durable role content has to move into
|
||||
`.pi/SYSTEM.md` and `.pi/APPEND_SYSTEM.md`, which are system-prompt files rather
|
||||
than context files and are therefore unaffected by `-nc`.
|
||||
|
||||
Verified combination — no coding-assistant framing, no pi-docs block, own
|
||||
identity and role text present, parent pollution absent, only the scenario's own
|
||||
skill listed:
|
||||
|
||||
```
|
||||
--no-builtin-tools --no-extensions -e <ext> --no-skills --skill <dir>
|
||||
--no-prompt-templates --no-themes --approve -nc
|
||||
+ .pi/SYSTEM.md + .pi/APPEND_SYSTEM.md
|
||||
```
|
||||
|
||||
Note also that `cwd` is what anchors this discovery: launching pi from the wrong
|
||||
working directory silently drops `.pi/SYSTEM.md` and every workspace context
|
||||
file. A probe that forgot `cwd` produced a 2601-character prompt with the
|
||||
coding-assistant persona intact; with the correct `cwd` it produced 4082
|
||||
characters with the persona replaced.
|
||||
|
||||
## 10. Project trust gates `.pi/`, and CLI `-e` bypasses it
|
||||
|
||||
@@ -187,6 +218,55 @@ Non-interactive modes (`-p`, `--mode json`, `--mode rpc`) never prompt; they use
|
||||
`-e /path/to/ext.ts` avoids the trust question entirely, which is the most
|
||||
robust option for a systemd-managed gateway.
|
||||
|
||||
## 10b. `PI_CODING_AGENT_DIR` isolates the agent directory — but not `~/.agents/skills`
|
||||
|
||||
```
|
||||
PI_CODING_AGENT_DIR Override the config directory; default is ~/.pi/agent
|
||||
```
|
||||
|
||||
This is the strongest isolation lever available, and it is stronger than the
|
||||
`--no-*` flags because it repoints **credentials and trust** as well as
|
||||
resources. The `pi-grok` scenario on this host uses it:
|
||||
|
||||
```sh
|
||||
export PI_CODING_AGENT_DIR="$PI_GROK_HOME/.pi-agent"
|
||||
```
|
||||
|
||||
Measured, with a marker extension planted in both directories and no `--no-*`
|
||||
flags at all:
|
||||
|
||||
| Resource | default agent dir | `PI_CODING_AGENT_DIR=<iso>` |
|
||||
|---|---|---|
|
||||
| `<dir>/extensions/*` | `DEFAULT_EXT_LOADED` | `ISO_EXT_LOADED` — **isolated** |
|
||||
| `<dir>/skills/*` | *(none)* | `iso-skill` present — **isolated** |
|
||||
| `~/.agents/skills/*` | `find-skills, modsearch, summarize` | `find-skills, modsearch, summarize` — **still leaks** |
|
||||
|
||||
So it isolates `settings.json`, `models.json`, `auth.json`, `trust.json`,
|
||||
`extensions/`, `skills/`, `prompts/` and `themes/` **under the agent directory**,
|
||||
but `~/.agents/skills/` is a separate discovery root that it does not touch.
|
||||
|
||||
Practical consequences:
|
||||
|
||||
* Use `PI_CODING_AGENT_DIR` per scenario when scenarios should not share
|
||||
provider credentials, trust decisions or model defaults. It is the only way to
|
||||
stop one scenario's `auth.json` from being readable by another's agent.
|
||||
* It does **not** replace `--no-skills`. Keep the loading flags as well.
|
||||
* A companion variable exists: `PI_CODING_AGENT_SESSION_DIR`, overridden by
|
||||
`--session-dir`.
|
||||
|
||||
## 10c. `--append-system-prompt` accepts a file path
|
||||
|
||||
The help text says "Append text **or file contents**". `pi-grok` relies on this:
|
||||
|
||||
```sh
|
||||
--append-system-prompt "$PI_GROK_HOME/AGENTS.md"
|
||||
```
|
||||
|
||||
This is a third way to inject durable role text, alongside
|
||||
`.pi/APPEND_SYSTEM.md` and `AGENTS.md`. Unlike a context file it is immune to the
|
||||
parent-directory walk, and unlike `.pi/APPEND_SYSTEM.md` it needs no project
|
||||
trust. Useful when the role text must live outside the workspace.
|
||||
|
||||
## 11. User-global resources leak into every scenario
|
||||
|
||||
Probed with no isolation flags, from an unrelated workspace, the skills list was:
|
||||
|
||||
@@ -80,6 +80,7 @@ agent loop,于是 `AGENTS.md`/`SKILL.md` 大量篇幅在用散文对抗一个
|
||||
| P0-10 | `media_catalog.py:249-264,34,55` | `acquire` 成功后不清 `_cache`(TTL 300 s),此后最多 5 分钟查询把刚加入的作品报成 `not_found`。另:`Settings.catalog_cache_ttl_seconds`(默认 60)从未被 `MediaCatalog` 读取。 |
|
||||
| P0-11 | `pi_agent.py:41-54` | 未传 `--no-extensions`/`--no-skills`/`--no-themes`,用户级 `herdr-agent-state.ts`(287 行)、`pi-memo-trust.ts` 与 `~/.agents/skills/{find-skills,modsearch,summarize}` 泄入。实测 `PROBE_SKILLNAMES=["find-skills","modsearch","summarize"]`。`find-skills` 诱导 agent 安装更多 skill。 |
|
||||
| P0-12 | 全局 | **`SKILL.md` 从未生效**(`system-prompt.js:59,113` 的 `hasRead` 门禁)。`--skill`(`pi_agent.py:48`)是空操作。README:89-91 与 `deployment.zh-CN.md:467` 描述错误。 |
|
||||
| P0-14 | workspace 无 `-nc` | context file 从 cwd 的每一级父目录加载。`~/AGENTS.md` 或 `~/pi-workspaces/AGENTS.md` 一旦出现即污染两个场景,且 `AGENTS.override.md` **不能**阻断(已实测:override 存在时 `/tmp/AGENTS.md` 仍进入系统提示)。唯一有效开关是 `-nc`,因此长期职责必须移入 `.pi/APPEND_SYSTEM.md`。 |
|
||||
| P0-13 | 无 `.pi/SYSTEM.md` | Curator 跑在 pi 默认**编码助手**人格上("reading files, executing commands, editing code"),并附带 pi 自身 README/docs/examples 的绝对路径与"读完并跟随交叉引用"指令 —— 对注入而言是现成路径。 |
|
||||
|
||||
### P1
|
||||
@@ -128,10 +129,10 @@ Telegram ──► TelegramGateway(薄适配器)
|
||||
--no-builtin-tools │
|
||||
--no-extensions -e curator-tools.ts ────────────┘
|
||||
--no-skills --skill .pi/skills/{curator-core,video-arr,books-ingest}
|
||||
--no-prompt-templates --no-themes --approve
|
||||
--no-prompt-templates --no-themes --approve -nc
|
||||
│
|
||||
├─ .pi/SYSTEM.md 策展人格(替换编码助手)
|
||||
├─ AGENTS.override.md 持久职责 + 截断父目录上溯
|
||||
├─ .pi/APPEND_SYSTEM.md 长期领域职责
|
||||
└─ .pi/skills/* 按需加载的领域策略
|
||||
```
|
||||
|
||||
@@ -197,7 +198,7 @@ Telegram ──► TelegramGateway(薄适配器)
|
||||
| # | 动作 | 修复 |
|
||||
|---|---|---|
|
||||
| 1 | 建 `.pi/SYSTEM.md`(规格见 §4) | P0-13 |
|
||||
| 2 | 建 `AGENTS.override.md` 截断父目录上溯 | F7 隐患 |
|
||||
| 2 | 加 `-nc`,长期职责移入 `.pi/APPEND_SYSTEM.md`,workspace 不留 `AGENTS.md`(`AGENTS.override.md` **不能**阻断父目录,已实测) | F7 隐患 |
|
||||
| 3 | `SKILL.md` 策略暂并入 AGENTS(阶段 3 拆回),删除空操作 `--skill` | P0-12 |
|
||||
| 4 | 加载隔离:`--no-extensions -e <abs>` `--no-skills` `--no-themes` | P0-11 |
|
||||
| 5 | `env=` 白名单 + `start_new_session=True` + `killpg` | P0-7 / P1-2 |
|
||||
@@ -255,7 +256,7 @@ Telegram ──► TelegramGateway(薄适配器)
|
||||
5. 写操作策略引擎(§2 的五条) → 修 P0-2 / P0-4 / P0-5。
|
||||
6. `.pi/settings.json`:`compaction.keepRecentTokens` 调优,配合会话轮转。
|
||||
7. 观测:`message_update.usage` / `get_session_stats` → `control_events` → 修 P1-9。
|
||||
8. `AGENTS.override.md` / `SYSTEM.md` 定稿;skill 拆 `curator-core` /
|
||||
8. `.pi/SYSTEM.md` / `.pi/APPEND_SYSTEM.md` 定稿;skill 拆 `curator-core` /
|
||||
`video-arr` / `books-ingest`,按架构 §2.3 声明字段,**不依赖 `allowed-tools`
|
||||
frontmatter**(0.84.3 未消费) → 修 P1-6 / P1-7。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user