Skip to content

sync dev with main after infrastructure/config refactoring for fly - #330

Merged
jlunder00 merged 23 commits into
devfrom
main
May 9, 2026
Merged

sync dev with main after infrastructure/config refactoring for fly#330
jlunder00 merged 23 commits into
devfrom
main

Conversation

@jlunder00

Copy link
Copy Markdown
Owner

No description provided.

jlunder00 added 23 commits May 8, 2026 20:52
…eploy workflow

Adds all config needed to deploy to Fly.io without any application code changes.

- supervisord.conf: runs api, mcp, and bot (long-polling) as supervised
  processes inside a single container
- Dockerfile: installs supervisor; copies supervisord.conf; changes default
  CMD to supervisord (Pi deploys override CMD via docker-compose.yml as before)
- fly.toml: prod app (tether-prod, sea, 512mb, min_machines=1 for bot polling)
- fly.dev.toml: dev app (tether-dev, sea, 256mb, min_machines=0 — can sleep)
- fly-deploy.yml: single workflow handling both prod (main) and dev (dev)
  branches; Fly remote build, no self-hosted runner needed
Telegram bot_token and chat_id were only written to TETHER_CONFIG_DIR
by configure.py, leaving no fallback for cloud deployments where no
local config dir is mounted. Adding ${TELEGRAM_BOT_TOKEN} placeholders
lets the config loader resolve them from env vars (Fly.io secrets) the
same way auth_config.yaml handles JWT, OAuth, and vault credentials.

Pi deployments are unaffected — local override in TETHER_CONFIG_DIR
still wins per the loader's resolution chain.
Without this, flyctl uploads source to Fly's builder but PREMIUM_GIT_TOKEN
is empty, so the Dockerfile silently skips the premium install and deploys
community edition. TETHER_PREMIUM_TOKEN is already in GitHub secrets (same
token used by the Pi build) — forwarded here as a Docker build arg.
Replace hardcoded 'tether' database name in GRANT/REVOKE CONNECT
statements with the actual database name from the connection URL.
Fixes fresh installs on managed Postgres (Neon) where the database
is named 'neondb' rather than 'tether'.
fix: use dynamic db name in tether_app role migration (Neon compat)
feat(infra): Fly.io deployment scaffolding (Phase 3a)
Fly.io deprecated the sea region — new machines cannot be provisioned
there. sjc (San Jose) is the recommended alternative for west coast.
fix(infra): Fly.io region sea → sjc
…onfig singleton

All load_config() call sites in bot/message_handler.py replaced with
tether_config.get() / get_bool() from the unified TetherConfig singleton
(config/loader.py). config.yaml is no longer read at runtime.

Missing sections added to app_config.yaml:
  - llm.use_v3, llm.v2_fallback, llm.mcp_server_url, llm.roles.main_agent.model
  - api.base_url, api.bot_token

telegram.bot_token / chat_id already present (baked-in placeholder values).

Fly.io entrypoint now only needs auth_config.yaml + app_config.yaml; the
separate config.yaml download step can be removed.

Dead code removed: load_config(), _CONFIG_PATH, yaml import.
Tests updated to mock tether_config instead of load_config.
…-config

refactor(bot): migrate message_handler off load_config() onto TetherConfig singleton
Bot crashes on Fly.io because ~/.tether-config/config.yaml doesn't exist
in the container. Adds docker-entrypoint.sh which downloads config.yaml
and anchors.yaml from CONFIG_SOURCE_URL before handing off to supervisord.

URL scheme determines backend: https:// uses curl (with optional
CONFIG_SOURCE_TOKEN for private gists), s3:// uses aws s3 cp. Switching
from gist to S3 only requires changing the URL and adding AWS credentials.

CONFIG_SOURCE_URL is set per Fly app (tether-prod vs tether-dev) so each
environment pulls from its own gist. Also adds --ha=false to both deploy
jobs to prevent Fly from creating a second HA machine on every deploy.
Config files in gist use ${PLACEHOLDER} markers for secrets. envsubst
fills them in from Fly secrets at container start — mirrors the Pi's
configure.py pattern. Non-secret config stays as literal values in the
gist. Adds gettext-base to Dockerfile for envsubst.
…load_config paths

Downloads auth_config.yaml and app_config.yaml for TetherConfig (no envsubst —
loader resolves placeholders itself). Also downloads config.yaml with envsubst
for bot/message_handler.py:load_config() which reads it raw. config.yaml path
removed once bot migrates to TetherConfig (tracked separately).
PR #327 migrated message_handler.py to TetherConfig. The loader resolves
${VAR} placeholders from env vars itself, so config.yaml and envsubst are
no longer needed in the entrypoint.

Entrypoint now downloads only auth_config.yaml and app_config.yaml (the
TetherConfig local override layer). If CONFIG_SOURCE_URL is unset, the
stack boots from baked-in defaults + Fly secrets alone. Removes gettext-base
from Dockerfile since envsubst is no longer used.
feat(infra): docker entrypoint downloads tether config from gist/S3 at startup
Pi is no longer the primary deployment target. Moving all pi-* workflows
to .github/workflows/archive/ so they no longer trigger on push.
Fly.io (fly-deploy.yml) is now the active deployment path.
chore(ci): archive Pi workflows + simplify Fly.io entrypoint
Fly.io runs the release_command in a temporary machine before cutting
traffic over to the new version. If migrations fail, the deploy is
rolled back automatically. Uses ADMIN_DATABASE_URL (neondb_owner) if
set, falls back to DATABASE_URL per alembic env.py.
feat(infra): alembic migrations via Fly release_command
alembic upgrade head fails with 'No script_location key found' because
alembic.ini was not included in the COPY layer. Release command runs in
/app but alembic.ini was missing.
fix(infra): copy alembic.ini into Docker image
Alembic uses psycopg2 dialect by default. psycopg2-binary was present
in a Pi-specific fix branch but never landed in main's requirements.txt,
causing alembic upgrade head to fail in the Fly release_command machine.
fix(deps): add psycopg2-binary for alembic Fly release_command
@jlunder00
jlunder00 merged commit f777967 into dev May 9, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant