# Runtime policy design

## Mục tiêu

Runtime policy là lớp kiểm soát cách agent đọc context, gọi tool, sửa source, chạy verify, và kết thúc task. Tài liệu này mô tả thiết kế trung lập của Pi Agent Platform, không phụ thuộc vào một project cụ thể.

## Design principles

1. Profile first: mọi task phải biết project mode, permission profile, protected paths, required context, verify commands, và MCP capabilities.
2. Bounded context: file lớn phải qua budget check; context manifest phải ghi lý do.
3. Guarded execution: shell/destructive actions đi qua exec policy. Đây là accident brake, không phải OS sandbox.
4. Tool capability: tool ngoài phải map vào capability được profile cho phép.
5. Evidence before done: source-changing task phải có verify evidence và trace.
6. Human gate for high risk: auth, release, deploy, destructive command, provider config, database migration, production data, broad Git staging, hoặc external Git/GitHub write action cần explicit confirmation.

## Runtime modules

| Module | Tool/hook | Purpose |
|---|---|---|
| Project context | `piagent_context` | Load profile, settings, policy, and local state summary. |
| Context index | `piagent_context_index_status/search/record` | Maintain a compact advisory node/edge/citation map for profile/project/tech/task navigation. |
| Permission profile | `piagent_permission_status` | Show active `read-only`, `workspace-write`, or `trusted-full-access` boundary. |
| Exec policy | `piagent_exec_policy_check` | Evaluate shell command risk before execution. |
| Context budget | `piagent_context_budget` | Enforce size/count limits for context files. |
| Tool registry | `piagent_tool_policy_check` | Check external tool capability against profile. |
| Task contract | `piagent_task_start` | Persist scope, acceptance criteria, risk lane, and verify plan. |
| Context manifest | `piagent_context_record` | Record files read for a task. |
| Verify evidence | `piagent_verify_record` | Record command result only after matching an observed Pi `bash` tool result after task start. |
| Final gate | `piagent_task_gate_check` | Validate readiness before final handoff. |
| Trace | `piagent_trace_record` | Persist changed files, outcome, and handoff state. |
| Usage | `piagent_usage_snapshot` | Show session/context/token usage when available. |

## Policy precedence

Effective policy is derived from:

1. safe defaults in `packages/piagent-core/policies/base-policy.json`;
2. installed package prompts/skills/extensions;
3. project `.pi/piagent-profile.json`;
4. explicit user instruction in the active session.

User instruction can narrow scope or raise safety requirements. It should not silently bypass protected paths, destructive command checks, or final task gates.

## Profiles

Profiles define:

- `mode`
- `permissionProfile`
- `rootMarkers`
- `protectedPaths`
- `shellProtectedPaths` — shell-only deny list for bash/exec parsing.
- `readOnlyPaths` — path tools may read, but write/edit and shell access are denied.
- `requiredContext`
- `verifyCommands`
- `mcpCapabilities`
- `runtimePolicy`
- `hardGates`

The same platform can operate as `web-frontend`, `backend-api`, `fullstack`, `be-readonly-fe`, `data`, `devops`, `docs`, `python`, `node-typescript`, or `mobile` by switching profile.

`protectedPaths` blocks read/write path-tool access and is also used for shell matching when `shellProtectedPaths` is omitted. `readOnlyPaths` is for contracts such as `be-readonly-fe`: path tools may inspect these files with `read`, `grep`, `find`, and `ls`, but write/edit and shell access are blocked automatically.

`shellProtectedPaths` is intentionally shell-only. A path declared only there blocks `bash`/`exec` access, but does not block `read`, `write`, or `edit` path tools. `profile-doctor` and `team-doctor` warn on shell-only entries so older custom profiles can migrate write-sensitive paths to `protectedPaths` or `readOnlyPaths`.

## Permission profiles

The runtime separates the active autonomy profile from the project profile:

| Profile | Meaning |
|---|---|
| `read-only` | Allows source inspection through `read`, `grep`, `find`, `ls`, plus piagent state tools. Blocks shell, write/edit, and unknown non-piagent tools before execution. |
| `workspace-write` | Default governed implementation mode. Existing protected-path, shell, capability, context, verify, and final gates remain active. |
| `trusted-full-access` | Trusted automation mode for known repos. It can relax tool-registry blocks and capability filesystem scopes inside the guard, but protected paths, secret redaction, capability-lock integrity, and destructive/external confirmation still apply. |

`PIAGENT_PERMISSION_PROFILE` can override the profile for a single run. Invalid values fail closed to `read-only`. Inside Pi, `/permission read-only`, `/permission workspace-write`, and `/permission full-access` set a session-local override without writing the project profile. Legacy aliases `/read-only`, `/workspace-write`, and `/full-access` still work. Precedence is launch env, then session command, then project profile, then policy default. `permissionProfiles.allowedModes` in base policy acts like a managed allowlist; removing `trusted-full-access` from that list disables it for the installation.

## Task lifecycle

```text
intake
  -> profile/context
  -> task contract
  -> context manifest
  -> plan
  -> guarded implementation
  -> observed verify evidence
  -> trace
  -> final gate
  -> handoff
```

This lifecycle is intentionally explicit. It makes task quality auditable and avoids relying on a long prompt as the only control layer.

## Verify evidence ledger

Pi `bash` results are observed through the runtime `tool_result` hook and appended to:

```text
.pi/piagent-state/observed-bash.jsonl
```

The ledger stores cwd, timestamp, status, a hash of the normalized command, and redacted command text for audit. It does not need the raw command text to validate a later `piagent_verify_record` call.

This file-based ledger is intentionally shared by parent and subagent processes that run in the same project cwd. If a worker subagent runs `npm test`, the parent can later record that exact verify command without depending on process-local memory.

The ledger and task/profile control files are self-protected:

- raw path-like tool access to `.pi/piagent-state/**` is blocked before execution;
- raw path-like tool access to `.pi/piagent-profile.json` is blocked before execution;
- the same protected-path gate covers Pi built-ins such as `read`, `write`, `edit`, `grep`, `find`, `ls`;
- custom/MCP tools are also blocked when a tool call contains path-like strings pointing at a protected path, including nested objects, arrays, and `file://` URIs;
- path-like strings are percent-decoded once before matching;
- input nesting above `MAX_TOOL_INPUT_INSPECTION_DEPTH=32` fails closed because an uninspectable input cannot be safely classified;
- generic extraction skips known leaf content fields such as `content`, `query`, `pattern`, `text`, and `command`, so normal search/edit strings do not become path false positives;
- `grep.glob` and `find.pattern` are checked when they explicitly name protected targets such as `.env*`, `auth.json`, `.pi/piagent-state/**`, or `piagent-profile.json`;
- broad `grep`, `find`, and `ls` results are filtered through the `tool_result` hook so protected content lines or protected path metadata are redacted before the model sees them;
- piagent tools still write/read these files through internal extension code, so normal task evidence and profile workflows continue to work.

This gate is independent from the tool registry. The registry can stay `advisory` for compatibility with changing Pi/MCP tool names, while protected-path access remains fail-closed whenever the event exposes a path-like input.

Final-gate semantics are stricter than simple observation:

- `observed=true`: Pi actually saw a matching bash result after `task.createdAt`;
- `matchedProfileCommand=true`: the command exactly matches one entry in `task.verifyCommands`;
- passing final gate: requires `observed=true`, `matchedProfileCommand=true`, and `exitCode=0`.

Ad-hoc commands can still be recorded for traceability, but they do not satisfy the passing verify gate unless they are part of the task verify plan. Exact matching is deliberate; if the task says `npm test`, record `npm test`, not `npm test || true` or `npm  test`.

## Benchmark discipline

Quality/token/cost claims must be recorded through `scripts/quality-benchmark.sh` or equivalent project evidence. The benchmark unit is a real task scenario with the same acceptance criteria and verification command.
