Call Baxter integration¶
Plugin configuration¶
plugins:
- module: cb_social_plugin.bluesky
config:
identifier: "publisher.example"
app_password: "${BLUESKY_APP_PASSWORD}"
state_db_path: "/srv/data/social-publications.db"
media_group_wait_seconds: 2
- module: cb_social_plugin.mastodon
config:
base_url: "https://social.example"
access_token: "${MASTODON_ACCESS_TOKEN}"
state_db_path: "/srv/data/social-publications.db"
visibility: "unlisted"
- module: cb_social_plugin.x_plugin
config:
access_token: "${X_ACCESS_TOKEN}"
state_db_path: "/srv/data/social-publications.db"
edit_policy: "ignore"
Secrets above are placeholders; keep actual credentials in the normal Call Baxter secret/env boundary rather than committing them to configuration files.
Mirror the same Telegram event to several providers¶
id: mirror-telegram-social
enabled: true
match:
source: telegram
kind: telegram.message.new
actions:
- kind: bluesky.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
required_hashtag: "#social"
- kind: mastodon.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
required_hashtag: "#social"
- kind: x.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
required_hashtag: "#social"
Add equivalent telegram.message.edited rules when edits should propagate. Bluesky and Mastodon
update their existing mapped post. X keeps its historical edit_policy: ignore default; choose
edit_policy: native explicitly to propagate Telegram edits through X's edit chain. Existing
edit_policy: replace rules remain accepted with their delete-then-repost semantics.
X durability and required read scope¶
Use persistent state_db_path for production X mirroring. The same database holds the normal source
mapping and a short-lived in-flight mutation intent used to harden the non-idempotent X create
boundary. Stateless X mirroring remains available for compatibility, but it cannot perform this
recovery and retains the remote-success/local-commit duplicate window.
X credentials used for mirroring should be able to read the authenticated user and their recent
posts as well as create/edit posts. The read path is only used when a previous mutation ended in an
ambiguous state (for example, a timeout after X may already have accepted the post). In that case
Call Baxter attempts a narrow timeline reconciliation. If it cannot prove exactly one matching
remote post, it raises XMirrorRecoveryRequired and does not send another create request.
This is intentionally different from an ordinary retry loop. The unresolved intent must remain in the state database so later deliveries continue reconciling rather than duplicating. Investigate X directly before manually removing an unresolved intent.
Media groups¶
When media_group_wait_seconds is greater than zero, every mirror action stages Telegram messages
with media_group_id. Schedule each configured provider's flush action against the same state DB:
actions:
- kind: bluesky.flush_due_media_groups
- kind: mastodon.flush_due_media_groups
- kind: x.flush_due_media_groups
Do not add a second broad album-staging mirror rule. As with the WordPress plugin, the ordinary mirror action itself is the staging path.