Skip to content

CLI reference: Draft and approve

25 commands. Every command runs on your own computer; nothing is sent to a social network unless a publishing command is run by the owner with its live switches.

Ideas inbox: save a post idea for later with reachweaver idea “text” (the same as idea add); list, drop or promote one to a NEW blocked campaign scaffold; never creates a draft, approval or send

Save a post idea for later: reachweaver idea “text” (short for idea add “text”); several at once: reachweaver idea “first” “second”. Then list, drop or promote it. Nothing is drafted, queued or sent.

Terminal window
reachweaver idea [-h] ACTION ...

No options.

Add one or more open ideas (each up to 2000 characters): idea add “first” “second” saves both in one step

Terminal window
reachweaver idea add [-h] [--source SOURCE] [--tag TAG] [--json] TEXT [TEXT ...]
Option Description
TEXT The idea, in a sentence or two; give several (each in quotes) to save them all at once
--source SOURCE A public https URL the idea comes from (not opened or checked; one idea only)
--tag TAG A lowercase tag; repeatable (at most 8; with several ideas, each gets the tags)
--json Machine-readable result

List ideas, newest last

Terminal window
reachweaver idea list [-h] [--status {open,promoted,dropped}] [--tag TAG] [--json]
Option Description
--status STATUS Only ideas in this state One of: open, promoted, dropped.
--tag TAG Only ideas with this tag
--json Machine-readable result

Mark an open idea dropped (kept in the file; only data-purge with closed_ideas_days removes it)

Terminal window
reachweaver idea drop [-h] [--json] id
Option Description
id The idea id, e.g. idea-1a2b3c4d
--json Machine-readable result

Write a NEW campaign scaffold folder from an open idea; it stays BLOCKED until you write and verify it; nothing is staged, approved or sent

Terminal window
reachweaver idea promote [-h] --campaign NAME --out NEW_DIR [--brand BRAND]
[--accounts A]
[--objective {awareness,contributors,discussion,qualified_visits,signups}]
[--json]
id
Option Description
id The idea id
--campaign NAME The new campaign_id (a lowercase slug)
--out NEW_DIR A NEW folder (0700) for campaign.reachweaver.json and brief.md (0600); refuses an existing one
--brand BRAND Optional brand JSON: sets brand_id; with –accounts one placeholder variant per approved account
--accounts A Optional PUBLIC accounts config used with –brand
--objective OBJECTIVE Campaign objective (default awareness) One of: awareness, contributors, discussion, qualified_visits, signups.
--json Machine-readable result

Queue a platform-native text draft for an account (repeat –account for one draft per account; each still needs its own approval)

Terminal window
reachweaver draft [-h] --account ACCOUNT (--text TEXT | --file FILE)
[--campaign CAMPAIGN] [--source-url SOURCE_URL] [--persona ID]
[--optout OPTOUT] [--reply-to ITEM] [--online]
[--override-flagged LABEL] [--sources CONFIG] [--json]
Option Description
--account ACCOUNT Account id; repeat to create one separate draft per account, all or none
--text TEXT
--file FILE
--campaign CAMPAIGN
--source-url SOURCE_URL
--persona ID Which of your personas this post is for (for example work or family). Refuses an account that belongs to another persona and names the one to switch to; default: preferences.default_persona in the profile
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention refuses the draft (and, with –reply-to, a listed parent author)
--reply-to ITEM Issue #17 (owner-approved 2026-10-09; disabled until a live receipt): make this a reply to an engagement item id (bluesky:at://… or mastodon:HOST:ID from engagement-fetch/triage) under one of your own published posts; needs –online to verify the parent; sending stays blocked by the capability registry
--online With –reply-to: allow the unauthenticated read-only GETs that verify the parent (without it the planned requests are printed and nothing is created)
--override-flagged LABEL With –reply-to: explicit human override for a parent that triage flags as suspicious, harassment, spam or moderation_labelled (must name that exact label); opt-out signals are never overridable
--sources CONFIG sources-scan config (#9): refuse when the text (a reply’s too) or –source-url links into any visibility:private repository of that config (private repository URLs are never public links)
--json Machine-readable result: the created post id(s); not with –reply-to

Validate a draft before approval

Terminal window
reachweaver check [-h] [--json] [--persona ID] [--optout OPTOUT] [--sources CONFIG]
post_id
Option Description
post_id
--json Machine-readable result: ok and the findings
--persona ID Which of your personas this post is for (for example work or family). Refuses an account that belongs to another persona and names the one to switch to; default: preferences.default_persona in the profile
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention is BLOCKED
--sources CONFIG sources-scan config (#9): refuse when any published text (post, alt texts, video title/tags), a hosted image URL or the source URL links into any visibility:private repository of that config (private repository URLs are never public links)

Read-only: have we already shared this video, image, wording or link on this platform? Compares a stored post, or material you name, with the local history

Terminal window
reachweaver repeat-check [-h] [--post-id POST_ID] [--platform PLATFORM]
[--account ACCOUNT] [--text TEXT] [--file FILE] [--image FILE]
[--video FILE] [--link URL] [--days N] [--json]
Option Description
--post-id POST_ID A stored post to check (its text, images, video and link)
--platform PLATFORM With no –post-id: the platform to check against, e.g. youtube
--account ACCOUNT With no –post-id: the account (same-account repeats are the blocking ones)
--text TEXT With no –post-id: the post text
--file FILE With no –post-id: read the post text from this UTF-8 file
--image FILE An image file; repeatable
--video FILE A video file (compared by its exact bytes)
--link URL A link; repeatable
--days N Look-back for similar (not identical) wording, 1..3650 (default 365); identical files and wording are always found
--json Machine-readable result

Record material you shared by hand (manual export, a platform app) so later drafts are checked against it; with –url also makes it measurable (posted by hand); local, never sends

Terminal window
reachweaver mark-shared [-h] --platform PLATFORM [--account ACCOUNT] [--text TEXT]
[--file FILE] [--image FILE] [--video FILE] [--link URL]
[--url URL] [--at WHEN] [--note NOTE]
Option Description
--platform PLATFORM The platform it was shared on, e.g. youtube
--account ACCOUNT The account it was shared from; without it the record counts for every account on that platform
--text TEXT The post text
--file FILE Read the post text from this UTF-8 file
--image FILE An image file; repeatable
--video FILE A video file
--link URL A link; repeatable
--url URL The link of the post on the platform. With it the post also becomes measurable: a ‘published_manual’ record that metrics, import-metrics, report, insights and the dashboard include, labelled posted by hand; it can never be approved, scheduled or sent
--at WHEN When it was shared (default: now): now, today, yesterday, YYYY-MM-DD (midday), ‘YYYY-MM-DD HH:MM’ (your computer’s time zone) or ISO 8601 with a timezone; with –url this is the post’s send time for report –since and insights
--note NOTE A short label for yourself

Owner-only guided approval (#11): walk the drafts one by one, oldest first, in your own terminal; each shows its review sheet and check result, then a approves it through the approve command, s skips, c cancels (type CANCEL), q quits. Needs an interactive terminal; never batches; reply drafts are left out

Terminal window
reachweaver review [-h] [--campaign CAMPAIGN] [--account ACCOUNT] [--approver APPROVER]
[--persona ID] [--optout OPTOUT] [--sources CONFIG]
[--verify-identity] [--online]
Option Description
--campaign CAMPAIGN Only drafts of this campaign
--account ACCOUNT Only drafts of this account id
--approver APPROVER Passed to each approve (attribution, not authentication); defaults to $USER/$LOGNAME
--persona ID Passed to each check and approve: refuse an account of another persona
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); passed to each check and approve
--sources CONFIG sources-scan config (#9), passed to each check and approve: refuse links into private repositories
--verify-identity Each approve runs its one read-only identity check (needs –online), as approve –verify-identity
--online Required with –verify-identity

Approve the exact current text; binds an immutable payload hash (#7), plus a Mastodon account’s visibility/language/spoiler_text or a Postiz account’s server and integration

Terminal window
reachweaver approve [-h] [--persona ID] [--approver APPROVER] [--verify-identity]
[--online] [--optout OPTOUT] [--allow-repeat]
[--ai-label {applied,not_needed}] [--sources CONFIG]
post_id
Option Description
post_id
--persona ID Which of your personas this post is for (for example work or family). Refuses an account that belongs to another persona and names the one to switch to; default: preferences.default_persona in the profile
--approver APPROVER Who approved (attribution, not authentication); defaults to $USER/$LOGNAME
--verify-identity Wave 9 item 2: run the read-only connect-check identity check once and bind a fingerprint of the verified account (no token or response stored); needs –online. A failed check approves nothing. Binds WHICH account, not WHO approved
--online Required with –verify-identity: allow that one read-only identity request
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention refuses approval
--allow-repeat Approve even though this account has already shared (or has another approved copy of) the same video, image or wording on this platform (repeat-check shows what matched). Bound into the approval, so the send-time repeat check lets this one post through; also an audit event
--ai-label AI_LABEL Posts with images or a video only: your answer to the AI-content label question when ai-label-check says required or unknown for the post’s platform (approval is refused without it). applied: you label it yourself (platform composer or text; ReachWeaver sets no label); not_needed: you decided no label is needed. Bound into the approval (approval/media-3) One of: applied, not_needed.
--sources CONFIG sources-scan config (#9): refuse when any published text (post, alt texts, video title/tags), a hosted image URL or the source URL links into any visibility:private repository of that config (private repository URLs are never public links)

Withdraw approval: an approved or scheduled post goes back to draft and its payload binding is cleared; local only

Terminal window
reachweaver unapprove [-h] [--json] post_id
Option Description
post_id
--json Machine-readable result

Cancel a draft, approved or scheduled post so it is never sent; local only

Terminal window
reachweaver cancel [-h] [--json] post_id
Option Description
post_id
--json Machine-readable result

Give an approved post a due time (explicit timezone offset); a worker you run still has to publish it

Terminal window
reachweaver schedule [-h] --at AT [--json] post_id
Option Description
post_id
--at AT Explicit ISO 8601 timezone offset, e.g. 2026-10-15T09:00:00+02:00
--json Machine-readable result

Add one image with required alt text to a DRAFT: a local PNG/JPEG/WebP file for Mastodon (–file, offline) or an owner-hosted HTTPS JPEG URL for Instagram (–url with –online: one read-only GET to hash it). Its SHA-256 (and the URL) are bound at approval (#13, #20); never uploads

Terminal window
reachweaver media-attach [-h] (--file FILE | --url URL)
(--alt ALT | --alt-file ALT_FILE) [--focus FOCUS] [--online]
[--rights-confirmed] [--license ID]
[--created-by {owner,third_party,tool}] [--tool TOOL]
[--attribution ATTRIBUTION] [--rights-source-url URL]
[--alt-translation LANG=TEXT] [--optout OPTOUT]
[--sources CONFIG]
post_id
Option Description
post_id
--file FILE Mastodon: local image file (not a symlink); checked from its header
--url URL Instagram: public HTTPS image URL on a host you control (no query string); Meta fetches this URL itself when the post is sent
--alt ALT Alt text describing the image (required; Mastodon description or Instagram alt_text)
--alt-file ALT_FILE Read the alt text from this UTF-8 file
--focus FOCUS Mastodon only: optional focal point x,y, each -1.0..1.0 (0,0 = centre)
--online Required with –url: allow one read-only GET of the image URL
--rights-confirmed #48: you confirm you hold the rights, consent and likeness permission for this image; required with any other rights option
--license ID #48: SPDX id (for example CC-BY-4.0), ‘owner’ or ‘licensed’; stored with the image and bound at approval
--created-by CREATED_BY #48: who made the image (provenance) One of: owner, third_party, tool.
--tool TOOL #48: with –created-by tool: the generation or editing tool
--attribution ATTRIBUTION #48: attribution text (required for third_party and CC-BY images)
--rights-source-url URL #48: public HTTPS page the image came from (provenance)
--alt-translation LANG=TEXT #48: your own alt text in another language (BCP-47 tag), stored and bound but not sent; repeatable
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention in the alt text refuses the attachment
--sources CONFIG sources-scan config (#9): refuse when the alt text or the image URL links into any visibility:private repository of that config (private repository URLs are never public links)

Offline: remove every image attachment from a DRAFT

Terminal window
reachweaver media-detach [-h] post_id
Option Description
post_id

Offline: record your AI-content declarations on a DRAFT: who wrote the text (–authorship) and whether each image or video is realistic AI-made media (–realistic-synthetic); bound at approval for a post with media (approval/media-3) and used by the AI-label precondition

Terminal window
reachweaver ai-declare [-h] [--authorship {human,ai_assisted,ai_generated,clear}]
[--realistic-synthetic {yes,no,clear}] [--attachment N] [--json]
post_id
Option Description
post_id
--authorship AUTHORSHIP Who wrote the text: human, ai_assisted or ai_generated (clear removes it) One of: human, ai_assisted, ai_generated, clear.
--realistic-synthetic REALISTIC_SYNTHETIC yes: the image/video could pass as a real photo or recording but was AI-made or altered; no: it is not; clear removes the answer. Applies to every attachment unless –attachment One of: yes, no, clear.
--attachment N Only the Nth attachment (1-based, in send order; a video is 1)
--json Machine-readable result: the declarations and the advice

Offline: bind one local MP4 to a TikTok DRAFT (issue #23; owner-approved, disabled until a live receipt); approval binds its SHA-256 and the delivery options; a post has images or one video, never both; never uploads

Terminal window
reachweaver video-attach [-h] --file FILE [--mode {creator_inbox,direct_post}]
[--privacy-level {PUBLIC_TO_EVERYONE,MUTUAL_FOLLOW_FRIENDS,FOLLOWER_OF_CREATOR,SELF_ONLY}]
[--commercial {none,own_brand,branded_content}]
[--allow-comment] [--allow-duet] [--allow-stitch] [--aigc]
post_id
Option Description
post_id
--file FILE Local MP4 (not a symlink), at most 256 MiB
--mode MODE creator_inbox (default): a draft the creator finishes in the TikTok app, never public by itself; direct_post: publishes (second registry switch, off) One of: creator_inbox, direct_post.
--privacy-level PRIVACY_LEVEL direct_post only, required, no default; must be offered by the creator’s creator_info One of: PUBLIC_TO_EVERYONE, MUTUAL_FOLLOW_FRIENDS, FOLLOWER_OF_CREATOR, SELF_ONLY.
--commercial COMMERCIAL direct_post only, required: commercial disclosure One of: none, own_brand, branded_content.
--allow-comment direct_post only: turn comments on (default off)
--allow-duet direct_post only: turn duets on (default off)
--allow-stitch direct_post only: turn stitchs on (default off)
--aigc direct_post only: label the video as AI-generated

Offline: remove the video from a TikTok DRAFT; the file is untouched

Terminal window
reachweaver video-detach [-h] post_id
Option Description
post_id

#22 (owner-approved; disabled until a live receipt): attach one local MP4 + upload metadata to a YouTube draft; offline, hashes the file; live upload stays registry-blocked

Terminal window
reachweaver youtube-attach [-h] --file FILE --title TITLE
[--privacy {private,unlisted,public}] --made-for-kids
{yes,no} --category-id CATEGORY_ID [--tag TAG]
[--sources CONFIG]
post_id
Option Description
post_id
--file FILE Local MP4 file (symlinks refused); its SHA-256 is bound
--title TITLE Video title, at most 100 characters, no ‘<’ or ‘>’
--privacy PRIVACY privacyStatus to request (default private; the API default would be public) One of: private, unlisted, public.
--made-for-kids MADE_FOR_KIDS Required human answer for selfDeclaredMadeForKids (YouTube requires every creator to set it) One of: yes, no.
--category-id CATEGORY_ID Numeric YouTube category id (videoCategories.list)
--tag TAG One tag; repeat (500 characters in total)
--sources CONFIG sources-scan config (#9): refuse when the title or a tag links into any visibility:private repository of that config (private repository URLs are never public links)

#22: remove the video from a YouTube draft; offline

Terminal window
reachweaver youtube-detach [-h] post_id
Option Description
post_id

Offline evidence/brand/variant checks; does not assert source truth

Terminal window
reachweaver campaign-check [-h] --file FILE [--brand BRAND] [--json] [--optout OPTOUT]
[--history-db PATH] [--history-days N]
[--history-window-days W] [--history-max-posts K]
Option Description
--file FILE
--brand BRAND Brand file; omitting skips account/voice checking
--json Machine-readable diagnostics
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present)
--history-db PATH Also compare variants with this EXISTING local database’s posts of the same account (read-only; never created or modified). Warnings only. The global –db is not used here
--history-days N History look-back for history_near_duplicate, 1..365 (default 30)
--history-window-days W Rolling window for the history_frequency heuristic, 1..365 (default 7)
--history-max-posts K history_frequency warns at K existing posts per window, 1..1000 (default 7; a ReachWeaver heuristic, not a platform limit)

Offline per-channel previews: exact text, platform length, facets, capability, evidence, rule-based confidence; never stages or publishes

Terminal window
reachweaver campaign-preview [-h] --file FILE --brand BRAND
[--accounts PREVIEW_ACCOUNTS] [--utm] [--optout OPTOUT]
[--history-db PATH] [--history-days N]
[--history-window-days W] [--history-max-posts K]
[--json | --markdown]
Option Description
--file FILE Campaign JSON (read only; never modified)
--brand BRAND Brand JSON, including optional per-account rules
--accounts PREVIEW_ACCOUNTS Optional PUBLIC accounts config (e.g. Mastodon max_characters); same as global –accounts
--utm Show each link with utm_source/medium/campaign and utm_content=variant id
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention is an error
--history-db PATH Also compare variants with this EXISTING local database’s posts of the same account (read-only; never created or modified). Warnings only. The global –db is not used here
--history-days N History look-back for history_near_duplicate, 1..365 (default 30)
--history-window-days W Rolling window for the history_frequency heuristic, 1..365 (default 7)
--history-max-posts K history_frequency warns at K existing posts per window, 1..1000 (default 7; a ReachWeaver heuristic, not a platform limit)
--json Machine-readable preview
--markdown Editable Markdown review sheet

Idempotently stage verified text variants as drafts; never publishes

Terminal window
reachweaver campaign-stage [-h] --file FILE --brand BRAND [--optout OPTOUT] [--json]
Option Description
--file FILE
--brand BRAND Required explicit brand-account allowlist
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present)
--json Accepted for consistency: the result is always JSON

Export validated draft pack for manual publishing; no network

Terminal window
reachweaver campaign-export [-h] --file FILE --brand BRAND --out OUT [--optout OPTOUT]
Option Description
--file FILE
--brand BRAND
--out OUT New output folder; refuses existing output
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present)

Offline LEXICAL claim grounding of variants vs declared evidence; not truth verification

Terminal window
reachweaver claims-check [-h] --brand BRAND [--duplicate-threshold DUPLICATE_THRESHOLD]
[--json] [--optout OPTOUT]
campaign
Option Description
campaign Campaign JSON file
--brand BRAND Brand JSON (banned_phrases, required_disclosure)
--duplicate-threshold DUPLICATE_THRESHOLD Word 3-gram Jaccard at which variants are near-duplicates, (0,1] (default 0.6)
--json Machine-readable grounding report
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention is an error

Offline: write a NEW private folder with the exact text, destination, alt text, content digest and check findings of posts for a co-reviewer; never approves

Terminal window
reachweaver review-packet [-h] (--post-id ID | --campaign-staged NAME) --out OUT
[--persona ID] [--optout OPTOUT] [--sources CONFIG] [--json]
Option Description
--post-id ID A stored post to include (repeatable)
--campaign-staged NAME Every draft, approved or scheduled post staged for this campaign id
--out OUT NEW folder (0700; files 0600); refuses an existing path. Under <state>/review-packets/ review-status finds it without –packet
--persona ID As for check: the persona these posts are for
--optout OPTOUT Opt-out list JSON (default $REACHWEAVER_OPTOUT or config/optout.json if present); a mention is a BLOCKED finding
--sources CONFIG sources-scan config (#9): a post linking into a private repository is refused and a private source URL is redacted
--json Machine-readable result (folder, files, digests)

Record a co-reviewer’s comment in the packet’s private comments.json, bound to the post’s content digest; never approves or changes a post

Terminal window
reachweaver review-comment [-h] --packet DIR --post-id ID --reviewer NAME --verdict
{looks_good,change_requested,question} --note TEXT [--json]
Option Description
--packet DIR Folder written by review-packet
--post-id ID A post in that packet
--reviewer NAME Who commented (a label, not authentication)
--verdict VERDICT looks_good is an opinion, not approval One of: looks_good, change_requested, question.
--note TEXT The comment (at most 2000 characters)
--json Machine-readable result

Read-only: reviewer comments per post, STALE when the post changed after the comment; never approves

Terminal window
reachweaver review-status [-h] [--packet DIR] [--json]
Option Description
--packet DIR One packet (default: every packet under <state>/review-packets/)
--json Machine-readable result