FastAPI service + Telegram bot that run coding agent tasks (e.g. Claude Code) inside disposable sandboxes provided by Boat.
For prerequisites, .env setup, and how to run the whole stack (this API,
the Telegram bot, and the web UI) with one command, see the
repo root README. This file covers backend-specific details.
app/routers/— REST API:sandboxes(sandbox lifecycle + Claude/GitHub auth),tasks(create/get/list),link(web ↔ Telegram identity linking),schedules(create/list/get/update/pause/resume/run-now/delete, and/{id}/runsfor its task history).app/services/—box_operations(Boat SDK wrapper),auth_flow_service(OAuth/device-flow login inside a sandbox),user_credential_service(encrypted credential storage; also pulls a renewed login back out of the box instead of overwriting it),user_sandbox_service,link_service,task_execution_service(create_task/start_tasksplit so a task row always exists before anything is launched, plussync_active_tasks),schedule_service(cron scheduling —poll_due_schedules,report_finished_runs),notification_service(Telegram delivery, independent of whether the bot process is running).app/core/background.py—run_every, the plainasyncioloop the three background jobs above run on; started inapp/main.py's FastAPI lifespan.app/telegram_bot.py— the bot, built on the same services as the REST API. Includes/schedule,/schedules,/pause,/resume,/unschedule— these only read/write thescheduletable; the bot process does not itself run schedules (see Scheduling).alembic/— migrations. Runuv run alembic upgrade headafter pulling changes that touchapp/db/models/.
docker compose up -d # Postgres
uv sync # install deps
uv run alembic upgrade head # migrations
uv run fastapi dev app/main.py # API — http://127.0.0.1:8000, docs at /docs
uv run python -m app.telegram_bot # bot, in a separate terminalapp/main.py's FastAPI lifespan starts three asyncio loops (30s interval,
app/core/background.py) that poll, launch, and report scheduled runs — see
the repo root README for how they fit
together. They only run inside the API process: running the bot without the
API lets users create/list/pause/resume/delete schedules (it just writes to
the schedule table), but nothing will actually fire until
uv run fastapi dev app/main.py is also running.
Scheduled-run notifications go out over Telegram via notification_service,
using telegram.Bot directly — not through app/telegram_bot.py's running
Application — so they're sent by the API process even if the bot process
isn't running. They require TELEGRAM_BOT_TOKEN and only reach users whose
user_id is numeric (Telegram-linked); a web-only guest's user_id (e.g.
web_...) has no matching chat, so notifications are silently skipped for
them — they still see outcomes in the web UI.
- Sandboxes are never automatically stopped/deleted — repeated
/connecttesting will accumulate them on the Boat account. - The bot's own polling loop (5 min) is shorter than the task command timeout (10 min), so a long-running task can appear to "fail" in Telegram before the sandbox actually gives up on it.
- Link codes expire after 10 minutes; there's no rate limiting on generating them.
- Schedules poll on a 30s interval (so a run can start up to ~30s late) and skip an occurrence missed by more than 15 minutes rather than run it late.
- No automated tests yet.