| name | fedica |
| version | 1.0.0 |
| description | Compose and schedule cross-platform social posts on Fedica (X, LinkedIn, Threads, Mastodon, Bluesky) via agent-browser. Handles login, image upload, scheduling, character limits, and Fedica's UTC-only time display. |
| metadata | {"openclaw":{"emoji":"📣","requires":{"commands":["agent-browser"]}}} |
Fedica Skill
Fedica is a cross-platform social scheduler that publishes to X, LinkedIn, Threads, Mastodon, Bluesky (and more) from one compose box. This skill drives it through agent-browser.
Prerequisites
agent-browser installed (npm i -g agent-browser)
- A Fedica account with at least one platform connected
- Credentials available to you (this skill does not manage secrets — load your own from your password manager,
pass, op, env vars, ~/.secrets/..., etc.)
Safety
Fedica is public broadcast. Never publish or schedule without explicit user confirmation on:
- final post text
- target platforms (checkboxes in the composer)
- scheduled local time (Fedica shows UTC — convert before confirming)
Treat every Post Now / Add to Calendar / Update click like an email you cannot unsend.
Key gotchas
| Gotcha | Rule |
|---|
| Timezone | Fedica displays everything in GMT+00 (UTC) regardless of browser or user TZ. Convert to the user's local TZ before confirming a schedule. Example: 07:00 UTC = 09:00 Europe/Paris (CEST, summer) or 08:00 Europe/Paris (CET, winter). |
| Bluesky limit | 300 graphemes max. Almost always the binding constraint — design around it first. |
| Threads / Mastodon | 500 chars each. X and LinkedIn much more generous. |
| Character counter | Bottom right of composer shows NNN / 300 (always anchored to Bluesky's 300). If the text exceeds a platform's limit, clicking Schedule pops an error listing which platforms fail. |
| Custom Posts tab | Allows per-platform versions (long LinkedIn + short Bluesky). Use when trimming to 300 kills the message. |
| Image upload | The visible camera icon only opens a hidden input that Fedica will not react to on direct upload. You must open the modal first: openTweetBoxAttachmentUploadModal(1). The modal's input is #imageUploader1 (note the trailing 1). |
| Schedule button | It is a split button. The primary Schedule label alone does not open the modal. The dropdown entry #openScheduleButton (labelled "Specific date") is what opens the "When to publish?" modal. |
| Date picker | Web component <calendar-date> containing <calendar-month> whose day buttons live in a shadow DOM. Reach them via document.querySelector('calendar-month').shadowRoot.querySelector('button[aria-label="April 20"]'). |
| Chrome extension nag | A dialog "Fedica Browser extension" pops up on the Calendar page. Close with its X button, or use the "Don't remind me again" link, or Escape. |
| Headless browser sandbox | In a headless/server environment the first agent-browser call needs --args "--no-sandbox" (or equivalent). |
Fast workflow (happy path)
agent-browser --args "--no-sandbox" open "https://fedica.com/dash/"
agent-browser open "https://fedica.com/publish/"
agent-browser snapshot 2>&1 | grep -i "checkbox.*-"
COMPOSE_REF=$(agent-browser snapshot 2>&1 | grep -oP 'textbox "Compose your post or thread" \[ref=\K[^\]]+')
agent-browser click @$COMPOSE_REF
agent-browser keyboard type "$(cat /tmp/post.txt)"
agent-browser eval "openTweetBoxAttachmentUploadModal(1)"
sleep 1
agent-browser upload "#imageUploader1" "/absolute/path/to/image.png"
sleep 3
agent-browser eval "document.querySelector('#openScheduleButton').click()"
sleep 2
agent-browser eval "
const sr = document.querySelector('calendar-month').shadowRoot;
sr.querySelector('button[aria-label=\"April 20\"]').click();
"
EXACT_REF=$(agent-browser snapshot 2>&1 | grep -B1 '"Exact Time"' | grep -oP 'ref=\K[^\]]+' | head -1)
agent-browser click @$EXACT_REF
agent-browser eval "
const t = document.querySelector('#scheduleTimeControl');
const setter = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value').set;
setter.call(t, '07:00');
t.dispatchEvent(new Event('change', {bubbles:true}));
"
CONFIRM_REF=$(agent-browser snapshot 2>&1 | grep -B1 -E 'Add to Calendar|Update' | grep -oP 'ref=\K[^\]]+' | head -1)
agent-browser click @$CONFIRM_REF
Verify a scheduled post
agent-browser open "https://fedica.com/schedule/"
agent-browser press Escape
agent-browser find text "<snippet from the post>" click
Always re-verify the displayed time after scheduling. Subtract or add the UTC offset to get the user's local time, and restate that local time to them.
Editing / rescheduling
agent-browser eval "editPost(<postId>)"
Composing for 5 platforms in one shot
Plan around the Bluesky 300-grapheme ceiling from the start. Techniques:
- Drop narrative intros — lead with the brand or headline
- Drop parenthetical qualifiers like "(no strings attached)"
- Remove redundant CTAs ("If you're building in this space…")
- 1 emoji per bullet + 1 CTA link is usually enough
- Em-dash (
—) instead of "such as", "including", etc.
If the message needs the full long form, switch to the Custom Posts tab in the composer. Each platform then gets its own text field — full long version for LinkedIn/X, short teaser + link for Bluesky/Threads/Mastodon.
Character counting
Fedica counts graphemes, and its live NNN / 300 counter is authoritative. For an offline estimate, Python codepoint count is close but undercounts some emoji (e.g. 🏛️ = two codepoints):
s = open('/tmp/post.txt').read()
print('codepoints:', len(s))
When you are close to the 300 limit, paste into the composer and read the live counter.
Troubleshooting
| Symptom | Fix |
|---|
Login redirects to account.fedica.com/oauth2/... | Normal OAuth handoff; fill the password on the Azure-B2C-style form that appears. |
upload command fails with a CDP error | The file input element ID differs: #imageUploader (page-level, not wired up) vs #imageUploader1 (inside the modal). Open the modal first with openTweetBoxAttachmentUploadModal(1) and use the modal input. |
| Date picker does not react to clicks | It is a shadow-DOM web component. Use document.querySelector('calendar-month').shadowRoot to reach the buttons. |
Post cannot be longer than N characters popup | The error lists the offending platforms. Either trim to the lowest limit, or switch to Custom Posts. |
| Scheduled time is off by 1–2 hours | Fedica is in GMT+00. Adjust for the user's current offset (e.g. CEST = UTC+2, CET = UTC+1, EDT = UTC−4, EST = UTC−5). |
| "Fedica Browser extension" dialog blocks the calendar page | Close with the X or the "Don't remind me again" link. |
Sensible defaults
When the user does not specify, propose and then confirm:
- Time: 09:00 local on the next weekday (good slot for pro-network engagement). Convert to UTC before entering it into Fedica.
- Platforms: all connected (leave every checkbox checked).
- Visibility: default public on each platform (Fedica does not add visibility controls per post).
Do not assume — always restate the final plan (text preview, platforms list, local-time schedule) and wait for explicit go before clicking the confirm button.
Fedica endpoints
- Dashboard:
https://fedica.com/dash/
- Compose:
https://fedica.com/publish/
- Scheduled queue:
https://fedica.com/schedule/
- Drafts:
https://fedica.com/publish/drafts/
- Media library:
https://fedica.com/publish/media/
Post IDs are numeric integers. They appear in the editPost(...), delPost(...), and calendar-preview popup onclick handlers.