Local-first runtime that keeps work alive across devices.
Continuum lets long-running, interactive tasks continue on your home or office machine while you observe, intervene, and resume them from anywhere—without moving your work to the cloud.
Tasks die when you close your laptop, lose a terminal, or walk away. You have to babysit sessions, set up SSH tunnels, or re-run work from scratch.
Continuum makes long-running work survivable. Start work on one machine, check progress from your phone, approve prompts, and resume exactly where you left off, without needing to hover over your device.
- Durable tasks — Work continues even when you disconnect
- Multi-device access — Monitor and interact from laptop, phone, or tablet
- Interactive prompts — Respond to password prompts and confirmations remotely
- PTY support — Full terminal output with colors and control codes
- Audit trail — Complete history of who did what and when
- Local-first — Your data stays on your machines, not in the cloud
# Build all crates (debug)
cargo build
# Build release binaries
cargo build --releaseThe daemon runs on your host machine and manages task execution:
# Start the daemon (foreground, with logging)
RUST_LOG=info ./target/release/continuum-daemon
# Or run in background
./target/release/continuum-daemon &The daemon listens on two ports:
- Port 50051: Enrollment service (server-auth TLS only)
- Port 50052: Main API (mTLS required)
Before using the CLI, you need to enroll your device. See Enrollment Guide for details.
Quick start (same machine):
# Same-machine auto-enrollment (simplest)
./target/release/continuum enroll --local
# Or with a token (for remote enrollment)
./target/release/continuum-daemon token generate --label "my-laptop"
./target/release/continuum enroll -t AQAA-xxxx-xxxx-...# Run a task
./target/release/continuum run -- echo "hello world"
# Run a long-running task
./target/release/continuum run -- ./my-script.sh
# List tasks
./target/release/continuum ls
# Show task details
./target/release/continuum show <task-id>
# Attach to task output (stream live)
./target/release/continuum attach <task-id>
# Attach interactively (forward your input to the task)
./target/release/continuum attach -i <task-id>
# Send input to a running task
./target/release/continuum send <task-id> "user input here"
# Cancel a task (SIGTERM)
./target/release/continuum cancel <task-id>
# Force kill a task (SIGKILL)
./target/release/continuum cancel --force <task-id>continuum [OPTIONS] <COMMAND>
Commands:
enroll Enroll this client with the daemon
status Check enrollment status
clients Manage authorized clients
run Run a new task
ls List tasks
show Show task details
attach Attach to task output
send Send input to a task
cancel Cancel a running task
Global Options:
--daemon <ADDR> Daemon address [default: http://127.0.0.1:50052]
--json Output JSON instead of human-readable text
-v, --verbose Verbose output
continuum enroll <TOKEN> [--label <NAME>]continuum statuscontinuum clients list # List enrolled clients
continuum clients revoke <FP> # Revoke by fingerprintcontinuum run [OPTIONS] -- <COMMAND>...
Options:
-i, --interactive Attach immediately after starting
--name <NAME> Task name (defaults to command name)
--cwd <PATH> Working directory
--env <KEY=VALUE> Environment variable (can be repeated)continuum ls [OPTIONS]
Options:
--status <STATUS> Filter by status (queued, running, completed, failed, canceled)
--recent <N> Show last N tasks [default: 20]
--all Show all taskscontinuum attach [OPTIONS] <TASK_ID>
Options:
-i, --interactive Forward stdin to task
--no-follow Print history and exit (don't stream)continuum send [OPTIONS] <TASK_ID> [DATA]
Options:
--file <PATH> Send contents of file
--ctrl-c Send interrupt signal
--raw Don't append newline to data┌─────────────────────────────────────────────────────────────────┐
│ Your Network │
│ │
│ ┌──────────┐ ┌───────────────────┐ ┌──────────────┐ │
│ │ Phone │────▶│ │◀────│ Laptop │ │
│ │ (view) │ │ continuum-daemon │ │ (admin) │ │
│ └──────────┘ │ │ └──────────────┘ │
│ │ Running on your │ │
│ │ home/office │ │
│ │ machine │ │
│ └────────┬──────────┘ │
│ │ │
│ ┌──────▼──────┐ │
│ │ Tasks │ │
│ │ (durable) │ │
│ └─────────────┘ │
└─────────────────────────────────────────────────────────────────┘
This is a Rust workspace with eight crates:
continuum/
├── continuum-core/ # Pure domain types (IO-free)
├── continuum-auth/ # Pure authentication library (IO-free)
├── continuum-proto/ # gRPC protobuf definitions
├── continuum-shim-proto/ # Shim↔Daemon IPC protocol
├── continuum-pty/ # PTY spawn/read/write/signal
├── continuum-shim/ # Per-task process manager
├── continuum-daemon/ # gRPC server, task supervisor
└── continuum-cli/ # Command-line interface
Pure domain types and business logic. Intentionally IO-free:
- No filesystem, network, or database operations
- All types are plain Rust structs/enums with serde serialization
- Stable API with semantic versioning
Key types:
Task— A durable command with lifecycle state machineTaskStatus— Queued → Running → Completed/Failed/CanceledAttentionState— Overlay indicating if a task needs user inputDevice,DeviceRole— Multi-device identity and authorizationAuditEvent— Security and compliance logging
Pure authentication library. Also IO-free, all persistence is injected via traits:
- Ed25519 keypairs with secure memory handling
- Signed enrollment tokens (no TOFU)
- mTLS certificate verification
- Server trust and client allowlist abstractions
The service that runs on your host machine:
- Dual-port gRPC server (enrollment on 50051, main API on 50052)
- mTLS authentication for all API calls
- Executes tasks via shim processes with PTY sessions
- Streams output to connected clients
- Detects when tasks need input (attention state)
- SQLite persistence for tasks and auth state
Command-line interface for interacting with the daemon:
- Device enrollment (local or token-based)
- Start, stop, and monitor tasks
- Send input to running tasks (including interactive
~.detach) - Stream live output
- Client management (list, revoke)
┌─────────────────────────────────────────────────────────────────┐
│ │
│ ┌─────────┐ ┌─────────┐ ┌───────────────┐ │
│ │ Queued │───▶│ Running │───▶│ Completed │ │
│ └─────────┘ └────┬────┘ └───────────────┘ │
│ │ │ │
│ │ │ ┌───────────────┐ │
│ │ └────────▶│ Failed │ │
│ │ │ └───────────────┘ │
│ │ │ │
│ │ │ ┌───────────────┐ │
│ └──────────────┴────────▶│ Canceled │ │
│ └───────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Tasks use an event-sourced state machine. Each state transition is recorded as an event, providing a complete audit trail and enabling replay.
- Local-first — Data never leaves your machines unless you want it to
- Work survives interruption — Tasks are durable, not tied to sessions
- Multi-device by design — Access from anywhere on your network
- Audit everything — Full history for security and debugging
- IO-free core — Business logic is pure and testable
Early development. Core functionality works:
- Task execution with full PTY support (colors, control codes)
- Live output streaming and input forwarding
- Attention detection (password prompts, stalls)
- Client enrollment with signed tokens (no TOFU)
- mTLS for secure connections
- SQLite persistence for tasks and auth
- Same-machine trust (local auto-enrollment)
- Graceful shutdown with task cancellation
Not yet implemented:
- Multi-device sync
- Mobile/web clients
- Omar Imtiaz (@oaimtiaz)
Licensed under the Apache License, Version 2.0. See LICENSE for details.