Share Claude Code and Codex session transcripts with end-to-end encryption.
- Private by default: Your transcripts are encrypted before they leave your machine. The server never sees your content.
- Safe links: The decryption key is part of the URL itself, so only people you share with can read it.
- Works with Claude Code and Codex: Just run
/agentexportin Claude or the publish command in Codex.
brew install nicosuave/tap/agentexportOr
curl -fsSL https://agentexports.com/setup | shThen run setup to install commands:
agentexport setupThis will:
- Claude Code: Install the
/agentexportcommand - Codex: Install the
/agentexportprompt
Restart Claude/Codex after setup.
Just type /agentexport in any session:
/agentexport
Claude will publish your current session and return a shareable URL like:
https://agentexports.com/v/ga1b2c3d4e5f6g7h8#SGVsbG8gV29ybGQh...
Use the publish command to share your current session.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Your Terminal │ │ Server (R2) │ │ Recipient │
│ │ │ │ │ │
│ 1. Gzip │ │ │ │ │
│ 2. Encrypt │ POST │ Store encrypted │ GET │ Fetch blob │
│ 3. Upload │─────>│ blob (opaque) │─────>│ Decrypt in JS │
│ 4. Get URL │ │ │ │ Decompress │
│ │ │ │ │ View transcript │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│
Key in URL fragment ────────┘
(never sent to server)
The server operator cannot read your transcripts because:
- Content is encrypted with AES-256-GCM before upload
- The decryption key is placed in the URL fragment (
#key) - Browsers never send URL fragments to servers
- Decryption happens entirely in the recipient's browser
- URLs without the correct key will fail to decrypt
https://agentexports.com/v/{id}#{key}
│ │
│ └── Base64url AES-256 key (never sent to server)
└─────── TTL prefix + content hash (e.g., g = 30 days)
List your shares and their expiration:
agentexport sharesDelete a share:
agentexport shares unshare <id>Shares are stored locally in ~/.cache/agentexport/shares.json with the decryption keys needed for deletion.
You can upload to GitHub Gist instead of the default server. This stores the share payload as a gist and returns the gist URL. Requires the GitHub CLI to be authenticated.
gh auth login
agentexport config set storage_type gistGists are created as secret (unlisted) by default. Gists are not encrypted and do not expire. The TTL setting is ignored. upload_url is ignored for the gist backend.
cd worker
# Create R2 bucket
wrangler r2 bucket create agent-exports
# Deploy to Cloudflare
wrangler deploy --env production- In Cloudflare dashboard, go to Workers & Pages
- Select
agentexport-share - Settings > Triggers > Add Custom Domain
- Enter your domain
Then configure the CLI to use your domain:
agentexport config set upload_url https://your-domain.comSet environment variables in wrangler.toml under [vars]:
| Variable | Description | Default |
|---|---|---|
MAX_TTL_DAYS |
Maximum allowed retention period. Requests exceeding this are rejected. Set to 365 to disable "forever" retention. |
unlimited |
- Rust (with
wasm32-unknown-unknowntarget) - Node.js (for wrangler)
- wrangler CLI
rustup target add wasm32-unknown-unknown
npm install -g wrangler
cargo install worker-build# Terminal 1: Start worker
cd worker && wrangler dev --port 8787
# Terminal 2: Test
agentexport publish --tool claude --upload-url http://localhost:8787# Unit tests
cargo test --lib
# E2E tests (requires worker running on :8787)
cargo test --test e2e -- --ignored| Component | Value |
|---|---|
| Algorithm | AES-256-GCM |
| Key | 256 bits, random |
| IV/Nonce | 96 bits, random |
| Compression | Gzip before encryption |
| Expiration | 30 days (configurable: 30, 60, 90, 180, 365, or forever) |
MIT