Skip to main content

Overview

YesPaPa uses a two-ring architecture. The Inner Ring (TOTP gate) is fully offline and self-contained. The Outer Ring (mobile app + remote server) adds push notifications and one-tap approvals.
┌──────────────────────────────────────────────────────────────────┐
│                        YOUR SHELL                                │
│                                                                  │
│  $ rm -rf ./dist                                                 │
│       │                                                          │
│       ▼                                                          │
│  ┌─────────────────┐    Unix Socket     ┌──────────────────┐    │
│  │  intercept.sh    │ ─────────────────► │  YesPaPa Daemon  │    │
│  │  (shell alias)   │ ◄───────────────── │  (Node.js)       │    │
│  └─────────────────┘    approve/deny     └────────┬─────────┘    │
│       │                                           │              │
│       ▼                                           │              │
│  execute or block                                 │              │
└───────────────────────────────────────────────────┼──────────────┘

                              ┌──────────────────── │ ──────────────────┐
                              │     OUTER RING      │   (optional)      │
                              │                     ▼                   │
                              │  ┌──────────────────────────┐          │
                              │  │    Remote Server          │          │
                              │  │    (Supabase / self-host) │          │
                              │  └────────────┬─────────────┘          │
                              │               │                        │
                              │               ▼                        │
                              │  ┌──────────────────────────┐          │
                              │  │    YesPaPa Mobile App     │          │
                              │  │    (push + one-tap)       │          │
                              │  └──────────────────────────┘          │
                              └────────────────────────────────────────┘

Component Details

Shell Interceptor (intercept.sh)

The interceptor is a shell script sourced by .zshrc / .bashrc. It defines shell functions that shadow deny-listed commands. When you type rm -rf ./dist, the shell runs the wrapper function instead of the real rm. How interception works:
# Generated by YesPaPa and injected into shell profile
source ~/.yespapa/interceptor.sh

# Inside interceptor.sh — shell functions shadow dangerous commands:
rm() {
  case "$*" in
    *-rf*|*-r*)
      if yespapa_intercept rm "$@"; then
        command rm "$@"   # 'command' bypasses the function, runs the real binary
      fi
      ;;
    *) command rm "$@" ;; # Safe usage passes through directly
  esac
}

yespapa_intercept() {
  # 1. Extract --justification from args (if present)
  # 2. Send command to daemon via Unix socket
  # 3. Wait for approval (TOTP code or remote approval)
  # 4. If approved: return 0 → wrapper executes the real command
  # 5. If denied: return 1 → wrapper skips execution
}

Daemon (packages/core/src/daemon/)

A long-running Node.js process that:
  1. Listens on a Unix socket (/tmp/yespapa.sock) for intercepted commands
  2. Evaluates the command against rules (deny-list, allow-list, bundles)
  3. Prompts for TOTP code via the terminal and/or pushes to the remote server
  4. Validates TOTP codes locally (never trusts the remote server)
  5. Checks grace periods (HMAC-validated auto-bypasses)
  6. Responds with approve/deny to the interceptor
The daemon stores all state in SQLite (~/.yespapa/yespapa.db). This is the source of truth. The remote server is a relay, not an authority.

Remote Server (optional)

The remote server relays commands between the daemon and the mobile app. It:
  • Stores pending commands in a commands table
  • Uses Realtime (WebSocket) to push updates to the daemon
  • Sends push notifications to the mobile app via Expo Push
  • Stores grace period records for cross-device sync
Zero-trust: The remote server cannot approve commands on its own. Every approval from the mobile app includes a TOTP code that the daemon validates locally against the seed. A compromised server cannot forge approvals.

Mobile App (packages/mobile/)

A React Native + Expo app that:
  • Pairs with hosts via QR code scan
  • Displays intercepted commands in a queue
  • Generates and submits TOTP codes automatically when you tap “Approve”
  • Sends push notifications when new commands arrive
  • Manages grace periods (activate/revoke auto-bypasses)

Data Flow: Command Approval

1. User types: rm -rf ./dist
2. Shell alias → intercept.sh
3. intercept.sh → daemon (Unix socket): { command: "rm", args: ["-rf", "./dist"] }
4. Daemon evaluates rules → matches "destructive/rm-rf"
5. Daemon creates pending command in local DB
6. [If remote configured] Daemon pushes to remote → mobile gets push notification
7. User approves via:
   a. Terminal: types TOTP code → daemon validates → approved
   b. Mobile app: taps Approve → app sends TOTP code → remote updates row →
      daemon receives via Realtime → validates TOTP → approved
8. Daemon responds to intercept.sh: { status: "approved" }
9. intercept.sh executes: /usr/bin/rm -rf ./dist

Security Model

ThreatMitigation
Agent removes interceptorsHeartbeat re-injects every 30s
Agent uninstalls YesPaPaUninstall requires TOTP/master key
Compromised remote serverTOTP validated locally; server cannot forge approvals
Forged grace tokenHMAC-signed with TOTP seed; seed never leaves the machine
TOTP brute force3 attempts per command, then 30s cooldown
Agent reads TOTP seedSeed encrypted with AES-256-GCM, key derived from master password via Argon2