Stratus is a Cloudflare-native agent, inspired by Nous Research's Hermes agent. Self-improvement, scheduled tasks, memory, tool use — all rebuilt on Cloudflare Workers, Durable Objects, Sandboxes, and the Agents SDK. No always-on host required.
Heads up: Stratus is at
v0.1.0. Features are fairly minimal and probably still buggy — treat this as experimental and use at your own risk.
- Cloudflare-native. Workers, Durable Objects, Sandboxes, and the Agents SDK. No always-on host to operate.
- Self-hosted, single-tenant. You own the Cloudflare account, the secrets, and every byte of state. No SaaS middle layer.
- Telegram for now. One private chat becomes your durable agent. Telegram is the only messaging surface right now; more are planned.
- Early self-improvement loop. A minimal first pass at the thing that makes Hermes so great. Your agent learns and improves over time.
- Basic context management. Stable prompt layers, per-model token budgets, and compaction with searchable recall.
- Scheduled and proactive tasks. One-off reminders and recurring jobs route back into the same runtime instance without a warm process.
- On-demand sandboxes. Wake a Cloudflare Sandbox for shell, git, compilers, test runners, and MCP tools; sleep when idle.
- Built-in web browsing. Your agent can read rendered pages and capture screenshots out of the box, powered by Cloudflare Browser Run. No extra MCP server required.
- Multiple providers. OpenRouter, OpenAI, Anthropic, and Nous behind one adapter. More coming soon.
- Basic skills management. Install and manage any skill on skills.sh from the CLI.
This assumes you have a Cloudflare account — sign up if not. The setup will walk you through Cloudflare Workers Paid and R2 enablement when required.
npm install -g stratus-agent-clistratus setup guides you through the entire setup process:
- it explains the Cloudflare token choices inline and links directly to the right dashboard/docs pages
- it asks for one deployment name that you choose, then derives the default Worker and R2 bucket names automatically
- it tells you to open the
@BotFatherTelegram chat, run/newbot, and paste the bot token for inline validation - it guides you through choosing providers and entering only the API keys those providers need
- it shows a final review screen where the selected/default provider can still be corrected before any Cloudflare or Telegram write
After the confirm gate, setup writes reusable local operator secrets to .stratus/live.env, deploys the Worker + Durable Objects + R2 + Sandbox bindings through the Cloudflare API using the release-published sandbox image, registers the Telegram webhook, and rotates a one-time pairing secret:
stratus setupOpen the Telegram bot in a private chat and send the one-time pairing secret printed at the end of stratus setup. The first verified private-chat message locks the owner to that Telegram user and chat.
Hopefully it says hi back.
If anything misbehaves:
stratus doctorIt diagnoses missing env, bad secrets, webhook mismatch, and sandbox config issues, plus the common account-level blockers (invalid Cloudflare API token, wrong-account access, missing Containers access, missing R2 access).
Canonical state lives in DO SQLite, Sessions, and R2. Sandboxes are woken only when the task requires shell, git, compilers, package managers, test runners, or dev servers, and put back to sleep when idle — keeping cost near zero while the operator is not actively using the agent.
Each private Telegram chat resolves deterministically to a single durable instance named stratus:{deployment_id}:telegram:private:{chat_id}, so cold starts and redeploys do not break continuity.
For the full architecture, including the runtime state machine, context layers, token budgets, and data model, see docs/ARCHITECTURE.md.
What you need to run Stratus on your own Cloudflare account:
| Requirement | Why |
|---|---|
Node.js >= 22 |
runtime for stratus-agent-cli |
| Cloudflare Paid Plan | Sandbox execution, R2 storage, and an API token for setup and updates |
| Telegram bot token | the user surface for the deployment |
| At least one provider API key | OpenRouter, OpenAI, Anthropic, or Nous |
Stratus itself is MIT-licensed. You pay only your own Cloudflare and model-provider bills.
stratus init # write local operator config only (no Cloudflare calls)
stratus setup # full first-time flow: config + deploy + webhook + pairing
stratus deploy # redeploy using existing local config (rotates pairing)
stratus update cli # upgrade the local stratus-agent-cli install
stratus update deployment # push the newest packaged runtime to the existing deployment
stratus status # runtime health, current provider/model, recent errors
stratus logs # recent structured logs
stratus sessions # inspect past and active sessions
stratus jobs # scheduled and recurring jobs, last-run status
stratus approvals # pending and resolved approvals
stratus sandboxes # sandbox status, recent activity, and warmup spans
stratus skills list # installed skills plus catalog version
stratus skills search <query> # supported skills.sh results
stratus skills inspect <ref> # preview a skills.sh ref's readable files and snapshot
stratus skills install <ref> # install a skills.sh ref into the deployment
stratus skills uninstall <name> # remove an installed skill
stratus skills update <name> # update an installed skill to the latest snapshot
stratus tui --once # render a local operator console snapshot
stratus env path # print the resolved local secret-store path
stratus env print # emit POSIX-safe export lines for the local secret store
stratus env edit # edit the local secret store in $EDITOR
stratus config show
stratus config validate ./.stratus/operator.json
stratus config edit ./.stratus/operator.json
stratus update cli --check
stratus update deployment --dry-run
stratus doctor # diagnose missing env, bad secrets, webhook mismatch,
# and sandbox config issues
stratus status also surfaces speculative sandbox warmup counters, so operators
can see how often streamed tool-use events turned into warmup hits, misses, or
wasted warmups.
Skills are managed deployment-scoped via the authenticated admin API — install, uninstall, and update hit skills.sh and never write local skill folders or shell out to the upstream CLI.
stratus update cli and stratus update deployment are separate on purpose: updating the local CLI does not mutate Cloudflare, and updating the deployed runtime does not mutate the local CLI install. See docs/operator/updating.md.
The local operator config at .stratus/operator.json only stores non-secret deployment metadata. Persisted operator secrets live in ignored .stratus/live.env, while Cloudflare still remains the canonical remote secret store for deploys. TELEGRAM_WEBHOOK_SECRET is persisted locally so routine deployment updates can reuse it, and the one-time pairing secret remains stdout-only.
See packages/cli/README.md for full command details, the operator config shape, and the deployment-scoped skills and update commands.
Operator slash commands inside the bound private chat:
| Command | Purpose |
|---|---|
/help |
list commands |
/status |
current runtime state, provider/model, recent errors |
/approve |
approve a pending risky action (fallback to inline buttons) |
/deny |
deny a pending risky action (fallback to inline buttons) |
/new |
start a new conversation thread while preserving persona and memory |
/jobs |
list scheduled jobs and next-run times |
/model |
inspect or switch the runtime-wide active provider/model |
Approvals surface as inline-keyboard buttons by default; /approve and /deny exist as a fallback when buttons are not usable.
Contributor prerequisites on top of the user-facing requirements above:
| Requirement | Why |
|---|---|
pnpm >= 10.17.1 |
workspace-aware package manager |
| Docker | local Sandbox SDK development via wrangler dev |
Node.js >= 22 is also used for local Worker dev and the test suite.
From a clean clone:
pnpm install
pnpm -r typecheck
pnpm lint
pnpm test
pnpm buildThe slower interactive CLI smoke lane lives near packaging:
pnpm --filter stratus-agent-cli pack:smokeThat PTY suite runs the built CLI in a real pseudo-terminal on macOS/Linux using the bundled Python pty bridge, while pnpm test keeps the fast mocked/non-TTY coverage.
Scope to a single package:
pnpm --filter stratus-agent-cli test
pnpm --filter @stratus-agent/worker devRun the Worker locally (requires Docker for the Sandbox SDK):
cd apps/worker
cp .dev.vars.example .dev.vars
pnpm devCI is path-based: only packages touched in a PR are typechecked, linted, and tested, with runs grouped and cancelled on superseded pushes to keep GitHub Actions usage low. See .github/workflows/ci.yml and AGENTS.md#ci-philosophy.
Source install for Stratus itself:
git clone https://github.com/BenSparksCode/stratus-agent.git
cd stratus-agent
pnpm install
pnpm --filter stratus-agent-cli build
node packages/cli/dist/bin.js --help| Doc | Read it for |
|---|---|
| docs/ARCHITECTURE.md | frozen v0.1.0 architecture, state machine, data model, context subsystem |
| AGENTS.md | contributor conventions, working defaults, review and debug modes |
| apps/worker/README.md | Worker substrate, bindings, and local smoke check |
| packages/cli/README.md | CLI commands, operator config shape, failure modes |
| docs/operator/updating.md | update and rollback guidance |
| docs/operator/releasing.md | npm release workflow and release checklist |
If this README disagrees with docs/ARCHITECTURE.md, that document is the source of truth.
Contributions are welcome. Before proposing changes:
- Read AGENTS.md — it is the working contract for both humans and agents.
- Read the relevant section of docs/ARCHITECTURE.md before touching frozen surfaces.
- Open an issue before opening a PR for non-trivial work.
- Use Conventional Commits. Keep commits focused. No AI attribution trailers.
- Run
pnpm lint,pnpm typecheck,pnpm test, andpnpm buildfor touched packages before committing.
MIT. See LICENSE.

