shuttle-rs
shuttle-rs is a local-first event log for agent memory, messaging, repository
context, and coordination. The stl CLI stores data in .shuttle/shuttle.db
under the current Git repository.
Agent Onboarding
Use AGENTS.md as the canonical workflow guide for coding agents. Tool-specific setup paths are available for opencode, Claude Code, and Codex. Claude Code can also use CLAUDE.md as its conventional entrypoint.
Install the bundled Codex skill for Shuttle:
Preview the generated skill without writing it:
Phase 1 Commands
Initialize local storage:
Set or inspect the local agent identity:
SHUTTLE_AGENT overrides the repo-local identity in .shuttle/agent. When
neither is set, Shuttle uses unknown.
Capture generic and typed memories:
Recall entries with ranked results:
Read repository context:
Send and receive agent messages:
Messages are stored in the same append-only event log as memories, tasks, handoffs, and repository context. Use messages for transient agent-to-agent communication, tasks for trackable work, handoffs for ownership transfer, and typed memories for durable outcomes.
Coordinate tasks and handoffs:
Promote an important message into durable project state:
Expose Shuttle over HTTP MCP:
The app serves a small JSON dashboard at / and API endpoints for dashboard
state, inbox, tasks, memories, and repository context. It also exposes the MCP
endpoint at /mcp.
Configure MCP clients to use the /mcp endpoint:
Set SHUTTLE_MCP_BEARER_TOKEN before starting stl app serve to require
Authorization: Bearer <token> on MCP requests. When the variable is unset,
local MCP remains unauthenticated.
Pass --public-url to stl app serve when the app is already behind a public
HTTPS endpoint and should publish OAuth metadata:
SHUTTLE_OAUTH_ADMIN_TOKEN=<admin-token> \
stl
Expose Shuttle as a remote MCP server for web chat clients with a Cloudflare Named Tunnel:
SHUTTLE_OAUTH_ADMIN_TOKEN=<admin-token> \
CLOUDFLARE_TUNNEL_TOKEN=<cloudflare-tunnel-token> \
stl
Configure ChatGPT or Claude with https://shuttle.example.com/mcp. The tunnel
token is read only from the environment, so use a secret manager or runtime
injection instead of putting it in shell history. The public URL must match the
Cloudflare Tunnel hostname that forwards to http://127.0.0.1:8787.
The MCP server provides memory, message, task, handoff, repository context,
repository status, changed-file, and diff tools. Tool aliases such as remember
and namespaced tools such as shuttle_memory_store call the same local event
log.
Multi-project Gateway
For web chat clients that should use one MCP server across several local
repositories, run shuttle-gateway. The gateway is the MCP, auth, and project
routing boundary. Each project can execute locally with stl --json ..., or it
can point at a repo-local stl app serve process over HTTP.
The remote deployment model is:
gateway host / LXC
└─ shuttle-gateway
project environment
└─ stl app serve
└─ repo + .shuttle/shuttle.db
Create a project config from examples/projects.example.toml. Use
backend = "http" with url for remote project environments, or
backend = "local" with an absolute repo path for compatibility mode. If
backend is omitted and repo is present, the project is treated as local.
Run the gateway with the config:
Check installed binary versions:
Use --stl /path/to/stl to choose the CLI binary for local backends, and
--timeout <seconds> to set local subprocess and HTTP backend timeouts.
--addr can override a single-listener config, but a config with multiple
[[listeners]] owns its listener addresses.
Listeners separate ingress/auth policy from project backend type. A public Web Chat listener should use OAuth, while private LAN/Tailscale/local listeners can use bearer auth or loopback-only unauthenticated access:
[[]]
= "public"
= "127.0.0.1:8787"
= "oauth"
= "https://shuttle.example.com"
= "SHUTTLE_OAUTH_ADMIN_TOKEN"
[[]]
= "private"
= "127.0.0.1:8788"
= "bearer"
= "SHUTTLE_GATEWAY_TOKEN"
The gateway requires an explicit project argument for writes such as
shuttle_remember and shuttle_task_create. Reads may use the configured
default project.
Add projects to a running gateway with POST /api/projects or the MCP tool
shuttle_project_add. Additions are written to projects.toml and are
available immediately to all listeners. If the requested name is already in use,
the gateway chooses the next available suffix such as extra-2.
For HTTP backends, start a repo-local app server in the project environment:
SHUTTLE_MCP_BEARER_TOKEN=<backend-token> \
stl
Then configure the gateway project with the URL and backend token environment variable:
[]
= "http"
= "http://10.10.10.21:8787"
= "SHUTTLE_MAIN_BACKEND_TOKEN"
Register the public listener URL with remote MCP clients such as ChatGPT or Claude web connectors:
Run OAuth listeners with the owner-approval token injected at runtime:
SHUTTLE_OAUTH_ADMIN_TOKEN=<admin-token> \
shuttle-gateway
OAuth client registrations, authorization codes, and access tokens are stored in gateway-local SQLite databases. Backend tokens and OAuth admin tokens should be provided by a secret manager or runtime-injected environment variables.
The standard v* release workflow publishes the Rust crate and gateway
artifacts from the same tag; a separate gateway-specific release tag is not
required.
For LXC-oriented gateway hosts, v* release tags publish archives named
shuttle-gateway-lxc-<target>.tar.gz. Each archive contains
bin/shuttle-gateway, bin/stl, LXC config examples, a systemd unit, and
install.sh. The installer uses /usr/local/bin, /etc/shuttle-gateway, and
/var/lib/shuttle-gateway by default. Edit projects.toml and
shuttle-gateway.env after installation; do not store real token values in the
example files.
The same v* releases also publish OCI images and per-architecture OCI layout
archives. Pull the registry image from GHCR:
Run it with mounted config and state directories:
Apple's container tool can pull the same OCI image or load a release archive:
Synchronize event logs between Shuttle instances:
When commands run inside a Git repository, Shuttle attaches repository metadata to captured events: repository path, remote-derived repository id when present, branch, commit, dirty status, and dirty file names.
Task and handoff state is projected from append-only events. No separate task table is required, and JSON output remains suitable for MCP clients.
Mesh synchronization imports events by stable event id and skips duplicates, so re-running a sync after an offline period only transfers events that the other store has not seen yet. The CLI normalizes imported events to the receiving workspace id and records the source workspace in event metadata, which keeps synced tasks, handoffs, messages, and memories visible to local commands.
Acknowledgements
Shuttle is inspired by kioku-mesh, a shared memory system for AI coding agents across tools and machines.
Shuttle also builds on ideas from rally-rs, which in turn builds on agmsg.