A production-ready service for uploading AI agent session logs, converting them to beautiful HTML using cclogviewer, and sharing via secure links.
Currently Supported: Claude Code Future Support (Aspirational): Codex, Gemini CLI, and other AI coding assistants
- Beautiful Upload UI: Modern, responsive drag-and-drop interface
- Claude Code Integration: Custom slash commands (
/logget,/logup) for instant session sharing - Secure Sharing: Cryptographically secure UUID-based links (security by obscurity)
- Smart Caching: Regenerates HTML only when cclogviewer binary or config changes
- Rate Limiting: Built-in protection against abuse
- Security Hardened: Comprehensive security headers, path traversal prevention, and Docker best practices
- Configurable Storage: Flexible filesystem-based storage location
- Production Ready: Multi-stage Docker build, health checks, non-root user
The easiest way to get started is using the pre-built image from GitHub Container Registry:
docker run -d \
--name agent-share \
-p 8721:8721 \
-v agent-share-data:/app/storage \
-e BASE_URL=http://localhost:8721 \
ghcr.io/henricook/agentshare:latestOr with docker-compose:
services:
agent-share:
image: ghcr.io/henricook/agentshare:latest
ports:
- "8721:8721"
volumes:
- agent-share-data:/app/storage:rw
environment:
- BASE_URL=http://localhost:8721
volumes:
agent-share-data:Then access the application at http://localhost:8721.
Optional: Install Claude Code slash commands for easy session sharing
# Clone the repository to get the slash commands
git clone https://github.com/henricook/agent-share.git
cd agent-share
# Install globally for all projects
mkdir -p ~/.claude/commands
cp .claude/commands/logget.md ~/.claude/commands/
cp .claude/commands/logup.md ~/.claude/commands/
# Set your Agent Share URL (if not using localhost)
export AGENT_SHARE_URL=http://localhost:8721Now you can use /logup in any Claude Code session to instantly share your work!
- Clone the repository
git clone https://github.com/henricook/agent-share.git
cd agent-share- Build and run with docker-compose
docker-compose up -d --build- Access the application
Open http://localhost:8721 in your browser.
- Prerequisites
- Node.js 20+
- Go 1.23+ (for installing cclogviewer)
- Install cclogviewer
go install github.com/brads3290/cclogviewer/cmd/cclogviewer@latestThis installs cclogviewer to ~/go/bin/cclogviewer, which will be automatically detected by Agent Share.
- Install dependencies
npm install- Create storage directory
mkdir -p storage- Copy environment file
cp .env.example .envThe cclogviewer binary path is automatically detected. Only set CCLOGVIEWER_BIN_PATH in .env if you installed it in a custom location:
# Only needed for custom installations
CCLOGVIEWER_BIN_PATH=/custom/path/to/cclogviewerAuto-detection locations (checked in order):
-
CCLOGVIEWER_BIN_PATHenvironment variable (if set) -
/app/bin/cclogviewer(Docker/Kubernetes) -
~/go/bin/cclogviewer(localgo install) -
Run in development mode
npm run dev- Access the application
Open http://localhost:8721 in your browser.
- Visit the home page at
/ - Drag and drop your
.jsonlfile or click to browse - Click "Upload & Generate Link"
- Copy the shareable link and share it with your team
Visit the generated link (e.g., http://localhost:8721/view/{uuid}) to view the converted HTML session log.
Agent Share includes custom slash commands for Claude Code that make uploading sessions much easier. These commands are stored in .claude/commands/ and can be used directly from any Claude Code session.
Option 1: Copy to your Claude Code global commands (Recommended)
This makes the commands available in all your projects:
# Create the global commands directory if it doesn't exist
mkdir -p ~/.claude/commands
# Copy the commands
cp .claude/commands/logget.md ~/.claude/commands/
cp .claude/commands/logup.md ~/.claude/commands/Option 2: Use per-project commands
The commands in .claude/commands/ will automatically be available when working in the agent-share project directory.
/logget - Copy session to project directory
Copies the current Claude Code session .jsonl file to your project directory, ready for manual upload.
/logget
This will copy the latest session file and show you where it was saved.
/logup - Upload session directly to Agent Share
Uploads the current session directly to your Agent Share instance and returns a shareable link.
/logup
By default, this uploads to http://localhost:8721. To use a different Agent Share instance, set the AGENT_SHARE_URL environment variable:
export AGENT_SHARE_URL=https://your-agent-share.example.com- Have an interesting Claude Code session you want to share
- Type
/logupin Claude Code - Get an instant shareable link
- Share the link with your team
No need to manually find the session file or visit the upload page!
All configuration is done via environment variables. See .env.example for all available options.
| Variable | Default | Description |
|---|---|---|
NODE_ENV |
development |
Environment mode |
HOST |
0.0.0.0 |
Host to bind to (0.0.0.0 for all interfaces, required for Docker/K8s) |
PORT |
8721 |
Server port |
STORAGE_PATH |
./storage |
Directory for uploaded files |
MAX_FILE_SIZE_MB |
50 |
Maximum upload file size |
MAX_JSONL_LINES |
10000000 |
Maximum lines in JSONL file |
CCLOGVIEWER_BIN_PATH |
Auto-detected | Path to cclogviewer binary (auto-detected, optional override) |
RATE_LIMIT_UPLOAD_MAX |
10 |
Max uploads per window |
BASE_URL |
http://localhost:8721 |
Base URL for shareable links |
Edit docker-compose.yml to customize:
- Port mapping (default:
8721:8721) - Storage volume (default: named volume
agent-share-data) - Environment variables
- BASE_URL (set to your domain in production)
The service uses a smart caching system:
- Global Marker: Hash of cclogviewer binary + generation config
- Per-Upload Marker: Stored with each session's HTML
- Cache Check: On view, compares markers
- Regeneration: Only regenerates if markers don't match
This means:
- Fast serving when nothing changes
- Automatic regeneration when you update cclogviewer or config
- No manual cache clearing needed
- UUID v4 IDs: 122-bit entropy, cryptographically secure
- Path Traversal Prevention: Strict validation on all file operations
- JSONL Validation: Validates file format and content
- Rate Limiting: Per-IP limits on uploads and views
- Security Headers: CSP, X-Frame-Options, X-Content-Type-Options, etc.
- Docker Hardening: Non-root user, capability dropping, read-only where possible
- No Shell Execution: Uses
spawninstead ofexecto prevent injection
agent-share/
├── src/
│ ├── index.ts # Main application entry
│ ├── config/
│ │ └── environment.ts # Environment configuration
│ ├── routes/
│ │ ├── upload.ts # POST /api/upload
│ │ └── view.ts # GET /view/:id
│ ├── services/
│ │ ├── storage.ts # File operations
│ │ ├── cclogviewer.ts # Binary wrapper
│ │ └── cache.ts # Generation marker logic
│ ├── middleware/
│ │ ├── validation.ts # File validation
│ │ ├── rate-limit.ts # Rate limiting
│ │ └── security.ts # Security headers
│ └── utils/
│ ├── id-generator.ts # UUID generation
│ └── path-sanitizer.ts # Path validation
├── public/
│ ├── index.html # Upload UI
│ └── app.js # Client-side logic
├── storage/
│ └── generation.config.json # Generation configuration
├── Dockerfile # Multi-stage build
├── docker-compose.yml # Container orchestration
└── README.md
Upload a JSONL session file.
Request:
- Content-Type:
multipart/form-data - Body:
file(JSONL file)
Response:
{
"success": true,
"id": "550e8400-e29b-41d4-a716-446655440000",
"url": "http://localhost:8721/view/550e8400-e29b-41d4-a716-446655440000"
}View a converted session.
Response: HTML page
Health check endpoint.
Response:
{
"status": "ok",
"timestamp": "2025-01-15T10:30:00Z"
}- Update BASE_URL in
docker-compose.ymlor via environment variable:
environment:
- BASE_URL=https://your-domain.comOr with docker run:
docker run -d \
--name agent-share \
-p 8721:8721 \
-v agent-share-data:/app/storage \
-e BASE_URL=https://your-domain.com \
ghcr.io/henricook/agentshare:latest-
Set up reverse proxy (nginx, Caddy, Traefik, etc.) with SSL in front of the application
-
Optional: Configure persistent storage with bind mounts instead of named volumes if needed:
volumes:
- /path/to/persistent/storage:/app/storage:rwPull the latest image which includes the latest cclogviewer:
docker pull ghcr.io/henricook/agentshare:latest
docker restart agent-shareOr with docker-compose:
docker-compose pull
docker-compose up -dRebuild the Docker image to pull the latest cclogviewer:
docker-compose build --no-cache
docker-compose up -dUpdate cclogviewer using go install:
go install github.com/brads3290/cclogviewer/cmd/cclogviewer@latestNote: All existing sessions will automatically regenerate on next view (generation marker will be different)
Edit storage/generation.config.json to change generation settings:
{
"version": "1.0.0",
"styling": {
"customCSS": false,
"theme": "default"
},
"cclogviewerArgs": []
}Changes to this file will trigger HTML regeneration for all sessions.
Check logs:
docker-compose logs -f agent-shareVerify cclogviewer is available:
docker-compose exec agent-share which cclogviewerThe Docker setup uses a named volume which handles permissions automatically. If you have issues, you can inspect the volume:
docker volume inspect agent-share-dataAdjust rate limits in .env or docker-compose.yml:
RATE_LIMIT_UPLOAD_MAX=20
RATE_LIMIT_VIEW_MAX=200MIT
- Built with Hono
- Powered by cclogviewer
- UI styled with Tailwind CSS