Deploy Walkthrough
This guide covers two paths:
- local testing on your workstation
- deployment on a VPS using Docker Compose
1. Local Setup
Prerequisites
- Python 3.11+
- Git
- Optional: Docker and Docker Compose
Install
python -m venv .venv
.venv\Scripts\activate
python -m pip install --upgrade pip
pip install -e .Configure
Edit config/config.json to match the runtime structure:
{
"telegram": {
"enabled": true,
"chat_id": "8408596072"
},
"model": {
"provider": "google",
"name": "gemini/gemini-2.5-flash-lite",
"temperature": 0.1,
"max_tokens": 4096,
"context_window_tokens": 65536
},
"scheduler": {
"enabled": true,
"poll_interval_seconds": 60,
"allowed_script_roots": ["scripts"],
"jobs": [
{
"name": "salesorderemail",
"schedule": "30 21 * * *",
"script": "scripts/salesorderemail_scheduler.sh",
"cwd": "scripts",
"enabled": true,
"requires_approval": false,
"description": "Send sales order email summary"
}
]
}
}Supply the Telegram bot token via .env (CRYSTAL_AGENTS_BOT_TOKEN) so Compose injects credentials into both services. Update config/policy.json only if you need to change agent or tool permissions, and keep scheduler scripts inside scripts/.
Run Locally
Start a workflow:
python -m orchestrator.cli run --task content --prompt "Draft a launch post."Generate reports:
python -m orchestrator.cli reportsStart the dashboard:
python -m orchestrator.cli dashboard --host 0.0.0.0 --port 8000Run the scheduler once:
python -m orchestrator.cli scheduler run-dueList scheduler jobs:
python -m orchestrator.cli scheduler listPoll scheduler continuously:
python -m orchestrator.cli scheduler loop --interval 60Start the Telegram bot (requires token/chat_id in config):
python -m orchestrator.cli telegramVerify
- Check
runs/for run artifacts. - Check
logs/for summaries, approval records, and scheduler history (scheduler_history.jsonl,scheduler_runs/). - Confirm Telegram replies/logs appear in
logs/approvals.jsonl(when approval gating is active) or via the bot console. - Open
http://127.0.0.1:8000/for the dashboard.
2. Docker Local
Build and Start
docker compose up --buildCompose now builds a single image and starts two services: dashboard (rendering the UI) and telegram (running the bot loop). Both services mount the repo, read .env, and set TZ=Asia/Kolkata.
Run a Command in Docker
docker compose run --rm dashboard python -m orchestrator.cli run --task content --prompt "Draft a launch post."
docker compose run --rm dashboard python -m orchestrator.cli reports
docker compose run --rm dashboard python -m orchestrator.cli scheduler list
docker compose run --rm dashboard python -m orchestrator.cli scheduler run-dueUse docker compose logs telegram to follow the bot logs while it polls Telegram.
Notes
- Both services share the same image and mount so updates apply to the dashboard and bot simultaneously.
- Keep
CRYSTAL_AGENTS_BOT_TOKENandGOOGLE_API_KEYin.env; Compose injects them into both services automatically.
3. VPS Deployment
Recommended Layout
On the VPS, keep the repo in a fixed directory, for example:
/opt/crystal-agentsInstall Docker
Install Docker Engine and Docker Compose on the VPS, then clone the repo into the target directory.
Configure
Update config/config.json on the server:
- set
telegram.enabledtotrueif you want notifications - add
telegram.bot_token - add
telegram.chat_id - choose the model provider and model name
- define scheduler jobs under
scheduler.jobsif you want the app to run bash scripts on a schedule
Example:
{
"telegram": {
"enabled": true,
"bot_token": "123456:ABCDEF",
"chat_id": "123456789"
},
"model": {
"provider": "openai",
"name": "gpt-5.4-mini"
},
"scheduler": {
"enabled": true,
"poll_interval_seconds": 60,
"allowed_script_roots": ["scripts"],
"jobs": [
{
"name": "nightly-backup",
"schedule": "0 2 * * *",
"script": "scripts/backup.sh",
"args": [],
"cwd": "",
"enabled": true,
"requires_approval": true,
"description": "Run the nightly backup script"
}
]
}
}Start the Stack
docker compose up -d --buildThis brings up the dashboard and the runtime container.
Use It
Run workflows:
docker compose run --rm dashboard python -m orchestrator.cli run --task content --prompt "Draft a launch post."Generate reports:
docker compose run --rm dashboard python -m orchestrator.cli reportsList scheduler jobs:
docker compose run --rm dashboard python -m orchestrator.cli scheduler listRun due scheduler jobs:
docker compose run --rm dashboard python -m orchestrator.cli scheduler run-dueOpen the dashboard:
http://YOUR_VPS_IP:8000/http://YOUR_VPS_IP:8000/approvalshttp://YOUR_VPS_IP:8000/scheduler
Operational Notes
- Keep
config/config.jsonandconfig/policy.jsonunder source control if you want the same settings on every deploy. - If you want to keep server-specific secrets out of git, replace them after deploy and do not commit those changes.
- Ensure the VPS firewall allows the dashboard port if you need remote access.
- If the VPS is only exposed through Tailscale, HTTPS is optional for that private path.
4. Update Flow
When you change code:
- pull the latest commit
- rebuild the container image
- run the tests locally
- redeploy with
docker compose up -d --build
5. Smoke Test
After deploy, confirm:
- the dashboard loads
python -m orchestrator.cli reportsworks in the containerpython -m orchestrator.cli scheduler run-dueworks in the container- a sample run writes artifacts to
runs/ - Telegram notifications trigger only when enabled