Skip to content

Browser Share Composer — a simpler way to prepare social posts

Status: experimental, local-only manual publishing preparation. This feature does not post, upload to a network, schedule, create accounts, fetch analytics, or call a social platform. Its only database write is “Mark as posted”, which records a post you already published by hand.

The browser composer is for people who want to share work on Instagram, TikTok, Threads, YouTube and other platforms without editing JSON or using lots of terminal commands. It uses the existing ReachWeaver manual-export safety checks, including the checks on each individually edited platform caption. No additional model API, subscription, cloud hosting or password is required.

From the project folder, run:

Terminal window
python3 -m reachweaver share --web --open

Or, if you have the ReachWeaver command installed:

Terminal window
reachweaver share --web --open

Your browser should open an address starting with http://127.0.0.1. If it doesn’t, copy the complete private local URL printed in your terminal into the browser on the same computer. Leave the terminal open while using the composer. Press Ctrl+C in the terminal to stop the server.

Do not share that session URL. It contains a random authorization token in the URL fragment. ReachWeaver does not store credentials, cookies or posting tokens for this feature.

Start from an idea or a text. reachweaver share --web --open --idea idea-0a1b2c3d starts the draft with that open idea’s text (the ideas inbox is only read; reachweaver next prints this command for each idea), and --text "..." does the same with your own words. If the composer already holds a post you have not saved, nothing is replaced: the terminal says so and the page asks, at the top of the editor (scrolled into view, with focus on Use it as my caption), whether to use the text as your caption; Keep my draft leaves it, and Undo brings your caption back. If the editor holds a saved package unchanged (opened or just saved), the idea starts a new post with your networks chosen instead, and the page says the saved package is still in Saved packages, unchanged. Both name the idea by its first words (Use your idea “Behind the scenes of the speckled mug glaze…” as the caption instead?), never by its id.

On a phone the brand bar stays at the top while you scroll and, under studio, keeps a Results link; the short tagline wraps instead of being cut off.

Composer and dashboard together. reachweaver studio --open starts this composer and the read-only dashboard together: See how your posts did (top and bottom of the page, and after Mark as posted) then opens the dashboard’s Results, and the dashboard’s Write a new post opens this page. On its own, the composer shows the command to start the dashboard instead. See the dashboard guide.

Five steps: Write → Choose → Preview → Save → Post

Section titled “Five steps: Write → Choose → Preview → Save → Post”

The page is titled ReachWeaver — Write a post. A small progress bar under the header shows these five steps and moves on as you work (the current step is marked for screen readers with aria-current="step"), and the line under it says what to do next. On a phone the header shrinks to one line, so the caption box is visible as soon as the page opens.

  1. Write: enter one caption/description. When the editor is empty, the caption box already has the cursor on a wide screen, so you can just type; on a phone it gets the cursor only when you came from a Write link on the dashboard (so the keyboard never pops up on a plain visit). For YouTube, add a video title. For human-only communities, add a short private note and write the real message yourself.
  2. Choose: search or tap networks, up to ten at once. The networks of your own accounts (accounts.json, read only; example placeholders left out) are listed first under Your networks and are already chosen on a fresh draft, so for your usual networks you only write, preview and copy; tap a chip to remove one, and the draft remembers your choice. The chosen ones show as chips above the list (tap a chip to remove it); on a phone the list is part of the page, not a small box to scroll inside. Every network gets a copy-only package; Bluesky, LinkedIn, Mastodon and Telegram are offered as copy-only too (see below), and nothing is sent from this page.
  3. Preview and tailor: the previews follow what you type. About 400 ms after you stop typing (or change a network, title, note or attachment) every network is checked again on this computer and each card shows its exact text and warnings; nothing is saved or sent. A newer check cancels one still running, and an answer that no longer matches the editor is dropped. Refresh previews (below both panels) stays as a fallback. Edit each network’s caption separately on its card (for example a short Threads version and a longer Instagram version); the other networks are rechecked as you type there, and the card keeps your text and cursor. Changing the main caption discards these per-network edits, so finish the main caption first. Copy caption appears on each card as soon as it has a preview; it copies the current editor text and says “Copied” (also announced to screen readers); nothing posts automatically.
  4. Save (optional): click Save as new package to keep the posts ready for later. ReachWeaver writes a new private folder below state/shares (in your workspace, or else the folder you started the command from) and says, for example, Saved: Our first speckled mugs are out of the… · 21 Oct 19:30 (in state/shares/share-20261021-193000-…), with a Copy folder path button. The readable name comes from the first words of your caption and the save time; it is for display only (kept in the package’s PACKAGE.json), and the folder keeps its fixed share-YYYYMMDD-HHMMSS-<hex> name. Open OPEN-FIRST.md, review each platform’s CHECKLIST.md, and paste the relevant caption into the native app yourself. You do not need to save first to mark a post as posted: see the next step.
  5. Post, then mark as posted (optional): after you published a network’s post yourself, choose Mark network as posted on its preview card (or under Saved packages, see below) and paste its link so ReachWeaver can measure it. If the post is not saved yet, that same step saves it as a new package first.

There is no Publish button, because this UI is a manual handoff, not a new API integration. “Mark as posted” only records what you already did by hand.

To see how your posts did, run reachweaver ui (the read-only dashboard) in a terminal; the composer shows that command with a Copy button in its header and footer. It does not link to the dashboard: the two are separate local servers with separate session links.

The composer uses the dashboard’s colours, font, corner radius and “RW” mark, and follows your system’s light or dark setting (prefers-color-scheme). Under studio, the dashboard’s Theme choice (Settings) travels in the address fragment of its links to the composer (&theme=dark, never sent to a server; the two pages are different origins and share no browser storage); the composer keeps it in its own browser storage until the next link brings another choice, and if storage is blocked it follows the system setting. The keyboard focus ring has at least 3:1 contrast in both themes; Copied, Saved and Recorded messages go to a screen-reader status region; and on screens narrower than 640 px every button and field is at least 44 px tall. Warnings use plain words, for example Instagram needs a photo or video. Add it here or attach it in the Instagram app. instead of the command-line media-manifest wording; the rule behind each message is unchanged.

As you type, the composer keeps your draft on this computer (state/composer/draft.json, readable only by you) and the bar above the editor says Saved. Close the tab or restart the composer and the draft comes back. The draft holds only the editor fields: networks, caption, per-network edits, YouTube title, community note, the attached files and the package you are editing; never the session link or any password. Undo reverts your last change (a burst of typing counts as one change). Clear form empties the editor and deletes the draft and its attached files; saved packages are not touched.

The Saved packages section lists every package in state/shares, newest first, under its readable name, with each network marked Ready to post (its files are in the package) or Posted by you.

  • Open in editor loads the package back: networks, caption, per-network edits, title, note and attached files. If the editor already holds something, the first click asks you to click again.
  • Duplicate as new copies the package into a new one (rechecked against every rule; no network is marked posted in the copy). The copy’s name ends in “(copy)”, it is listed first with a New copy label, and the message names the new folder.
  • After opening a package, preview it, then choose Save as new package (always a fresh folder, nothing overwritten) or Update this package. Update asks you to confirm, replaces that package’s files in one step, and is refused if the package changed since you opened it or if any of its networks is already marked as posted (save as new instead). For a package with a network marked as posted the button is disabled with that reason under it, so the confirmation is never offered. Each preview card shows the network’s saved state (Ready to post, Posted by you) only while the editor still holds that package unchanged; after any change it says Changed, not saved.

Choose Photos or videos under the caption to attach up to ten files (.jpg, .jpeg, .png, .webp, .mp4, .mov or .webm, at most 256 MiB each). The browser sends the file only to the local ReachWeaver server on this computer, which keeps it in state/composer/media and copies it into the package’s media folder when you save. Nothing is uploaded to a social network: you still attach the file yourself in Instagram, TikTok, YouTube Studio and so on.

Each preview card then lists Photo and video checks: the same offline header checks as share –attach (container, size, dimensions, duration and the like against each network’s sourced limits, and what could not be checked). These checks do not cover copyright, faces/likeness consent, disclosures, captions or alt text; the existing media-check validates owner-supplied media manifests for those.

Mark as posted (measure what you posted by hand)

Section titled “Mark as posted (measure what you posted by hand)”

On a preview card choose Mark network as posted (for example Mark Bluesky as posted), or under a saved package choose Mark as posted next to a network. The cursor is in the link field: paste the link of the post you published, press Tab to the numbers (Likes, then Replies, Reposts, Views), type what the app shows, and press Enter (or Record as posted). Enter in any field of the form records it. The optional account and posted time come after the numbers. A link without https:// (such as www.threads.net/@you/post/…) gets it added; anything that is still not one web link shows Paste the full link to your post, starting with https:// before anything is sent. The server checks the link again.

From a preview card, before saving. When the editor holds a saved package unchanged, the card records into that package, exactly as under Saved packages. Otherwise (a new post, or a saved package you changed) the server saves what the editor holds as a new package and records the network in the same request (/api/save-and-mark; never an update, nothing existing is overwritten). Every check of both runs first: the post is rechecked for every network, then the link, account, numbers, network, a posted time in the future and a link already recorded for that network (read-only). Any refusal there saves and records nothing. If the history database still refuses the record after the save, the page says which package was kept (Saved as a new package: … but it was not marked as posted: …); the editor then holds that package, and Mark as posted again records it there. The card then shows Posted by you, and the page says what was saved and recorded. Mark the next network on its own card: it records into the package just saved.

If your accounts.json (REACHWEAVER_ACCOUNTS, else the workspace’s config/accounts.json) has accounts for that network, an optional Which account? list offers them (id and public handle only; the file is read, never written, and read again when the page comes back into view and before recording, so an account you just added appears without a reload). When exactly one of your accounts is on that network, it is already chosen. As soon as you paste a link that names one of your accounts (for example bsky.app/profile/work-creator.bsky.social/post/…, or a Mastodon @handle on your account’s server), that account is chosen for you, the same way reachweaver posted LINK resolves it. You can still change it, or pick “Not sure / skip”: then the server still uses the account the link names, and says so (Recorded … for work-bluesky (from the link)). A chosen account must exist in accounts.json and be for that network’s platform (dev matches devto), and it must not contradict the link (a link by another of your accounts, or by a handle the chosen account does not have), else the server refuses with a plain message and records nothing.

Numbers, optional: Likes, Replies, Reposts, Views — optional, as shown in the app. Type the counts the app shows (whole numbers from 0 to 1,000,000,000; leave the others empty). They are kept with the record as numbers you entered by hand, as of now (entered-by-hand, the same as reachweaver posted LINK --likes N).

The composer records it exactly like mark-shared --url (with --account when an account was chosen or named by the link): a “posted by hand” record (status published_manual) in your history database, with the package’s caption and media fingerprints so the repeat guard knows them. The network turns Posted by you. With numbers, the page says so and offers See it in your results (under studio; alone it shows the reachweaver ui command with a Copy button). Without numbers it says how to add them later: Update numbers under that network, or reachweaver posted LINK --likes N in a terminal (Copy command button).

Update numbers appears under every network you marked as posted here. It adds a new snapshot of the numbers the app shows now (entered by hand, as of now) to that post only: the server checks that the package’s posted record names a “posted by hand” post of the same network and link in your history, and refuses anything else (nothing is recorded). It never changes the post itself.

It is refused, with nothing recorded, when the link is not one http(s) link, when that link is already recorded for the network, when the time is in the future, when a number is not a whole number from 0 to 1,000,000,000, for human-only venues (record your own post with mark-shared in the terminal), and for networks ReachWeaver cannot measure yet. The record can never be approved, scheduled or sent. It uses the history database of --db, REACHWEAVER_DB or the workspace, like other commands (reachweaver --db PATH share --web).

These networks are in the list too, marked “Copy and post yourself · or connect it to send from ReachWeaver”. The composer prepares copy-ready text for them exactly as for the others and never sends. Each preview card says: Copy and post it yourself; to send it from ReachWeaver instead, connect the account and use draft → review. A caption that is too long for a network is shortened for that network only (at a sentence end when possible, else at a word; a closing link is kept), and its card says what was removed; edit it there if you prefer your own cut.

Some destinations (e.g. Reddit and Hacker News) are treated as human-only. They receive private NOTES.md files, not ready-made AI-authored promotional text. Human participants must check community rules and create their own posts. No bulk messages, automatic comments, login workarounds or unsolicited engagement.

How is the browser interface kept private?

Section titled “How is the browser interface kept private?”
  • It binds only to 127.0.0.1 (loopback). It is not a public website. Do not set up proxy forwarding to the composer.
  • This session is meant for the same computer that runs ReachWeaver. Do not expose it with SSH tunnels, reverse proxies, remote-access tools or router port forwarding.
  • A new cryptographically random session token is required for both reads of the manual platform catalog and POST actions. Every request must carry the exact local Host header (a DNS-rebinding defence); POST actions also require the exact local Origin. Cross-origin preflights and other methods are refused, and no CORS header is sent. A request body is limited to 96 KiB and must arrive within 10 seconds.
  • No cookies, external JavaScript, remote fonts, images, trackers or cloud backend. The local page uses a restrictive Content Security Policy and inserts content as text, not executable HTML.
  • No caption is transmitted to social platforms. Text is sent from your browser to the local ReachWeaver server on the same computer for validation and file generation.
  • Preview never writes files. Saving always rechecks rules, creates a fresh 0700 owner-only directory (on POSIX), writes 0600 files and stages the entire handoff before a final rename. An update replaces a package only after your confirmation and only if it is unchanged since you opened it.
  • The browser cannot specify an arbitrary destination path or load a local file by URL. Package names and attached-file ids must match a strict pattern and are resolved and confirmed to sit inside the private state/shares or state/composer folder; symbolic links there are refused, never followed. An attached file is at most 256 MiB, must have a photo or video extension and must arrive within 120 seconds.
  • The history database is opened only by Mark as posted (a terminal “posted by hand” record, plus the numbers you typed; from a preview card it may first save a new package, in the same request and behind the same token, Host, Origin, size and write-lock checks, where a refused check opens the database read-only at most and writes nothing) and Update numbers (a numbers snapshot for a post this composer recorded by hand). None of them can approve, schedule or send. accounts.json is only read (for the optional account list, “Your networks”, the account a link names and to check a chosen account); credential variable names are never sent to the page.
  • A malicious program already running as your operating-system user may still access your local files or browser session. Keep the computer secure and never share your session link.

The default command line share –guide remains available for anyone who prefers using a terminal. The existing read-only operations dashboard, reachweaver ui, remains unchanged and read-only.

Run the offline test suite and packaging checks before release:

Terminal window
python3 -m unittest tests.test_share tests.test_share_browser tests.test_share_browser_composer -v
python3 -m unittest discover -s tests -v
python3 scripts/sync_skill.py --check

A passing test is not a real social-platform receipt. Browser previews and saved manual packages should never be labelled “published” in the app or in marketing.