Skip to content

Latest commit

 

History

History
102 lines (79 loc) · 4.27 KB

ARCHITECTURE.md

File metadata and controls

102 lines (79 loc) · 4.27 KB

Architecture

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.

Trust transitions

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.

Native broker

  • 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.cpp implements 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.

Browser flow

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.

Agent flow

popyd/mcp/server.py advertises three intent-level tools:

  • popy_open: safe inspection, one visible call, no raw path.
  • popy_save: requested persistence; returns approval_required when 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.

Artifact states

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-opfs
  • browser-fallback
  • local

Deliberate limits

  • 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.