Deploy Walkthrough

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 reports

Start the dashboard:

python -m orchestrator.cli dashboard --host 0.0.0.0 --port 8000

Run the scheduler once:

python -m orchestrator.cli scheduler run-due

List scheduler jobs:

python -m orchestrator.cli scheduler list

Poll scheduler continuously:

python -m orchestrator.cli scheduler loop --interval 60

Start the Telegram bot (requires token/chat_id in config):

python -m orchestrator.cli telegram

Verify

  • 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 --build

Compose 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-due

Use 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_TOKEN and GOOGLE_API_KEY in .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-agents

Install 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.enabled to true if you want notifications
  • add telegram.bot_token
  • add telegram.chat_id
  • choose the model provider and model name
  • define scheduler jobs under scheduler.jobs if 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 --build

This 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 reports

List scheduler jobs:

docker compose run --rm dashboard python -m orchestrator.cli scheduler list

Run due scheduler jobs:

docker compose run --rm dashboard python -m orchestrator.cli scheduler run-due

Open the dashboard:

  • http://YOUR_VPS_IP:8000/
  • http://YOUR_VPS_IP:8000/approvals
  • http://YOUR_VPS_IP:8000/scheduler

Operational Notes

  • Keep config/config.json and config/policy.json under 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:

  1. pull the latest commit
  2. rebuild the container image
  3. run the tests locally
  4. redeploy with docker compose up -d --build

5. Smoke Test

After deploy, confirm:

  • the dashboard loads
  • python -m orchestrator.cli reports works in the container
  • python -m orchestrator.cli scheduler run-due works in the container
  • a sample run writes artifacts to runs/
  • Telegram notifications trigger only when enabled