Popy is an explicit-ingress trust broker, not an operating-system filesystem monitor. Browser, CLI, MCP, and guarded agent flows converge on one artifact model and one persisted Standard/Strict policy.
untrusted URL
|
+-- popy_open ----------------> verified safe derivation ------> model/user
|
+-- popy_save / browser ------> byte classification
|
Standard + non-executable ---> materialize
|
executable or Strict --------> held
|
explicit approval
|
materialize
Safe derivation is not a raw release. The model-facing MCP layer combines
fetch, verification, and rendering into popy_open, so internal security steps
do not become extra model-visible tool calls.
popyd/src/broker/database.*owns the SQLite artifact ledger and durable policy setting.popyd/src/broker/policy.*detects ELF, PE, Mach-O/fat binaries, shebangs, and known script extensions from verified content and logical names.popyd/src/broker/service.*exposes bounded JSON operations over the same-user Unix socket: list, track, ingest, adopt, approve, delete, and policy.popyd/src/main_popy_native.cppimplements Chromium native messaging and forwards control JSON only. Artifact bytes never cross native messaging.popyd/src/store/creates mode-restricted staged files, signed sidecars, and verified no-follow release copies.popyd/src/render/is the restricted child used for fixed PDF/image views.
The database lives at
~/Library/Application Support/popy/popy.db on macOS. The socket and PID file
live below the same application-support root; the sealed byte stage defaults to
~/.popy-stage.
src/background/background.ts synchronously registers Chromium listeners. A
replayable download is cancelled and refetched by the offscreen document into
OPFS. The stream validates response metadata and magic, computes SHA-256, and
collects only a bounded head for executable classification.
Under Standard, a non-executable OPFS artifact is immediately materialized by an extension-origin blob download. That internal download is explicitly exempt from interception, then the OPFS entry is removed. Executables and all Strict artifacts remain available in the dashboard for approval.
Non-replayable or oversized downloads receive an inert _popy name under
Downloads/popy-quarantine. On completion, the extension asks the broker to
adopt the exact canonical path. The broker reopens it without following
symlinks, verifies inode identity, removes the handler-visible name, hashes and
classifies it, then materializes or holds it according to policy.
The browser communicates with the broker through src/lib/native/broker.ts.
If the native host is unavailable, OPFS isolation still works; local fallback
files remain inert and visible in the browser ledger.
popyd/mcp/server.py advertises three intent-level tools:
popy_open: safe inspection, one visible call, no raw path.popy_save: requested persistence; returnsapproval_requiredwhen held.popy_approve: explicit raw trust transition.
Claude Code and Cursor receive pre-shell adapters that rewrite simple curl/wget
downloads or deny complex ones. Codex uses the MCP server plus repository/user
AGENTS.md rules because no documented pre-shell hook contract is assumed.
fetching -> stored -> materialized
Policy-sensitive artifacts use fetching -> held -> materialized. User cleanup
produces deleted; failed ingress produces failed. Browser-only historical
release uses released for compatibility.
Storage backends are independent of state:
browser-opfsbrowser-fallbacklocal
- No filesystem watcher or create-to-rename race.
- No origin allowlist bypass.
- No claim of OS-wide enforcement.
- No raw artifact bytes over the broker socket or native messaging.
- No model-visible fetch/list/verify/read choreography in the primary API.