Rust implementation of the Opencode share service for sharing AI coding agent sessions. Built with Axum, SQLx, and PostgreSQL for maximum performance and type safety.
- High Performance: Built with Rust and Axum async framework for maximum throughput
- Type Safety: Compile-time checked SQL queries and strongly typed data structures
- Event Sourcing: Efficient event-driven data synchronization with JSONB storage
- Secret-based Authentication: Secure sharing without user account management
- Rich Share Page: Interactive UI for viewing AI coding sessions
- π§ Tool Call Visualization: Beautiful cards showing bash commands, file operations, grep, etc.
- π¦ Collapsible Reasoning Blocks: Display AI "thinking" with expand/collapse functionality
- π’ Step Markers: Visual indicators for reasoning steps with token usage tracking
- π Split Diff Viewer: Side-by-side file change visualization with synchronized scrolling
- π¨ Syntax Highlighting: Code blocks with monospace fonts and proper styling
- π Token Usage Tracking: Display message and session token consumption
- Docker Support: Multi-stage builds for optimized container images
- Structured Logging: Comprehensive request/response logging with emoji indicators
- CORS Support: Full cross-origin support for frontend integration
- Environment Configuration: Flexible configuration via environment variables
- Client IP Extraction: Proper handling of reverse proxy headers
| Component | Technology | Version |
|---|---|---|
| Language | Rust | 2021 edition |
| Web Framework | Axum | 0.7 |
| Runtime | Tokio | 1.0 (async) |
| Database | PostgreSQL | (via SQLx) |
| ORM | SQLx | 0.7 (compile-time checked) |
| Serialization | Serde | 1.0 |
| Frontend | Vanilla ES6+ JavaScript + CSS3 |
opencode-share/
βββ src/
β βββ main.rs # Application entry point (84 lines)
β βββ models.rs # Data models and ShareData enum (76 lines)
β βββ middleware.rs # HTTP request logging middleware (119 lines)
β βββ core/
β β βββ mod.rs # Core module definition
β β βββ share.rs # Business logic for share operations (178 lines)
β βββ database/
β β βββ mod.rs # PostgreSQL pool setup (13 lines)
β βββ routes/
β βββ mod.rs # Route module exports
β βββ api.rs # REST API endpoints (183 lines)
β βββ share.rs # Share page rendering (82 lines)
βββ static/
β βββ share.js # Client-side renderer (617 lines)
β βββ share.css # Styling (978 lines)
β βββ favicon/manifest # PWA assets
βββ templates/
β βββ share.html # HTML template
βββ migrations/
β βββ 001_initial.sql # Database schema
βββ Cargo.toml # Rust dependencies
βββ Dockerfile # Multi-stage container build
βββ docker-compose.yaml # Orchestration with PostgreSQL
βββ README.md
- Layered Architecture: Routes β Service β Data layers
- Repository Pattern:
ShareServiceabstracts database operations - Event Sourcing: Data stored as events in JSONB format
- State Pattern:
AppStateholds shared database pool - Tagged Unions:
ShareDataenum with serde for type-safe event handling
- Rust 1.70+
- PostgreSQL 12+
- Docker (optional, for containerized deployment)
# Start the service with PostgreSQL
docker-compose up -d
# View logs
docker-compose logs -f
# Stop the service
docker-compose downThe server will start at http://localhost:3006
# Set environment variables
export DATABASE_URL="postgres://postgres:password@localhost:5432/opencode_share"
export RUST_LOG="opencode_share=debug,tower_http=debug"
export PORT=3006
# Run the server
cargo run# Build the release binary
cargo build --release
# Run the binary
./target/release/opencode-sharePOST /api/share
Content-Type: application/json
{
"sessionID": "your-session-id"
}Response:
{
"id": "share-id",
"secret": "uuid-secret",
"url": "http://localhost:3006/share/share-id"
}POST /api/share/{shareID}/sync
Content-Type: application/json
{
"secret": "share-secret",
"data": [
{
"type": "session",
"data": {
"id": "session-id",
"title": "Session Title",
"status": "active"
}
},
{
"type": "message",
"data": {
"id": "message-id",
"role": "assistant",
"content": "Response text"
}
}
]
}GET /api/share/{shareID}/dataResponse: Array of ShareData objects
DELETE /api/share/{shareID}
Content-Type: application/json
{
"secret": "share-secret"
}GET /share/{shareID}CREATE TABLE shares (
id TEXT PRIMARY KEY,
secret TEXT NOT NULL,
session_id TEXT NOT NULL,
data JSONB DEFAULT '[]',
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);CREATE INDEX idx_shares_session_id ON shares(session_id);
CREATE INDEX idx_shares_created_at ON shares(created_at);
CREATE INDEX idx_shares_updated_at ON shares(updated_at);
CREATE INDEX idx_shares_data_gin ON shares USING GIN (data);Data is stored as a discriminated union in JSONB:
session: Session metadata and statusmessage: User/assistant messagespart: Message parts (text, code blocks, tool outputs)session_diff: File changes made during sessionmodel: Model information (provider, name)
| Variable | Description | Default |
|---|---|---|
DATABASE_URL |
PostgreSQL connection string | - |
RUST_LOG |
Log level | opencode_share=info,tower_http=info |
PORT |
Server port | 3006 |
HOST |
Server host | 0.0.0.0 |
services:
postgres:
image: postgres:15
environment:
POSTGRES_PASSWORD: password
POSTGRES_DB: opencode_share
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
opencode-share:
build: .
environment:
DATABASE_URL: postgres://postgres:password@postgres:5432/opencode_share
RUST_LOG: opencode_share=debug,tower_http=debug
PORT: 3006
ports:
- "3006:3006"
depends_on:
- postgres
restart: unless-stopped
volumes:
postgres_data:Create or update opencode.json in your OpenCode project:
{
"$schema": "https://opencode.ai/config.json",
"enterprise": {
"url": "http://localhost:3006"
},
"share": "manual"
}In the OpenCode TUI/CLI:
/shareThis will create a share and provide you with a URL to view the session.
Navigate to the provided URL in your browser to view the shared session.
The share page can be customized by modifying:
- HTML Template:
templates/share.html - CSS Styling:
static/share.css - JavaScript Renderer:
static/share.js
- Define your route in
src/routes/api.rs:
pub fn api_routes() -> Router<AppState> {
Router::new()
.route("/api/share/:id/custom", post(custom_endpoint))
.with_state(app_state)
}
async fn custom_endpoint(
State(state): State<AppState>,
Path(id): Path<String>,
Json(payload): Json<Value>,
) -> Result<Json<Value>, AppError> {
// Your custom logic
Ok(Json(json!({ "result": "success" })))
}- Add business logic in
src/core/share.rs:
impl ShareService {
pub async fn custom_operation(
&self,
id: &str,
) -> Result<ShareData, anyhow::Error> {
// Implementation
}
}Add new data types to the ShareData enum in src/models.rs:
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type")]
pub enum ShareData {
#[serde(rename = "session")]
Session { data: Value },
#[serde(rename = "custom")]
Custom { data: YourCustomType },
}# Run all tests
cargo test
# Run tests with database
cargo test --features test-db
# Run specific test
cargo test test_create_share- Memory Safety: No garbage collection pauses
- Zero-Cost Abstractions: Compile-time optimizations
- Async Runtime: Efficient concurrent request handling with Tokio
- PostgreSQL + JSONB: Fast queries with flexible schema
- SQLx: Compile-time checked SQL queries prevent runtime errors
- Secret-based Authentication: Each share has a unique secret key
- SQL Injection Prevention: Parameterized queries via SQLx
- Input Validation: Type checking through Serde
- CORS: Configurable cross-origin resource sharing
This implementation maintains full API compatibility with the original TypeScript version:
- β Same endpoint URLs and request/response formats
- β Compatible data structures
- β Same event sourcing logic
- β Equivalent share page functionality
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Models: Define data types in
src/models.rs - Core Logic: Implement business logic in
src/core/share.rs - Routes: Add API endpoints in
src/routes/api.rs - Database: Add migrations in
migrations/
The service uses structured logging with tracing:
use tracing::{info, warn, error};
info!("share_created", id = %share_id);
warn!("sync_failed", share_id = %id, error = %err);Use anyhow::Error for error propagation:
pub async fn create_share(&self, session_id: &str) -> Result<ShareInfo, anyhow::Error> {
let share = sqlx::query_as::<_, ShareInfo>(...)
.fetch_one(&self.pool)
.await?;
Ok(share)
}Same as the original Opencode project.