apollo-agent 0.6.0

Local-first Rust AI agent runtime — Telegram-first, trait-driven, SurrealDB + RocksDB state layer.
Documentation
[workspace]
members = [".", "ui", "ui/tui"]
resolver = "2"

[package]
name = "apollo-agent"
version = "0.6.0"
edition = "2021"
description = "Local-first Rust AI agent runtime — Telegram-first, trait-driven, SurrealDB + RocksDB state layer."
license = "MPL-2.0"
readme = "README.md"
documentation = "https://docs.rs/apollo-agent"
repository = "https://github.com/tschk/apollo"
homepage = "https://github.com/tschk/apollo"
keywords = ["agent", "ai", "llm", "telegram", "automation"]
categories = ["command-line-utilities", "web-programming::http-client"]
exclude = ["/.cursor/", "/memory/", "/USER.md", "/SOUL.md", "/IDENTITY.md", "/MEMORY.md", "/NOW.md", "/HEARTBEAT.md", "/gemini.md", "/apollo.json"]

[[bin]]
name = "apollo"
path = "src/main.rs"

[[bin]]
name = "apollo-install"
path = "src/bin/apollo_install.rs"

[lib]
name = "apollo"
path = "src/lib.rs"

[features]
default = [
    "core",
    "channel-cli",
    "channel-telegram",
    "provider-ollama",
    "rs-ai",
    "zkr-memory",
    "plugin-web",
    "plugin-skills",
]

# Core (always needed)
core = []

# Optional tool packs (compile-time; also filter via toolsets/manifest)
plugin-web = []
plugin-browser = []
plugin-skills = []
plugin-advanced = []

# Channels — pick what you need
channel-cli = []
channel-telegram = []
channel-discord = ["dep:tokio-tungstenite"]
channel-slack = []
channel-whatsapp = []
channel-signal = []
channel-matrix = []
channel-irc = []
channel-googlechat = ["dep:jsonwebtoken"]
channel-msteams = []

# Providers — pick what you need
provider-copilot = []
provider-ollama = []

# rs_ai integration (providers, image/TTS/STT)
rs-ai = ["dep:rs_ai", "dep:rs_ai_core", "dep:rs_ai_providers", "dep:rs_ai_oauth"]

# Swarm mode (distributed agent coordination)
swarm = []

# Evidence-backed temporal memory (zkr on crates.io)
zkr-memory = ["dep:zkr"]

# Bundles
all-channels = ["channel-cli", "channel-telegram", "channel-discord", "channel-slack", "channel-whatsapp", "channel-signal", "channel-matrix", "channel-irc", "channel-googlechat", "channel-msteams"]
all-providers = ["provider-copilot", "provider-ollama"]
desktop = ["plugin-browser", "computer-use-praefectus"]
all-plugins = ["plugin-web", "plugin-browser", "plugin-skills", "plugin-advanced", "computer-use-praefectus"]
full = ["all-channels", "all-providers", "all-plugins", "swarm"]
computer-use-praefectus = ["dep:praefectus", "dep:ed25519-dalek"]

[dependencies]
# Rotary (rx4) — agent harness engine providing the core agent loop, tools,
# providers, sessions, skills, memory, guardrails, and MCP support.
# Used during the migration from apollo's built-in agent loop to rx4's
# harness.
#
# Every feature here is load-bearing; read this before trimming.
#   ipc       — despite the name, this gates mid-turn *cancellation* in rx4's
#               agent loop, not just the ACP/LSP transports. Removing it
#               silently drops the ability to cancel a running turn.
#   providers — gates `provider::StreamResult` and `Provider::stream`
#               themselves, so the bridge's `impl rx4::Provider for
#               RotaryProviderAdapter` will not compile without it. It is
#               needed even though apollo supplies its own model backends.
#   skills    — rx4's `SkillEngine`, used by `RotaryAgentBridge::
#               enable_skill_engine`.
#   graph-memory — rx4's `GraphMemory`, used by `RotaryAgentBridge::
#               enable_graph_memory`.
#
# Deliberately off: `builtin-tools` (apollo registers its own tools; also
# pulls in the fff/git2/notify stack), `mcp` (apollo has src/mcp_server.rs),
# `zkr-memory` (gates rx4's self_improve; apollo depends on zkr directly).
rx4 = { version = "0.5.0", default-features = false, features = ["ipc", "providers", "skills", "graph-memory"] }

# Async runtime (optimized features only)
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "io-util", "sync", "time", "fs", "signal", "process", "io-std"] }
async-trait = "0.1"
futures-util = "0.3"

# Serialization
serde = { version = "1", features = ["derive"] }
serde_json = "1"
toml = "1.1"

# HTTP client + server (no unused features)
reqwest = { version = "0.12", features = ["json", "multipart", "rustls-tls"], default-features = false }
axum = { version = "0.8", features = ["ws"] }

# CLI
clap = { version = "4", features = ["derive", "env"] }

# Error handling
anyhow = "1"
dotenvy = "0.15"

# Logging (lightweight)
tracing = "0.1"
tracing-subscriber = { version = "0.3", features = ["env-filter", "fmt", "json"] }

# UUID + Time
uuid = { version = "1", features = ["v4", "serde"] }
chrono = { version = "0.4", features = ["serde"] }

# Embedded SurrealDB + RocksDB (primary memory backend)
surrealdb = { version = "2.1", features = ["kv-rocksdb"] }
rocksdb = { version = "0.23" }

shlex = "1.3"
base64 = "0.22"

# Crypto (credential security)
sha2 = "0.10"
aes-gcm = "0.10"
rand = "0.8"

# Faster synchronization primitives
parking_lot = "0.12"
libc = "0.2"

# Scheduling (Phase 4: cron)
cron = "0.17"

# Regular expressions (skill templates, etc.)
regex = "1"

# Home directory resolution
dirs = "6.0"
praefectus = { version = "0.8.0", optional = true }
ed25519-dalek = { version = "2.1", features = ["rand_core"], optional = true }
zkr = { version = "0.4.1", optional = true }
jsonwebtoken = { version = "9", optional = true, default-features = false, features = ["use_pem"] }
tokio-tungstenite = { version = "0.29", optional = true, default-features = false, features = ["connect", "rustls-tls-webpki-roots"] }
rs_ai = { version = "0.2", optional = true }
rs_ai_core = { version = "0.2", optional = true }
rs_ai_providers = { version = "0.2", optional = true, features = ["chatgpt", "gemini", "openai-compatible", "xai", "cloudflare"] }
rs_ai_oauth = { version = "0.2.30", optional = true, default-features = false }

[dev-dependencies]
axum = "0.8"
reqwest = { version = "0.12", features = ["json", "multipart", "rustls-tls"], default-features = false }
serde_json = "1"
tempfile = "3"
temp-env = "0.3"
tokio-test = "0.4"

[profile.release]
opt-level = "z"     # Optimize for size
lto = true          # Link-time optimization
codegen-units = 1   # Single codegen unit
strip = true        # Strip symbols
panic = "abort"     # No unwind tables