Social publishing recipes¶
All examples use ordinary Call Baxter rules. Adjust plugin credentials and Telegram attribute paths to the ingress/projection contract in your deployment.
Mirror one Telegram message to all three providers¶
id: mirror-social-all
enabled: true
match:
source: telegram
kind: telegram.message.new
actions:
- kind: bluesky.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
- kind: mastodon.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
- kind: x.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
The three effects are independent. If one provider fails after another succeeded, Call Baxter records partial success; there is no cross-provider transaction.
Require an explicit publishing hashtag¶
id: mirror-social-tagged
enabled: true
match:
source: telegram
kind: telegram.message.new
actions:
- kind: mastodon.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
required_hashtag: "#publish"
The shared mirror contract compares hashtags case-insensitively. A message without the required tag
returns a successful mastodon.skipped result with reason required_hashtag_missing; it is not a
provider failure.
Stage Telegram media groups¶
Configure a non-zero wait and a durable state database:
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
The ordinary mirror action becomes the staging path for messages carrying media_group_id. Do not
add a second broad “album staging” mirror rule. Run bluesky.flush_due_media_groups periodically
after the wait window; equivalent flush actions exist for Mastodon and X.
A dry-run flush reports due publication keys without deleting staged rows. A successful real flush publishes once, persists the mapping, and removes the staged group.
Propagate Telegram edits¶
Use a second rule for the edit event kind and point it at the same provider/state database:
id: mirror-social-edits
enabled: true
match:
source: telegram
kind: telegram.message.edited
actions:
- kind: bluesky.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
- kind: mastodon.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
- kind: x.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
edit_policy: native
Bluesky updates the deterministic record key, Mastodon edits the mapped status, and this rule opts X
into its native edit chain. X's compatibility default remains edit_policy: ignore; existing
edit_policy: replace rules retain delete-then-repost behavior.
For production X mirroring, use a persistent state_db_path. When a prior X request has an ambiguous
remote outcome, the next delivery reconciles the stored attempt and recent timeline rather than
sending a second create blindly; unresolved ambiguity fails closed with XMirrorRecoveryRequired.
Stateless compatibility mode cannot provide that recovery guarantee.
Fail the chain when media is mandatory¶
actions:
- kind: mastodon.mirror_telegram_message
args:
update: "{{ event.attrs.raw_update }}"
media_required: true
on_error:
- kind: telegram.send_message
args:
chat_id: 123456
text: "Social publication failed because required media could not be acquired."
media_required converts media acquisition omissions into action failures, which activates normal
on_error behavior.