Browser social account maintenance
Skill Muvon/octomind-tap/skills/browser-social-account-maintenance
Octomind Agents Registry
npx -y skills add Muvon/octomind-tap --skill browser-social-account-maintenanceAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 3 stars3 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Operational playbook for RECURRING social-account hygiene executed via a headless browser — profile/bio sync across networks, cross-posting a pre-written piece to N platforms, scheduled-post audits, follower/connection cleanup, notification triage, archive/delete of old posts, DM-inbox housekeeping. Activate ONLY when the user wants the browser to actually drive social account ops as maintenance work. Authoring new post copy is NOT this skill — text must be supplied as input or fetched from a content specialist via tap.
The file declares its own license as Apache-2.0. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
12.7 KB, as published. Nobody here has run it
Overview
Drive recurring social-account operations across X, LinkedIn, Mastodon, Bluesky, Threads, Instagram, YouTube, TikTok, Reddit and similar — when the work is mechanical hygiene, not voice work. The skill covers six operations: profile sync, cross-post, scheduled-post audit, follower/connection cleanup, notification triage, archive/delete. Each follows the same shape: pull current state per platform, diff against the user's source-of-truth profile or task spec, drive the per-platform UI, capture evidence, log.
This skill explicitly does NOT write new posts. New copy is supplied as input or authored by content specialists called via tap. This skill takes already-written copy and ships it.
Mental model
Treat each social network as a target with three things: (1) a profile surface (display name, bio, links, avatar, banner), (2) a publish surface (compose box / scheduler), (3) an admin surface (followers, notifications, archive). Every operation is the same loop: read current state → compare to spec → drive the UI to converge → screenshot → log. Per-platform quirks live in a small lookup table; the loop stays identical.
Three immovable invariants:
- One source of truth per operation. Profile sync reads
profile.json; cross-post readspost.json; cleanup readscleanup-rules.json. Never invent values; never paraphrase the user's bio. - Confirm-before-destructive. Delete, unfollow, archive, mass-block — confirm the count and a sample with the user before executing, even if the rules file says "auto".
- Per-platform compliance > convenience. Twitter/X 280-char limit, LinkedIn URL-penalty, Bluesky 300-char, Mastodon CW conventions — honor each. If a piece doesn't fit, log and skip that platform; do NOT silently truncate.
Rules
Per-network compose limits and quirks
| Network | Compose limit | Link handling | Image / video | Notes |
|---|---|---|---|---|
| X (Twitter) | 280 chars (free) / 25k (premium) | Counts as ~23 chars | 4 imgs / 1 video / 1 GIF | Threads: post 1, then reply with 2..N to own root |
| 3000 chars; 210-char "see more" fold | Naked links suppress reach ~60% — put link in first comment | 9 imgs / 1 video | Personal profile vs page have different composers | |
| Mastodon | 500 chars (instance default; varies) | No penalty | 4 imgs / 1 video | CW (content warning) is a culture norm, not optional for sensitive content |
| Bluesky | 300 chars | No penalty | 4 imgs / 1 video | Threads via reply-to-self |
| Threads | 500 chars | No penalty | 10 imgs / 1 video | Cross-post toggle to Instagram exists |
| Caption 2200 chars; bio 150 chars | Only one clickable URL in bio | Feed / Reels / Stories all separate composers | Posting requires mobile-style flow even on web | |
| YouTube (community / Shorts metadata) | Community 500 chars | URLs allowed | N/A for community | Use Studio composer, not the consumer site |
| Title 300 / body 40k | Allowed; subreddit rules vary | 1 img/video per post | NEVER mass-post; subreddit-by-subreddit only | |
| TikTok | Caption 2200 chars | Bio link only | Vertical video required | Captions accept hashtags, no naked URLs in caption-link form |
| Mastodon / Bluesky / Threads | — | — | — | Treat as the "open social" trio for low-risk cross-posting |
Operation 1 — Profile sync
Input: profile.json source-of-truth.
{
"display_name": "Jane Doe",
"bio": "Building things. Writing things.",
"bio_per_platform": { "x": "...", "linkedin": "..." }, // optional override
"links": ["https://janedoe.com"],
"location": "Berlin",
"pronouns": "she/her",
"avatar_path": "./assets/avatar.png",
"banner_path": "./assets/banner.png",
"platforms": ["x", "linkedin", "mastodon", "bluesky", "threads"]
}
For each listed platform:
- Open settings / edit-profile route.
- Read current values.
- Diff against spec; build a change set.
- If diff is empty → log
noopand skip. - Apply changes one field at a time; verify each landed.
- Save, screenshot the post-save profile page.
- Log row:
{ platform, fields_changed, status, screenshot_path }.
Per-platform bio cap: truncate ONLY if the user supplied bio_per_platform.<platform>; otherwise skip platforms where the bio doesn't fit and log skipped:bio-too-long.
Operation 2 — Cross-post
Input: post.json — one piece, multiple targets.
{
"platforms": ["x", "linkedin", "mastodon", "bluesky"],
"variants": {
"x": { "text": "...", "thread": ["...", "..."] },
"linkedin": { "text": "...", "link_in_first_comment": "https://..." },
"default": { "text": "...", "link": "https://..." }
},
"media": ["./assets/img1.png"],
"schedule": "now" | "2026-05-10T18:00:00Z"
}
Per platform:
- Pick variant (
variants[platform]elsevariants.default). - Validate length against the table above. If too long and no platform variant is given → skip, log
skipped:length. - Open native composer (NOT a third-party scheduler unless the user specified one).
- Paste text; attach media; for LinkedIn, post link in first comment if
link_in_first_commentset. - If
scheduleis a future timestamp, use the platform's native scheduler; ifnow, publish. - Capture the published-post URL (or scheduled-post id) — this is critical evidence.
- Log:
{ platform, post_url, scheduled_for, status, char_count, screenshot_path }.
For X threads: post root, capture URL, then post each reply against the captured root URL. If any reply fails, stop the thread (do not orphan replies).
Operation 3 — Scheduled-post audit
Pull the platform's scheduled queue, output a table: {platform, scheduled_for, preview, length, has_media, post_id}. Do not modify anything; this is a read operation. User decides what to delete / reschedule; if they say "execute the deletes" the skill confirms count + sample first.
Operation 4 — Follower / connection cleanup
Input: cleanup-rules.json.
{
"platform": "x",
"criteria": [
{ "field": "last_post_age_days", "op": ">", "value": 365 },
{ "field": "has_default_avatar", "op": "=", "value": true },
{ "field": "follower_count", "op": "<", "value": 5 },
{ "field": "bio_contains_any", "op": "in", "value": ["crypto signals", "DM for promo"] }
],
"logic": "any | all",
"action": "unfollow | block | mute | report",
"max_actions": 50,
"dry_run": true
}
Always start with dry_run: true regardless of input — produce a candidates list with reasons. Then ask the user to confirm before running with dry_run: false. Cap actions per session at 50 even if max_actions is larger; rate-limit one action per ~3 seconds; abort on first rate-limit warning from the platform.
Operation 5 — Notification triage
Input: triage-rules.json — patterns + intent (reply / like / archive / ignore).
For each notification:
- Match against rules.
intent: reply→ DO NOT compose here; collect into a queue. Hand the queue to a content specialist viatapfor batch-drafted replies. This skill never writes the reply text itself.intent: like→ click like, log.intent: archive/ignore→ mark read, log.
Operation 6 — Archive / delete old posts
Input: archive-rules.json — age threshold, keyword excludes, platform.
- Page through user's post history.
- Build candidate list:
{post_url, posted_at, preview, engagement, matches_rule}. - Always present sample + count + irreversible-warning, ask user to confirm.
- If confirmed: action one by one, ≥ 2 s spacing, screenshot per action, log.
- Stop on any platform error or rate-limit warning.
Auth and session hygiene
- Use existing browser sessions if available. If a platform requires login mid-run, prompt the user once for that platform and continue.
- 2FA: prompt the user; never attempt to bypass.
- Never persist cookies or tokens to disk after the run.
- One identity per run. Don't switch accounts mid-operation.
Output artifacts
Write to ./out/social/<operation>/<UTC>/:
log.json— one row per platform/action.<platform>-before.pngand<platform>-after.pngfor sync/cleanup ops.<platform>-published-<post_id>.pngfor cross-post ops.
Examples
Example 1: Bad → Good (cross-post length handling)
❌ Bad:
The post is 480 chars. For X, truncate silently to 280 and add an ellipsis. Move on.
✅ Good:
For X, the post is 480 chars and no x-variant was supplied → log `skipped:length` for X, continue with the other platforms,
report at the end: "X skipped — supply variants.x or shorten to ≤ 280 chars."
What changed: silent truncation produces broken posts in the user's name. Skip and report — never mangle copy.
Example 2: Edge case — LinkedIn link-in-first-comment
LinkedIn down-ranks posts with naked external URLs in the body by ~60%. If variants.linkedin.link_in_first_comment is set: post body without the URL → after publish, capture the post URL → reopen the post → add the link as the first comment from the same account → screenshot. Log both actions in one row.
Example 3: Edge case — cleanup dry-run
User says "unfollow all bots, do it now." Skill still runs dry_run: true first, returns: "Found 117 candidates by your rules. Sample: @x, @y, @z. Confirm to execute (will action max 50 this session, ~3 s spacing)." Only after explicit confirmation does the skill execute.
Checklist
- Inputs validated —
profile.json/post.json/cleanup-rules.json/triage-rules.json/archive-rules.jsonexists and required fields are present - Authenticated session confirmed for every target platform; 2FA prompts handled by the user
- Per-platform compose limits checked BEFORE driving the UI; over-limit posts skipped with a
skipped:lengthrow, not truncated - Destructive operations (delete, unfollow, block, archive) ran a dry-run first and got explicit user confirmation
- Each action has evidence: post URL captured for publishes, screenshots for profile/cleanup, log row for everything
- Anchor / link / variant rotation respected for cross-post (no identical paste across all platforms when variants exist)
- Rate limits honored: ≥ 2 s between actions, ≤ 50 destructive actions per session, abort on platform warning
- Reply / comment composition was NOT done inside this skill — handed to content specialists via
tap - No credentials, cookies, or tokens persisted to disk after the run
- Final report: per platform, what changed, what was skipped (with reason), what failed (with reason), artifact paths
Composition / References
- Pairs with
browser-form-filling-patterns(selector resilience, file upload, multi-step UI). - For ANY new copy (post bodies, replies, comments, DMs): call a content specialist via
tap. This skill ships copy; it does not author it. - For follower / engagement analysis or growth strategy: out of scope. Hand to a marketing specialist via
tap. - X Help — Tweet length
- LinkedIn Help — Post length
- Bluesky — Post length