Check has three components. Only the hook is required.
Components
| Component | Required | What it does |
|---|---|---|
| Hook | Yes | Local binary that intercepts ExitPlanMode, runs the review UI |
| Share Portal | Optional | Static site that renders shared plans. When you open a share link, this is what loads in your browser. |
| Paste Service | Optional | Storage backend for the share portal. When a plan is too large for a URL, the paste service holds the compressed data and the portal fetches it on load. |
How sharing works
Small plans are encoded entirely in the URL hash — the share portal reads the hash and renders the plan. No backend involved. The data remains private — it never leaves the URL.
Large plans don’t fit in a URL. When a user explicitly confirms short link creation, the plan is encrypted in the browser (AES-256-GCM) before being sent to the paste service, which stores only the ciphertext and returns a short ID. The decryption key is embedded in the URL fragment (#key=...) and never sent to the server — not even the paste service operator can read stored plans. When someone opens that link, the portal fetches the ciphertext, decrypts it client-side using the key from the URL, and renders the plan.
Without paste service: Sharing still works for plans that fit in a URL. Those plans stay completely private — the data lives only in the URL hash and never touches a server. Large plans show a warning that the URL may be truncated by messaging apps.
With paste service: Large plans get short, reliable URLs that work everywhere. Data is end-to-end encrypted and auto-deletes after the configured TTL.
1. Install the Hook
See Installation for hook setup instructions.
2. Deploy the Share Portal
The share portal is a static single-page application. It has no backend, no database, and makes no network requests beyond fetching paste data for short URLs.
Build
bun install
bun run build:portal
Output: apps/portal/dist/
Deploy
Upload the dist/ folder to any static hosting provider.
Nginx
server {
listen 80;
server_name check.internal.example.com;
root /var/www/check;
try_files $uri /index.html;
}
AWS S3 + CloudFront
aws s3 sync apps/portal/dist/ s3://your-bucket/ --delete
Configure the CloudFront distribution to return /index.html for 404s (SPA routing).
Vercel / Netlify / Cloudflare Pages
Point to the repository root:
- Build command:
bun run build:portal - Output directory:
apps/portal/dist
3. Deploy the Paste Service
The paste service accepts compressed plan data and returns a short ID. A compressed plan goes in, a link to retrieve it comes out. Pastes auto-delete after the configured TTL. No database required.
The paste service is fully open source — the same codebase you’re looking at.
Run the binary
Download the paste service binary for your platform from GitHub Releases (private repo — sign in with a Passion Factory GitHub account that has access). Binaries are available for macOS (ARM64, x64), Linux (x64, ARM64), and Windows (x64).
chmod +x check-paste-*
./check-paste-darwin-arm64 # or whichever matches your platform
Pastes stored to ~/.check/pastes/ by default.
Configuration
| Variable | Default | Description |
|---|---|---|
PASTE_PORT | 19433 | Server port |
PASTE_DATA_DIR | ~/.check/pastes | Storage directory |
PASTE_TTL_DAYS | 7 | Auto-delete after N days |
PASTE_MAX_SIZE | 5242880 | Max encrypted payload size (5 MB) |
PASTE_ALLOWED_ORIGINS | (see defaults) | CORS allowed origins |
4. Connect the Components
export CHECK_SHARE_URL=https://your-portal.example.com
export CHECK_PASTE_URL=https://your-paste.example.com
5. Verify
- Start a plan review in Claude Code or OpenCode
- Add annotations, click Export → Share
- Confirm the share URL starts with your configured domain
- If the plan is large, click Create short link when prompted
- Open the short URL — the plan should render correctly