agent-recall  

"Git for Agent Sessions"

Design Spec — March 30, 2026 — v1

TL;DR: A $1.50/quarter cloud service that stores versioned agent session data in Cloudflare R2. Push/pull/log semantics over a REST API. Stripe billing. Open source — use ours, self-host, or resell.
Architecture

Architecture

The cloud service is a new provider adapter for the existing sync engine. Same YAML format, same .recallignore, same secret scanning. The cloud adapter translates push/pull into HTTP REST calls.

/recall sync init --github      → user's GitHub repo (free, actual git)
/recall sync init --gitlab      → user's GitLab repo (free, actual git)
/recall sync init --bitbucket   → user's Bitbucket repo (free, actual git)
/recall sync init --cloud       → our managed R2 backend ($1.50/quarter)
┌─ Sync Engine (existing) ───────────────────────────────┐
│                                                    │
│  Provider adapters:                                │
│  ├── git (GitHub, GitLab, BB) → git push/pull    │
│  └── cloud (NEW) → HTTP REST to Worker          │
│                                                    │
└────────────────────┬───────────────────────┘
                    │ HTTPS
                    ▼
┌─ Cloudflare Worker ────────────────────────────┐
│                                                    │
│  Auth → Rate Limiter → Route Handler           │
│  (API key)  (KV)         (PUT/GET/LIST/DELETE)    │
│                                                    │
│  Stripe Webhook (/webhook/stripe)                 │
│                                                    │
│  ┌───────────┐   ┌────────────────────────┐  │
│  │ KV Store  │   │ R2 (versioning enabled)  │  │
│  │ api keys  │   │ /{user_id}/              │  │
│  │ rate ctrs │   │   restarts/*.yaml        │  │
│  │ usage     │   │   learnings/*.yaml       │  │
│  │ tier info │   │   adm/*.yaml             │  │
│  └───────────┘   │   sops/*.yaml            │  │
│                   │   sessions/*.yaml        │  │
│                   │   agent-configs/*.yaml   │  │
│                   └────────────────────────┘  │
└────────────────────────────────────────────────┘

Why Cloudflare, not AWS

Cloudflare Worker + R2AWS ECS Fargate + S3
Baseline$0~$23/mo
Egress$0$0.09/GB
Profitable fromUser #1~User #200
Deploywrangler deployContainer + ALB + IAM + ECR

R2 Object Versioning = The VCS

No git server. No commits. No refs. R2's built-in object versioning provides automatic version history, restore any previous version, list all versions, and soft delete with retention. Each file is a complete, self-contained YAML document. No diffs, no deltas, no changelogs.

API

API Surface

All endpoints except /webhook/stripe require Bearer token auth
PUT    /v1/files/{path}              Store a file (R2 auto-versions)
GET    /v1/files/{path}              Get latest version
GET    /v1/files/{path}?version={n}  Get specific version
GET    /v1/files/{path}/versions     List all versions of a file
GET    /v1/files/?after={timestamp}  List files changed since
DELETE /v1/files/{path}              Soft delete (versions retained)
DELETE /v1/files/{path}/versions     Trim old versions (keep=N)
GET    /v1/status                    Storage, rate limits, billing
GET    /v1/export                    Signed R2 URL for full download
POST   /v1/auth/rotate               Rotate API key
POST   /v1/webhook/stripe            Stripe billing events

What the user types vs. what happens

Local commandCloud callWhat happens
/recall sync pushPUT /v1/files/*Upload changed files since last push
/recall sync pullGET /v1/files/?after={ts}Download files changed since last pull
/recall sync statusGET /v1/statusShow storage, limits, billing
/recall cloud exportGET /v1/exportDownload everything as tarball

Push/Pull Protocol

Push (fast-forward only): Sync engine gathers changed files → secret scan locally → .recallignore filter → PUT each file → R2 auto-versions → record timestamp.

Pull: GET files changed since last pull timestamp → download each → write to local directories → regenerate index.

No merge. No conflict resolution. Two machines create different files with unique timestamps. Latest write wins; versions are retained so nothing is lost.

Storage

Storage Tiers

TierWhat syncsSize per session
Lite (default)Distilled restarts + index metadata~2-5KB
StandardLite + raw JSONL (expires 30 days)~1-10MB
FullEverything, against 10GB cap~1-10MB, persists
sync:
  provider: cloud
  tier: lite
  include:
    adm: true
    restarts: true
    learnings: true
    sops: true
    session_metadata: true
    agent_configs: true
    transcripts: false

10GB cap per user (includes R2 version history). When full: 507 Insufficient Storage. Version cleanup via DELETE /v1/files/{path}/versions?keep=3.

Cost Protection

Rate Limiting & Cost Protection

Five stacking windows — abuse requires sustained cost across ALL time windows
WindowMax requestsMax INMax OUTWhy
Session (5hr)5020MB50MBMatches agent session
Hourly3010MB30MBBurst prevention
Daily20050MB100MB~4 sessions/day
Weekly800200MB500MBHeavy dev week
Monthly2,000500MB1GBFull billing period

Enforcement: Request → Auth → Check all 5 windows → Process or 429. Counters stored in KV with TTL-based auto-cleanup.

Export exemption: GET /v1/export always works regardless of rate limits. Your data is your data. Limited to 1/day to prevent CDN abuse.

Billing

Stripe Billing & Account Lifecycle

$1.50/quarter = $0.50/month effective — auto-cancels if you stop using it

Economics

ItemCost/user/quarter
Stripe fee (2.9% + $0.30)$0.34
R2 storage (10GB, 3mo)~$0.45
Worker compute~$0.01
Total cost~$0.80
Revenue$1.50
Profit~$0.70

Checkout Flow

User visits cloud.html
  → Stripe Checkout ($1.50/quarter)
  → Webhook: checkout.session.completed
    → Generate API key (32-byte hex)
    → Store SHA-256(key + salt) in KV
    → Show key once on post-checkout page
  → echo "sk_recall_..." > ~/.env/agent-recall/api-key
  → /recall sync init --cloud

Auto-Cancel on Inactivity

On invoice.upcoming webhook: check if any API requests in last 60 days. If no → cancel subscription, retain data for 30 days grace, then 7 more days export-only, then delete.

Account States

StatePush/PullExportData retained
ActiveYesYesYes
InactiveNoYes30 days
ExpiredNoYes7 more days
DeletedNoNoNo
Configs

Agent Config Versioning

A new sync category for AGENTS.md / CLAUDE.md files. Snapshots taken on session start, stored as versioned documents.

# agent-configs/CLAUDE.md/2026-03-30T08:01:00.yaml
file: CLAUDE.md
project: myapp
snapshot_date: 2026-03-30T08:01:00
session_id: abc123
changed_by: agent:claude-opus-4-6
diff_summary: "Added 3 rules about ArangoDB env vars"
content: |
  # full file content at this point in time

Commands

/recall configs                  # list tracked config files
/recall configs diff             # changes since last session
/recall configs rollback 2       # restore from 2 snapshots ago
Security

Security & Data Isolation

  • Every R2 object prefixed with /{user_id}/ — hard isolation
  • Worker never serves objects outside authenticated user's prefix
  • No admin API, no cross-user queries
  • HTTPS only (Cloudflare enforces)
  • No PII beyond email (Stripe billing only)
  • Session content is opaque — stored, not parsed

API Key Security

raw_key  = crypto.randomBytes(32).hex()  → shown once
key_hash = SHA-256(raw_key + SALT)       → stored in KV

Raw key never stored. Salt is a Worker secret. Rotation via POST /v1/auth/rotate.

If a Key Leaks

  1. Attacker limited to that user's data only
  2. Rate limits still apply — can't exfiltrate fast
  3. User rotates key immediately
  4. Storage cap prevents abuse as free storage
Microsite

Microsite & Self-Host

docs/
├── index.html       ← existing recall microsite
├── cloud.html       ← NEW: service + Stripe checkout
└── self-host.html   ← NEW: deploy-your-own guide

cloud.html

One paragraph, pricing ($0.50/mo billed $1.50/quarter), Stripe Checkout button, post-payment API key display, link to self-host guide.

self-host.html

1. Fork the repo
2. Create Cloudflare account (free)
3. Create R2 bucket (versioning) + KV namespace
4. Create Stripe account + product
5. wrangler secret put STRIPE_SECRET_KEY
   wrangler secret put STRIPE_WEBHOOK_SECRET
   wrangler secret put API_KEY_SALT
6. wrangler deploy
7. Configure Stripe webhook URL
8. Done — selling under your own brand

Open source safety: No credentials in code, ever. All secrets via wrangler secret put.

Plugin

Recall Plugin Integration

Config

# ~/.config/agent-recall/sync.yaml
sync:
  provider: cloud
  endpoint: https://recall-api.agent-recall.workers.dev
  api_key_file: ~/.env/agent-recall/api-key
  tier: lite
  auto_sync: true

New Commands

CommandWhat it does
/recall cloud setupPrompt for API key, write config, test
/recall cloud statusStorage, rate limits, billing
/recall cloud exportDownload full data tarball

Existing Commands + Cloud

CommandCloud behavior
/recall sync pushPUT changed files to R2
/recall sync pullGET files since last pull
/recall sync push --dry-runShow what would push
/recall sync --verifyConfirm all data pushed
/recall sync pause/resumeToggle auto-sync

Local always works. Cloud is additive. Sync failures never block the user.

Files

File Structure

agent-recall/
├── worker/                        # NEW: Cloudflare Worker
│   ├── src/
│   │   ├── index.ts               # Entrypoint, router
│   │   ├── auth.ts                # API key validation
│   │   ├── rate-limiter.ts        # 5-window rate limiting
│   │   ├── files.ts               # R2 CRUD
│   │   ├── stripe.ts              # Webhook handler
│   │   └── export.ts              # Signed URL generation
│   ├── wrangler.toml              # R2 + KV bindings
│   ├── package.json
│   └── tsconfig.json
├── lib/
│   ├── sync_cloud.py              # NEW: cloud adapter
│   └── sync.py                    # MOD: register cloud
├── docs/
│   ├── cloud.html                 # NEW: service page
│   └── self-host.html             # NEW: deploy guide
└── wrangler.toml                  # existing (microsite)
Scaling

Scaling Path

UsersEst. req/dayAction
0 – 500<10kFree tier, no action
500 – 2,00010k – 50kWorkers paid plan ($5/mo)
2,000 – 5,00050k – 100kMonitor, approaching limit
5,000+>100kSplit read/write Workers

At 5,000 users: $10,000/quarter revenue. Infra: ~$50/month. Comfortable margin.

Scope

v1 vs v2

v1 This spec

  • Cloudflare Worker with auth, rate limiting, R2 storage
  • Stripe quarterly billing with auto-cancel on inactivity
  • Cloud provider adapter in sync engine
  • cloud.html and self-host.html pages
  • Agent config snapshotting
  • /recall cloud setup, status, export commands
  • Open source with self-host documentation

v2 Future

  • Encryption at rest (client-side, before push)
  • Server-side full-text search
  • Usage analytics dashboard
  • Team/shared sync (multi-user)
  • Cloudflare affiliate integration
  • Continuous sync daemon
  • Webhook notifications