Skip to content

call-baxter monorepo

Call Baxter is a generic event-driven callback/runtime scaffold organized around four primitives:

Signal (EventEnvelope) -> Rule (RuleSpec) -> Action (ActionInvocation)
        ^
        `-- Schedule (ScheduleSpec) runs a poller that publishes signals

Telegram is one interface plugin among several. The same runtime can connect HTTP, MQTT, CalDAV, Docker, files, WordPress, Bluesky, Mastodon, X, and other plugin-defined sources/sinks.

Monorepo layout:

  • packages/call-baxter:
  • generic callback/runtime scaffold
  • webhook ingress, pollers, schedules, rules, and actions
  • Telegram integrated as a plugin
  • packages/tg-agent-cli:
  • Telegram projection/index database and CLI
  • browse chats, messages, callbacks, media, and action history from tg.db
  • packages/wordpress-plugin:
  • WordPress bridge plugin for mirroring Telegram events into WordPress posts
  • idempotent media upload, hashtag routing, and gallery support
  • packages/social-plugin:
  • Bluesky, Mastodon, and X action-sink plugins
  • shared Telegram mirror contract, durable source mappings, and media-group staging
  • infra:
  • Docker/Compose and Caddy deployment assets
  • rules.d:
  • operator rule files
  • services/rust-baxter:
  • Rust service/docs kept in the same repository

Runtime split

signal source / ingress / scheduled poller
  -> normalize EventEnvelope
  -> match RuleSpec
  -> execute ActionInvocation(s)
  -> interface plugin performs local/remote effect

Telegram-specific branch:
  Telegram webhook or poll
    -> call-baxter telegram plugin
    -> persist into tg-agent-cli projection db
    -> emit telegram.* signals into the same generic rule engine

The documentation starts with the Architecture page, then separates core runtime behavior, interface plugins, deployment, and concrete signal→action recipes.

Quickstart from monorepo root

Run the canonical verification gate before changing or releasing the repository:

./scripts/verify.sh

This root gate runs lockfile validation, all package tests, ruff, mypy, coordinated release-version validation, package builds, installation tests for the built wheels, Compose validation, Docker hardening checks, infra todo checks, repository hygiene checks, documentation command checks, quality/architecture todo checks, and coverage floors.

After the wheels have been built, their focused installed-artifact smoke test is:

./scripts/smoke-packages.sh

The complete release gate additionally starts both shipped container configurations:

./scripts/verify-release.sh v0.8.2

Focused infra todo verification is also available with:

./scripts/verify-infra-todos.sh

Focused quality/architecture todo verification is available with:

./scripts/verify-qual-arch-todos.sh

Deploy from the monorepo

For the complete Telegram-to-WordPress example, use the self-contained docker/ bundle and start in polling mode:

cd docker
cp .env.example .env
# Edit .env with the Telegram token and database passwords.
mkdir -p state/{run,data,caddy_data,caddy_config,mysql,wordpress}
sudo chown -R 10001:10001 state/run state/data
sudo chmod 0770 state/run state/data
docker compose up -d --build

Then follow docker/TELEGRAM_WORDPRESS_TUTORIAL.md to install WordPress, create the integration user and application password, verify the REST API, publish a real #blog message, and optionally switch to HTTPS webhook mode.

Use infra/ only for the minimal Call Baxter + Caddy layout. That image includes the social publishing plugins, but does not contain the WordPress plugin and does not run WordPress or MariaDB.

Coordinated release

Release v0.8.2 ships call-baxter, tg-agent-cli, cb-wordpress-plugin, and cb-social-plugin as one coordinated package set. The first three remain the TGEX/telegras2 replacement surface; the social package adds independently configurable Bluesky, Mastodon, and X publishing actions.

This patch release restores reliable Telegram-to-WordPress video/media uploads when Telegram omits an original filename, synchronizes the coordinated Python package metadata after the historical v0.8.1 tag divergence, and includes the current Rust scheduler cutover hardening and tagged binary-artifact workflow. The social publishing plugin family and its provider documentation remain part of the coordinated release surface.

The call-baxter package installs compatible telegras and telegras2 launchers. Existing webhook and polling deployments can retain the legacy command names, environment aliases, webhook path, /healthz, and /internal/introspection/* clients while the process runs the Call Baxter runtime.

Install the coordinated release artifacts into the same environment, preserve the existing TGEX environment, and initialize compatibility state:

telegras2 db-init
telegras2 doctor
telegras2 migrate-history --dry-run
telegras2 migrate-history
telegras2 routes
telegras2 start

The full compatibility matrix, cutover checklist, limitations, and rollback procedure are documented in packages/call-baxter/docs/tgex-migration.md and in the MkDocs page call-baxter → Replace TGEX.

Documentation

The repository includes a root mkdocs.yml configured for Material for MkDocs. The site is built from docs/ wrapper pages that include the package-local markdown, so the package docs remain the canonical source. The published site provides client-side search with suggestions, highlighting, and shareable result URLs.

The documentation toolchain is pinned in tools/docs/uv.lock. Use the repository scripts instead of an unpinned global MkDocs installation:

# Live local preview
uv run --project tools/docs --locked mkdocs serve

# Strict HTML/search-index build into site/
./scripts/build-docs.sh

# Strict HTML validation plus the combined A4 PDF
./scripts/build-docs-pdf.sh

The PDF is written to site/assets/call-baxter-documentation.pdf. CI uploads it as a workflow artifact, and the Pages workflow publishes the same file beside the HTML site.

Automation

  • .github/workflows/ci.yml runs package tests, linting, type checks, package builds, the reproducible HTML/PDF docs build, and the existing full scripts/verify.sh gate.
  • .github/workflows/docs.yml deploys the searchable MkDocs site and generated PDF to GitHub Pages from main or master.
  • .github/workflows/release.yml runs the complete release gate for tags matching v*, then publishes all wheels, source archives, the verified documentation PDF, and a SHA256SUMS manifest. Publishing is idempotent, so a failed or interrupted run can be rerun without recreating the tag.

Operator access and zrok command allowlist

Set CALL_BAXTER_API_KEY for non-ingress /v1/* operator routes such as reload, action execution, event publishing, poller runs, and query endpoints.

Set CALL_BAXTER_INGRESS_TOKEN separately for webhook/ingress execution routes so webhook callers do not gain operator privileges.

The zrok.run action is constrained by allowed_subcommands in the call_baxter.plugins.zrok plugin config. The default allowlist is share, status, and version; add more commands only when an operator rule genuinely needs them.

plugins:
  - module: call_baxter.plugins.zrok
    config:
      allowed_subcommands:
        - share
        - status
        - version

Docker deployment layouts

Layout Contents Intended use
docker/ Call Baxter, Telegram projection, WordPress plugin, MariaDB, WordPress, optional Caddy profile complete Telegram-to-WordPress deployment
infra/ Call Baxter, Telegram projection, Caddy minimal runtime/webhook deployment without the bundled WordPress bridge

The docker/ example uses Telegram polling by default so the first deployment needs no public domain. Caddy starts only with docker compose --profile webhook ... after webhook mode is configured.