Create or save a new Repost-with-agent source → destination pair. Use when the user wants to set up cross-posting between websites the agent can safely operate through a logged-in browser (with documented examples for LinkedIn, X, Bluesky, Threads, and Facebook), or asks to "configure a repost pair", "set up reposting", "wire up cross-posting", or "add a new pair to repost-with-agent / repost_with_agent".
설치
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
Create or save a new Repost-with-agent source → destination pair. Use when the user wants to set up cross-posting between websites the agent can safely operate through a logged-in browser (with documented examples for LinkedIn, X, Bluesky, Threads, and Facebook), or asks to "configure a repost pair", "set up reposting", "wire up cross-posting", or "add a new pair to repost-with-agent / repost_with_agent".
when_to_trigger
User asks to set up, create, configure, or save a new repost pair, e.g. "set up reposting from LinkedIn to X", "add a Bluesky → Threads pair", "configure repost-with-agent for my new account".
Repost Pair Setup
You are the running agent. Repost-with-agent v4 ships ZERO code that does the
work — this skill is the instructions for you to set up a new source →
destination pair using your own native tools (Read, Edit, Write, Bash,
configured current-harness user-message delivery).
Goals
Ask the user for the source platform + URL/handle.
Ask for the destination platform + account.
Ask for the run mode + safety mode.
Write or update ~/.repost-with-agent/pairs.json.
Verify the user is logged into both platforms in the current harness browser profile.
Confirm success and explain next steps.
State files
All state lives at ~/.repost-with-agent/:
~/.repost-with-agent/pairs.json — array of pair configs (see schema below).
~/.repost-with-agent/pairs/<pair-id>/posted.jsonl — append-only history.
The directories are created lazily on first run for a pair.
pairs.json schema (schemaVersion 4)
{"schemaVersion":4,"notification":{"delivery":{"harness":"openclaw | claude-code | other","channel":"telegram | slack | discord | ...","accountId":"<harness account/bot id, optional when the harness has only one>","target":"<chat/user/channel destination id>","threadId":"<optional thread/topic id>"},"payloadStyle":"short-human","noRawToolOutput":true},"customRules":[],"schedulerJobs":[],"pairs":[{"id":"linkedin-to-x","name":"LinkedIn to X","enabled":true,"mode":"preview-only | approval-required | live-approved","runMode":"listen-for-future | backfill","source":{"platform":"<site-key, e.g. linkedin | x | bluesky | threads | facebook | your-site>","url":"https://www.linkedin.com/in/<handle>","profileUrl":"https://www.linkedin.com/in/<handle>"},"destination":{"platform":"<site-key, e.g. linkedin | x | bluesky | threads | facebook | your-site>","accountHint":"@<handle>","accountDisplayName":"<visible account/page name>","targetType":"profile | page | group","profileUrl":"https://x.com/<handle>"},"schedule":{"kind":"manual | cron | every","tz":"Europe/London","expression":"0 10 * * *","everyHours":24,"everyMinutes":1440},"policy":{"maxItemsPerRun":1,"minDelayBetweenPostsMinutes":60,"blockOnUncertainDuplicate":true,"overlengthStrategy":"compact","textFidelity":"exact-source-body-unless-live-ui-overlength","forbidSemanticRewrites":true,"semanticRewriteAllowedOnlyWhen":"live-ui-overlength","globalDedupeEnabled":true,"semanticDedupeEnabled":true,"semanticDedupeWindowSize":30},"createdAt":"<ISO-8601>","updatedAt":"<ISO-8601>"}]}
Field invariants:
notification.delivery records where publish confirmations should go. The setup agent should write it from the current harness/chat metadata (OpenClaw channel/accountId/target, Slack/Discord channel id, etc.) rather than relying on a default bot/account.
notification.payloadStyle: "short-human" and notification.noRawToolOutput: true keep user-facing pings concise and prevent raw tool/JSON dumps.
customRules is optional top-level user preference filtering. The run/backfill skills apply enabled skip rules after source scrape and before dedupe/publish, logging to considered.jsonl instead of publish ledgers. Pair-specific pair.customRules may be added when a rule should affect only one route.
id is kebab-case, unique. Default form: <source-platform>-to-<destination-platform>.
New pairs default to mode: "preview-only" and enabled: false. Never flip to live without explicit user authorization in the current conversation.
runMode: "listen-for-future" is the default — tail new posts on a schedule.
runMode: "backfill" is for one-shot historical walks (newest-first).
mode: "live-approved" is the only mode that allows unattended scheduled live publishes; scheduled dry/preview jobs may inspect pairs without publishing.
Optional top-level schedulerJobs records human/agent-readable scheduler intent (all-enabled sweep, source-item fanout backfill jobs, per-pair jobs, subsets, preview-only jobs). The host scheduler remains the operational source of truth.
mode: "approval-required" requires the agent to ask the user per-post.
policy.overlengthStrategy: "compact" is the Ethan/OpenClaw default, but it
only applies after the live destination UI explicitly reports overlength or
cutoff for the exact cleaned draft. Before that feedback, do not compact,
truncate, summarize, paraphrase, fix grammar, or otherwise reword the public
post text.
policy.textFidelity: "exact-source-body-unless-live-ui-overlength",
policy.forbidSemanticRewrites: true, and
policy.semanticRewriteAllowedOnlyWhen: "live-ui-overlength" are the default
guardrails. They mean the public destination draft must preserve Ethan's
wording exactly, except for removing source-platform UI artifacts outside the
real post body and replacing forbidden source-platform wrapper links with
verified non-source targets. The only rewrite exception is compacting a
live-UI-proven overlength draft while preserving intent, tone, links, key
claims, and nuance.
policy.globalDedupeEnabled defaults to true; every pair reads the global cross-pair ledger before publishing so alternate routes do not double-post the same content to the same destination.
policy.semanticDedupeEnabled defaults to true; Layer 2 semantic dedupe runs after Layer 1 string/fuzzy dedupe.
policy.semanticDedupeWindowSize defaults to 30 recent destination posts.
schedule.kind: "manual" means no scheduler should be installed for that pair unless a separate custom job explicitly names it.
schedule.kind: "cron" uses schedule.expression; schedule.kind: "every" uses everyHours or everyMinutes. These per-pair values are advisory metadata for custom per-pair scheduler jobs.
schedule.everyHours defaults to 24 (daily) when runMode = "listen-for-future" (see repost-listen-for-future-setup skill). The default all-pairs sweep may use its own global cadence instead.
Conversation flow
Source. "What's the source platform and the profile URL? (linkedin / x / bluesky / threads / facebook)"
Destination. "What's the destination platform and the account handle? (one of the same five)"
If the destination platform can contain multiple posting identities inside
one login (Facebook profile/page/group, Meta/Threads account switchers,
Bluesky multi-account sessions), also capture:
destination.targetType — profile, page, or group.
destination.accountDisplayName — the visible name to confirm in the UI
before composing (for example Reetham).
If Ethan only gives a brand/account name, preserve it literally and infer
the likely handle conservatively (Reetham → @reetham or
reetham.bsky.social) until the logged-in browser confirms the exact
platform handle.
Pair name + id. Suggest <source>-to-<destination> as the id; let the user override the human-readable name.
Run mode. "listen-for-future (tail new posts on a schedule) or backfill (one-shot walk back through history)?" Default to listen-for-future if unsure.
Safety mode. Default to preview-only. Only set approval-required or live-approved if the user explicitly asks for live posting now.
Schedule. If listen-for-future, default to the global all-enabled daily sweep. If backfill is scheduled at source level, default to source-item fanout: one source item across all enabled destinations per slot. If the user wants something else, capture it literally: manual-only, custom cron expression, every-N-hours/minutes, source-fanout job, per-pair job, subset job, preview-only dry job, or multiple jobs. Store per-pair intent in pair.schedule; store cross-pair/source-fanout/subset intent in optional top-level schedulerJobs when useful.
Notification route. Capture or confirm the current user-facing delivery route and write it to top-level notification.delivery in ~/.repost-with-agent/pairs.json. Prefer harness metadata over asking: e.g. OpenClaw can use its current channel, account_id, and chat target; Slack/Discord equivalents should record channel/user ids; Claude Code should record its configured user channel. If the route is unavailable, block scheduled/live setup until the user provides it.
Destination account / page switching
Some sites authenticate through a parent account and then require selecting the
actual posting identity. Save the intended identity in the pair config and make
the run skill verify it before typing any draft.
destination.accountDisplayName is the primary human-visible name to match in
the browser UI. When Ethan says "use whatever is logged in", configure this to
the currently logged-in visible name.
destination.accountHint is a loose human hint (name, handle, vanity path, or
page label), not a separate authoritative account id unless Ethan explicitly
gives an exact handle.
destination.targetType tells the agent whether to expect a profile,
page, or group composer.
When configuring Facebook/Meta surfaces, prefer the visible logged-in name Ethan
expects the browser to use. If the UI shows a profile/page switcher, the running
agent must switch to, or verify it is already using, accountDisplayName before
posting. Do not block merely because a stale handle differs from the logged-in
profile; update the pair to the logged-in visible name.
Writing the pair
Read~/.repost-with-agent/pairs.json if it exists. If not, initialise with {"schemaVersion": 4, "notification": {"delivery": {}, "payloadStyle": "short-human", "noRawToolOutput": true}, "customRules": [], "schedulerJobs": [], "pairs": []}.
Populate notification route before enabling scheduled/live pairs: write top-level notification.delivery from current harness/chat metadata where available, otherwise ask the user for the delivery destination.
Validate that id is unique in the existing pairs.
Append the new pair object with the fields above. Set createdAt and updatedAt to the current ISO-8601 UTC timestamp (date -u +%Y-%m-%dT%H:%M:%SZ via Bash).
Backup before write: copy existing pairs.json to pairs.json.bak.<unix-ts>.
Write the updated JSON with two-space indentation.
Verify with jq . ~/.repost-with-agent/pairs.json (Bash) — if jq exits non-zero, restore from the backup and tell the user.
Create the per-pair dir ~/.repost-with-agent/pairs/<pair-id>/ if missing (mkdir -p). Create empty posted.jsonl, audit.jsonl, learnings.md files (touch).
Login checkpoint (CRITICAL)
You CANNOT log in for the user. Before the first preview / publish, the user must
have an existing logged-in session for both source and destination platforms in
the current harness browser profile that you'll drive (OpenClaw's built-in
browser, chrome-devtools-mcp when the current harness is Claude Code, or another
explicit browser adapter).
Tell the user:
"Before I can run /repost-run <pair-id>, please open the current agent's
browser profile and confirm you're logged into both and
. I cannot log in for you. Once both sessions exist, I'll
reuse them on every run."
You can verify by navigating the current harness browser to the source profile
URL and taking a snapshot — if you see logged-out indicators
(login modal, "Sign in to continue" CTA, etc.), tell the user and stop.
Notify after every successful source item — non-negotiable
Every successful source item from this plugin MUST trigger a user-facing
message confirming the source and destination URL(s). For source fanout /
all-destination runs, send one message per source post containing all platform
outcomes, not one message per platform. Silent publishes are a bug.
(Ethan voice 5977 + 5978, 2026-05-01; aggregate fanout clarification 2026-05-06.)
The agent (you) is responsible for sending this via the configured
notification.delivery route and the current harness's message-delivery tool.
Single-pair runs can notify immediately after appending to posted.jsonl;
source fanout runs must wait until every enabled destination for the source item
has been evaluated, then send one aggregate outcome message. This behavior is
enforced by the repost-notify, repost-run, and repost-source-fanout skills.
During setup, write notification.delivery into ~/.repost-with-agent/pairs.json
from the current harness/chat metadata (channel, account/bot id, target/chat id,
optional thread id), then test once with repost-notify before flipping any pair
to a non-preview-only mode.
Final summary
After writing the pair, print a short summary to the user:
✅ Pair created: <id>
Source: <platform> · <url>
Destination: <platform> · <accountHint>
Mode: <mode>
Run mode: <runMode>
Schedule: <schedule.kind> · <schedule.expression or everyHours>
Next steps:
1. Verify you're logged into both platforms in the current harness browser profile.
2. Run /repost-run <id> to do one preview + (if safety mode allows) one live publish.
3. Run /repost-setup-cron for the default daily all-enabled sweep, or ask for a per-pair/subset/custom scheduler entry if you want different timing.
Safety
New pairs default to preview-only + enabled: false. That's intentional.
Never flip to live-approved without explicit, current-conversation authorization.
No stealth, CAPTCHA bypass, 2FA bypass, or anti-detection guidance. Browser
automation only operates on user-controlled, transparent login sessions.
Refuse to scrape or post on behalf of an account the user is not the operator
of (e.g. don't repost from someone else's profile to another account without
explicit written authorization).
See also
skills/repost-pair-list/SKILL.md — list pairs.
skills/repost-pair-show/SKILL.md — inspect one pair.
skills/repost-run/SKILL.md — run a pair (single-post).
skills/repost-listen-for-future-setup/SKILL.md — install the current-harness scheduler trigger.
docs/state-files.md — formal state-file schemas.
docs/destinations/<platform>.md — per-platform DOM hints.