feat(pi): inject the safe schedule skill into every session (built-in, not grantable) #85

Merged
weiwen merged 1 commit from fm/evie-schedule-builtin into main 2026-07-30 21:51:20 +08:00
Owner

Make the schedule skill built-in (supersedes #84)

The operator decided the safe schedule skill should be built-in — always injected into every session, sandboxes included — rather than grantable. This supersedes the grantable approach in #84.

Change

Previously pi_argv(&config, sudo) injected bundled skills all-or-nothing, gated entirely to /sudo. That boundary exists to keep the dangerous control skill (skills/evie, which drives the Run verb — arbitrary host script execution — plus cross-chat Send/Prompt/Query) out of sandboxes.

This splits bundled skills into two classes via an explicit, audited allowlist (SAFE_BUNDLED_SKILLS, currently ["schedule"]):

  • Safe bundled skills → injected into every session (sudo AND sandboxed). Their whole surface is self-scoped: schedule/list/cancel, and scheduled send/prompt/run that re-enter the caller's own sandbox as their non-root drop target (see scoped_allows — the immediate Run verb stays rejected on the scoped socket).
  • Sudo-only bundled skills (the evie control skill, first-party integrations like immich) → still gated to the unsandboxed /sudo path. The control-skill boundary is preserved exactly.

Sandboxed sessions now get the safe skill via --skill, and its host path is bound read-only in sandboxed_pi_argv. The installed layout already resolves under the wholesale /nix bind, so no new bind is strictly needed in production; the explicit bind also covers the cargo run source-tree fallback and keeps injection self-contained.

Tests (security-sensitive boundary)

  • pi_argv_sandboxed_excludes_control_skill_but_includes_safe_schedule_skill: a sandboxed argv includes --skill .../schedule but NEVER skills/evie.
  • pi_argv_sudo_includes_bundled_skills: sudo gets both control + schedule.
  • sandboxed_pi_argv_binds_the_safe_schedule_skill: sandbox binds the schedule host path RO, never the control skill's.
  • safe_bundled_skill_dirs_holds_schedule_but_not_the_control_skill: allowlist guard.

just check green: fmt + clippy -D warnings + 488 tests.

Runbook

docs/schedule-skill-deploy-runbook.md brought over from #84 and simplified for the built-in approach: step 1 deleted (no skills_dir seeding, no /grant, no rebind — the skill auto-injects on the next session after redeploy). Remaining operator steps kept and kept-accurate: relocate the two briefing scripts to a sandbox-readable path, re-create morning-briefing+evening-review as sudo=false, and a 60s test-fire. Precondition that the schedule-rebuild steps need #83 merged AND redeployed is retained.

Skill content (skills/schedule/SKILL.md) reused from #84, verified against the current evie schedule/list/cancel CLI and scoped_allows.

## Make the schedule skill built-in (supersedes #84) The operator decided the safe `schedule` skill should be **built-in** — always injected into every session, sandboxes included — rather than grantable. This supersedes the grantable approach in #84. ### Change Previously `pi_argv(&config, sudo)` injected bundled skills all-or-nothing, gated entirely to `/sudo`. That boundary exists to keep the **dangerous control skill** (`skills/evie`, which drives the `Run` verb — arbitrary host script execution — plus cross-chat `Send`/`Prompt`/`Query`) out of sandboxes. This splits bundled skills into two classes via an explicit, audited allowlist (`SAFE_BUNDLED_SKILLS`, currently `["schedule"]`): - **Safe** bundled skills → injected into **every** session (sudo AND sandboxed). Their whole surface is self-scoped: `schedule`/`list`/`cancel`, and scheduled `send`/`prompt`/`run` that re-enter the *caller's own* sandbox as their non-root drop target (see `scoped_allows` — the immediate `Run` verb stays rejected on the scoped socket). - **Sudo-only** bundled skills (the `evie` control skill, first-party integrations like immich) → still gated to the unsandboxed `/sudo` path. The control-skill boundary is preserved exactly. Sandboxed sessions now get the safe skill via `--skill`, and its host path is bound read-only in `sandboxed_pi_argv`. The installed layout already resolves under the wholesale `/nix` bind, so no new bind is strictly needed in production; the explicit bind also covers the `cargo run` source-tree fallback and keeps injection self-contained. ### Tests (security-sensitive boundary) - `pi_argv_sandboxed_excludes_control_skill_but_includes_safe_schedule_skill`: a sandboxed argv includes `--skill .../schedule` but NEVER `skills/evie`. - `pi_argv_sudo_includes_bundled_skills`: sudo gets **both** control + schedule. - `sandboxed_pi_argv_binds_the_safe_schedule_skill`: sandbox binds the schedule host path RO, never the control skill's. - `safe_bundled_skill_dirs_holds_schedule_but_not_the_control_skill`: allowlist guard. `just check` green: fmt + clippy -D warnings + 488 tests. ### Runbook `docs/schedule-skill-deploy-runbook.md` brought over from #84 and simplified for the built-in approach: **step 1 deleted** (no `skills_dir` seeding, no `/grant`, no rebind — the skill auto-injects on the next session after redeploy). Remaining operator steps kept and kept-accurate: relocate the two briefing scripts to a sandbox-readable path, re-create `morning-briefing`+`evening-review` as `sudo=false`, and a 60s test-fire. Precondition that the schedule-rebuild steps need #83 merged AND redeployed is retained. Skill content (`skills/schedule/SKILL.md`) reused from #84, verified against the current `evie schedule/list/cancel` CLI and `scoped_allows`.
feat(pi): inject the safe schedule skill into every session (built-in, not grantable)
All checks were successful
CI / check (pull_request) Successful in 1m32s
PR Triage — label changes-requested reviews / triage-review (pull_request) Successful in 2s
b114abf478
The bundled schedule skill exposes only self-scoped verbs (schedule/list/
cancel, and scheduled send/prompt/run that re-enter the caller's own sandbox),
so it is safe to inject everywhere. Split bundled skills into a safe allowlist,
always injected into every session including sandboxes, and the sudo-only
remainder (notably the evie control skill, which drives the Run verb) that
stays gated to the unsandboxed /sudo path. Sandboxed sessions now get the safe
skill via --skill and have its host path bound read-only.

Supersedes #84 (the grantable approach): no skills_dir seeding, no /grant, no
rebind - the skill ships in the package and auto-injects on the next session.
weiwen merged commit c90a34c586 into main 2026-07-30 21:51:20 +08:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
weiwen/evie!85
No description provided.