# Security

## Supported version

The latest commit on `main` is supported while the project remains pre-1.0.

## Reporting

Use a private GitHub Security Advisory or contact the repository owner privately.
Do not include credentials, provider responses, private source documents, or
unrelated session logs.

## Trust and process boundaries

Pi Tmux Orchestrator launches local Pi and Python processes under the current
operating-system account. It uses configured Pi providers without reading or
copying authentication files. It is not an operating-system sandbox between
same-user workers.

Only the implementer receives normal Pi write tools. Reviewer, probe,
Playwright, and Django roles omit `edit` and `write` but retain `bash`; their
read-only rule is a workflow boundary. The broker validates each role's report
kind and disallows changed paths from read-only reports.

Project trust is explicit. Parent trust never transfers automatically to child
Pi processes. `--approve-project` is permitted only after target inspection and
separate confirmation. RPC presentation uses Pi's saved/global trust behavior
because it cannot display a startup trust prompt.

Worker provider/model/thinking policy comes only from bounded explicit
arguments or the strict user-global orchestrator configuration outside target
repositories. Version-3 configuration may additionally map existing canonical
absolute project directories to bounded profile/model/flow/specialist/workspace
defaults using exact matching only. It cannot grant trust, tools, writer/reviewer
authority, forced execution, prompts, or skills. Credential, endpoint, header,
and arbitrary extra fields are rejected. Pi's own model registry and
authentication remain authoritative. Bounded model discovery returns no
authentication material.

## Broker boundary

Every run created by `0.5.0` or later uses one local Unix-domain socket:

- private run directory mode `0700`;
- socket, database, manifests, and token files mode `0600`;
- independent random 128-bit role tokens plus a separate control token;
- role-scoped report/lifecycle permissions;
- read-only parent observers authenticated with the control token;
- same-user peer credential checking where supported;
- four-byte length-prefixed JSON frames bounded to 256 KiB;
- bounded report fields, arrays, and canonical encoded size;
- no TCP listener, network service, cloud queue, or runtime dependency.

A socket owner running under the same account can inspect or alter local process
state. Permissions and peer checks are hardening, not protection from a
compromised same-user process.

## Private data and persistence

Never place credentials, private customer/career/production data, raw provider
requests/responses, system prompts, private endpoints, unbounded errors, copied
diffs, or logs in task or report fields.

The Pi dashboard overlay reads only bounded `list`/broker summaries and doctor
metadata on open or explicit refresh. It does not inspect pane output, Pi
histories, workflow bodies, or provider payloads, and starts no timer or
background poll.

The metadata-only SQLite database retains:

- workflow and role lifecycle, worker generations, and body-free context-boundary events;
- assignment/report IDs and report shape counts;
- verdicts and bounded statuses;
- command/delivery IDs and state;
- provider-reported token/cost totals and context pressure.

It does not retain task, parent-context-capsule, assignment, run-state-capsule,
report, prompt, message, provider, diff, or log bodies. Task and optional bounded
parent context enter through one transient private startup file deleted after
authenticated baseline delivery. Rendered role baselines and run-state capsules
remain only in live broker memory and recipient Pi sessions for confirmed
generation-handover replay. Bounded latest accepted report bodies may exist only
in live broker memory for rolling-state rendering and authenticated parent
observer replay. Report bodies remain in Pi's own protected session tool
results; recipient context and parent completion/attention updates remain in
their complete Pi JSONL sessions. Pi
session files and local backups remain the operator's responsibility.

The package extension transfers start/message input through unique private
temporary files so payloads do not enter subprocess argv, status, details,
notifications, or widgets. Cleanup is not a secure-erasure claim.

State roots, session/run directories, manifests, tokens, and databases must be
canonical non-symlink paths with expected types. Private writes use no-follow
opens where available, descriptor checks, atomic replacement, and restrictive
permissions. Manifest v3+ validates exact project/session/window identity,
known roles, pane IDs, session paths, transport presentation, and `broker-v1`
protocol identity. Manifest v5 additionally retains only bounded external config
path/schema and exact-project mapping metadata, never configuration or workflow
bodies.

## Delivery semantics

Broker/bridge acknowledgement proves acceptance, not task completion.

- Delivery and command IDs are 32-character lowercase hexadecimal values.
- Matching action/role/delivery command retries deduplicate.
- Conflicting metadata reuse is rejected.
- Bridge custom entries deduplicate session delivery and record body-free
  assignment boundaries without adding state to LLM context.
- Pi invokes context projection for every provider request, but each distinct
  new assignment emits the only metadata-only boundary event that changes the
  pruning policy; every projection within an assignment retains all current
  turns.
- Confirmed restart advances a broker generation, rejects stale bridges, replays
  the live in-memory baseline and latest coalesced run state (including a
  replacement deferred during the active assignment), and preserves the Pi
  conversation. Replaying the same assignment is not a new pruning boundary.
- A failed local respawn is reported through a body-free authenticated control
  command, and either that failure or a replacement disconnect marks role and
  workflow `uncertain` with metadata-only handover evidence.
- A crash in any other unprovable delivery or handover window becomes `uncertain`.
- Uncertain work is not blindly replayed and requires explicit retry.
- The project makes no exactly-once claim.

Idle agents end their turn. A settled worker with an active assignment but no
report moves the workflow to `needs_attention` for parent intervention. The
broker and bridge use OS event delivery; agents do not poll files, sockets, or
tmux and never use sleeps for lifecycle. Bounded timeouts detect failures
rather than schedule workflow work.

## Token data

Cumulative token and cost totals come from complete Pi/provider assistant
usage. Current provider-context occupancy is reported separately when available.
Missing values are not estimated. Soft budgets can warn or prevent a future
assignment, but cannot stop an already-started provider response at an exact
token boundary.

## Metadata APIs

Status, the broker dashboard, JSON output, journals, widgets, and Supervisor
API return only bounded metadata. The dashboard selects only workflow, role,
assignment-shape, configured model, usage/context, and event metadata; it never
renders task, context-capsule, prompt, message, report, diff, log, credential,
token-secret, or provider-response bodies. Dynamic terminal text is
control-byte sanitized and width-bounded before display. Supervisor API v2 reads retained state without
tmux and reports host runtime as `not_observed`; retained PIDs never imply
liveness. Directory scans and pages remain bounded.

Retained `0.4.x` runs remain readable and operable through compatibility code.
No newly started run can select their file-relay or mailbox payload protocol.

## Destructive operations

The CLI:

- never replaces an existing tmux session;
- uses exact tmux targets;
- validates reserved controller identity before attach/stop;
- permits extension-driven worker-grid attach only as an exact `switch-client` when the parent Pi is already inside tmux; it never injects keys or replaces the parent process;
- requires `--yes` for role restart and grid stop;
- requires `--confirm` for controller stop;
- records ambiguous delivery as `uncertain`;
- retains Pi sessions and metadata after tmux termination;
- kills partial tmux startup and records private failure state where safe.

It does not push, merge, publish, deploy, or clean target repositories.

## Package and tests

In a regular interactive parent Pi session, the extension makes one
best-effort HTTPS request to the public npm registry's package metadata endpoint
to detect a newer release. The request is time-bounded, sends no project or
orchestration data, stores only the validated version in process memory, and is
skipped in worker/controller sessions. Set
`PI_TMUX_ORCHESTRATOR_DISABLE_UPDATE_NOTICE=1` to disable it.

The npm package declares no dependencies or lifecycle scripts and does not
bundle Pi. Deterministic package checks exclude tests, CI files, generated
sessions/state, credentials, caches, `node_modules`, and authentication data.
Model-free acceptance uses isolated Pi/npm homes, offline package operations,
and no provider prompt. Pre-release staging writes only to a new canonical
operator-selected directory outside the checkout, records bounded Git/tarball
provenance, and proves Pi resource discovery from the staged package path. The
default manual runner uses a disposable Pi home with no real auth. Any later
real-home `-e` test is explicit, temporary, and documented separately; package
settings remain unchanged unless the operator deliberately runs `pi install`.
