ReachWeaver 0.16.0 release notes
Released on 2026-10-22.
Much easier to use, measured. reachweaver studio opens one browser app where you write a post (your networks preselected), copy it for each network, mark it as posted with its numbers and see how it did. In the terminal, posted LINK --likes N records a post you made by hand in one step, next answers “what should I post next?” with your ideas by name, report --week gives a short summary instead of JSON, and every error says what to do. Measured against 0.15.0 with the same journeys: failed commands, dead ends, errors without a next step, hand-edited files and web steps that needed the terminal all went to zero; phone tap targets under 44 px went from 71 to 2; journey friction is about 3x lower. 133 commands (4 more than 0.15.0, none removed). No live adapter is added.
Security
Section titled “Security”- Composer numbers and link accounts (owner-approved write path, 2026-10-21):
/api/mark-postedtakes optionalnumbers(only likes/replies/reposts/views, each an exact JSON integer 0..10^9 or null; strings, decimals, booleans and other keys are refused before any write) and stores them withstorage.store_metrics(sourceentered-by-hand, observed now) for the post it just created. New/api/numbersadds a snapshot only for the post named by that package network’sPOSTED.json, and only when the database row ispublished_manualwith the same platform and link (a draft, another post or a tampered record is refused, nothing written). A chosen account that the link contradicts is refused before the database is opened. New read-only/api/link-accountreturns which configured account a link names. All new routes sit behind the same Host/token/Origin/size/depth guards and the server write lock; nothing new can approve, schedule or send, and the dashboard stays GET/HEAD-only. Tests:tests/test_composer_ux3.py. - Composer: the optional
account_idon/api/mark-postedis checked by the server (id pattern, present in accounts.json, same history platform) before the database is opened, and passed torecord_manual_publish; nothing new can approve, schedule or send. New read-only/api/accountsroute behind the same Host/token/Origin/size guards returns ids, platforms and public handles only (neverenv_prefix). Display names are stripped of control, format/bidi, surrogate and private-use characters, re-validated on every read, and shown withtextContent. postedis inmcp_server.NEVER_EXPOSED(a backstop; it is taggedwrites, so it was never a tool): an MCP client never states on the owner’s behalf that a post was published or what its numbers are. It never writes the send queue, approves or contacts a network; its record is the existing never-sendablepublished_manualstate.nextprints the owner’s idea text and post wording, somcp-servewithholds it (mcp_server.WITHHELD_COMMANDS, a tightening). No approval, dry-run, pause, credential, reconciliation, Hacker News or Reddit rule changed; nothing new writes to the database or the send queue.studiolinks the dashboard and the composer without merging them: two loopback servers, two per-run tokens, every guard unchanged (the dashboard stays GET/HEAD-only and read-only; the composer keeps its Host/Origin/token/size checks). Each learns the other’s URL only from a token-gated JSON answer in the same process (api/studio,/api/catalog), never from static HTML; both sendReferrer-Policy: no-referrer, links arerel="noopener noreferrer", CSPs are unchanged. The new composer route/api/ideaonly reads one open idea.studiois added tomcp_server.NEVER_EXPOSED(a tightening). Details: docs/ARCHITECTURE.md “Studio”.postedcorrections (storage.correct_manual_publish) write only apublished_manualrow (theUPDATEitself is guarded bystatus='published_manual') and its linkedmark-sharedentry:send_started_at,content,account_idand the derivedremote_id. Status and approval columns are never written, so the record stays outside every send path; a post ReachWeaver sent, and every other status, is refused. Nothing writes the send queue; no approval, dry-run, pause, credential, reconciliation, Hacker News or Reddit rule changed.
- Composer: numbers in the browser. Mark as posted has optional fields Likes, Replies, Reposts, Views — optional, as shown in the app, and every network marked as posted gets Update numbers (a new hand-entered snapshot, as of now). After recording with numbers the page offers See it in your results (under
studio; alone, thereachweaver uicommand); without numbers it points to Update numbers orreachweaver posted LINK --likes Ninstead of the oldmetrics POST_IDcommand. - Composer: “Your networks”. The networks of your own accounts (accounts.json, example placeholders left out) are listed first and preselected on a fresh draft (you can remove any; the draft remembers the choice). Writing for your usual three networks is caption + Preview + 3 Copy = 5 clicks (was 9).
- Composer: the account a link names. Typing a post link picks the account it names in Which account?; with “Not sure / skip” the server still uses that account, the same way
reachweaver postedresolves it, and says so (“Recorded … for work-bluesky (from the link)”). The account list is read again when the page comes back into view and before recording. account-remove ID(new command, offline): removes one entry fromconfig/accounts.json(or--accounts) after a[y/N]confirmation in a terminal, or--yeselsewhere;--dry-runwrites nothing. The previous file is kept asaccounts.json.bak. It never touches credentials, the database, approvals, the approval ledger or disconnect state; posts recorded for the account stay in the database, are counted read-only and reported. An unknown id is refused with the list of ids. Catalog:writes. Tests:tests/test_account_add.py.--versionglobal flag: prints exactly whatreachweaver versionprints.workspace --init DIR --with-examplesseeds the four example placeholder accounts (the earlier default; see Changed).- “link in bio” check in
share. Where a link in the post itself works, the package warns and says why: Bluesky (rich-text links, https://docs.bsky.app/docs/about-bluesky-content/post-richtext, quote “Posts in Bluesky use rich text to handle links”), Telegram (https://core.telegram.org/api/entities, “These entities turn certain sections of the message blue and make them clickable”) and Mastodon (https://docs.joinmastodon.org/user/posting/, “If you include links in your post, they must begin with http:// or https://”), all checked 2026-10-21. LinkedIn’s note says clickability is unverified. The text is never changed. - One labelled tip per network in
share’s OPEN-FIRST.md, each restating a fact ReachWeaver already holds with a source (manual_export.FACTS, the capability registry, the draft/check limits); a suggestion, not a promise of reach. reportat a terminal prints a short summary (“This week (since 2026-10-14): 3 posts · 120 likes · 9 replies · best: … on Instagram (95 likes, 7 replies)”), a table per network, the top 5 posts by interactions with their first words, posts with no numbers or due for their 7-day numbers, and the early-results note.--format textasks for it explicitly;--weekis--since 7d. Unknown counts print as-, never 0.show POST_IDlists the post’s latest recorded numbers per source, with when they were observed and how many hours after posting (resultsin the JSON for published and posted-by-hand posts), or the exactmetricscommand when none are recorded.- Human times when recording (
reachweaver/when.py, one parser):metrics --observed-at/--window-start/--window-endandmark-shared --atacceptnow,today,yesterday,YYYY-MM-DD(midday local, never in the future),'YYYY-MM-DD HH:MM'(the computer’s time zone, its daylight-saving rules for that date) and ISO 8601 as before. Stored times are unchanged: ISO 8601 UTC with offset.import-metricsfiles still need an explicit offset. Tests:tests/test_when.py. reachweaver posted URL [--likes N --replies N --reposts N --views N] [--text "..."] [--at WHEN] [--account ID] [--platform P](new everyday command, offline): record a post you made by hand and, optionally, its numbers in one command. The platform comes from the link’s host through an explicit map (bsky.app, instagram.com, linkedin.com, tiktok.com, youtube.com/youtu.be, threads.net/threads.com, x.com/twitter.com, facebook.com, t.me, dev.to, reddit.com, pinterest.com, hashnode.com/hashnode.dev, and theserverof a configured Mastodon account); an unknown host asks for--platformwith the list and a “Did you mean”. The account is the configured one whose handle the link names, else the only configured (non-placeholder) account of that network; several and no clue asks for--accountwith the ids; none records the post without an account and says so. It usesstorage.record_manual_publish(the same never-sendablepublished_manualrecord asmark-shared --url) andstorage.store_metrics(sourceentered-by-hand, observed now). A link that is already recorded (by hand or sent by ReachWeaver) gets the new numbers added instead of failing (“Updated numbers for … on Bluesky”). Metric values are checked before anything is written.--textis optional: without it the link identifies the post (record_manual_publish(link_is_enough=True)), reports name it by a short link, and the repeat guard has no material to compare (an empty text never matches). Recording the J3 week (“how did my posts do this week”, 3 posts with numbers) goes from 7 commands plus copying 3 post ids (mark-shared --platform P --text ... --url ...andmetrics POST_ID ...per post, thenreport --week) to 4 (posted URL --likes N ...per post, thenreport --week). Catalog:writes. Docs: docs/MANUAL-EXPORT.md. Tests:tests/test_posted.py.startwithout an accounts file but with posts or ideas already recorded shows your progress (next, the duemetricsline,report --week, the composer) instead of only “No accounts file yet.” (stateposting_by_hand); a brand-new user still starts withshare --web --open.reachweaver studio(new command): the read-only dashboard and the browser composer in one process, linked to each other. Write a new post (sidebar, a 44 px button at the top of the Overview on phones, the next-step card, the Write page and Ctrl K) opens the composer; the composer’s See how your posts did (header, footer and after Mark as posted) opens the dashboard’s Results; each open idea on the Ideas page gets Write a post from this idea.--openopens the dashboard, or the composer when there are no posts yet; an empty database is created when none exists (asinit); Ctrl+C stops both.uiandshare --webalone keep the copyable-command fallback. Catalog:writes,interactive. Docs: docs/DASHBOARD.md. Tests:tests/test_studio.py.share --web --idea ID/--text Tstart the composer draft from an open idea (read-only) or your own text, through the draft store’s allowlisted fields. An unsaved draft is never replaced: the terminal says so and the page offers the text once.- Plain-language help for every readiness code on the dashboard (
REASON_HELP), includinglinkedin_version_unsupported(“LinkedIn API version too old (only for automatic sending)” with the fix) and the approval-ledger codes;tests/test_reason_help.pyenumerates the codeshealthcan emit and fails on one without help. reachweaver next(new everyday command, read-only): “What should I post next?” At most five ranked, concrete steps in plain language, each with one command: safety issues first, drafts waiting (review), posts due for their 7-day numbers (the exactmetrics POST_ID --likes N --replies N --reposts Nline), each open idea by name withshare --web --open --idea ID(the browser composer with that idea as the caption; see Changed), days since you last posted per network, and the top “what works for you” line.--json(schemareachweaver.next.v1). Reads the ideas inbox and an existing databasemode=ro; never creates the database, drafts, approves, schedules or sends. Docs: docs/NEXT-ACTIONS.md. Tests:tests/test_whats_next.py.- “Did you mean” for mistyped input. An unknown option names the closest one of that command (
unrecognized arguments: --platfrom bluesky. Did you mean --platform?, the error and its hint only, without the usage block) and says when a global option such as--dbwas put after the command; an invalid choice (account-add blusky) names the closest choice; an unknown network insharesaysUnknown network 'blusky'. Did you mean bluesky?; common words suggest the real commands (post/write/compose→share,draft;undo→cancel,unapprove;results/stats→report). Tests:tests/test_ux_errors.py. posted LINK --at/--text/--accountagain corrects a post you recorded by hand (storage.correct_manual_publish, UX re-measure 2026-10-21, J6 “I posted yesterday; record it”): “Corrected: posted 2026-10-20 (was 2026-10-21)”, and the 7-day reminder follows the corrected date. Only apublished_manualrecord is corrected: same row, status and empty approval columns unchanged (still never approved, scheduled, claimed or sent), the linkedmark-sharedentry gets the same values, and onemanual_publish_correctedevent records the old and new time and account (never the text). A post ReachWeaver sent (published) keeps its time, text and account; only numbers are added. A future time, or one after numbers already entered, is refused with nothing changed. Before, re-running said “–text, –at and –account were not changed” and there was no way to fix a wrong day. Tests:tests/test_ux3_cli.py.postedasks when you posted it at a terminal without--at(When did you post it? [today] (e.g. yesterday, 2026-10-19), Enter = today, a wrong answer is asked again); a script still gets now and the output saysposted today (2026-10-21) — if not, run again with --at yesterday.reachweaver idea "text"is short foridea add "text"(when the word afterideais not one of its actions);idea addnow ends withSaved. When you're ready: reachweaver next.nextoffers a terminal alternative for each idea:Or in the terminal: reachweaver share --guide --text '<idea>'(keyalternativein--json, additive).share --guide --textshows that caption and asksKeep this caption? [Y = keep / e = edit].- Bare
reachweaverandstartend with an “Everyday” footer (six lines): write (studio --open, orshare --guide), record (posted LINK --likes N), results (report --week), ideas (idea "text"), next (next), with where--helpand--help allare. version --verboseprints the install kind and skill folder;--versionandversionprint onlyreachweaver 0.15.0(--jsonunchanged).
Changed
Section titled “Changed”- The dashboard names a post recorded from its link without text the way the terminal does (“Instagram post of 20 Oct”) instead of “(empty)”; the composer no longer asks for numbers it just kept;
account-addasks each network for its own kind of username and points LinkedIn questions to the online guide;postedrecognises mastodon.social links without a configured Mastodon account;startdescribesworkspace --initcorrectly. - Composer: ideas, posted packages and theme (UX round 4, Playwright under
studioat 1280 and 375 px, synthetic workspace). Write a post from this idea while a saved package is open and unchanged now starts a new post with the idea as the caption in 1 click (“your saved package … is still in Saved packages, unchanged”); before, nothing visible happened (the choice rendered at y≈1202/2656 px). With unsaved changes the choice Use it as my caption / Keep my draft appears at the top of the editor (sticky, scrolled into view, focus on it; 44 px buttons, were 32 px): 2 clicks. Update this package is disabled with a reason whenever a network in the open package is marked as posted, and “Yes, update it” is never offered then (the server’s 409 refusal is unchanged). Preview cards show “Changed, not saved” once the editor differs from the saved package instead of keeping “Posted by you”. The media label and file field are one 44 px+ tap area. The dashboard’s Settings theme reaches the composer through its links (&theme=…in the fragment; the composer keeps it in its own browser storage). New read-onlypackage_unchangedon/api/draft/load(share_composer_store.draft_matches_package); nothing new writes, approves, schedules or sends. Tests:tests/test_composer_ux4.py. - UX round 3 (measured with Playwright in Chrome under
studioon a synthetic workspace, 1280 and 375 px; clicks before → after): compose from the dashboard 1 → 1, weekly results 1 → 1, what next via ideas 2 → 2, compose and copy for the 3 configured networks 9 → 5, mark as posted with the right account and numbers 4 → 3; no horizontal overflow, no console errors, no target under 44 px at 375. Duplicate as new names the new package in its message, adds “ (copy)” to the copy’s name and labels it New copy. Ideas are named by their first words (about 60 characters), never by id, on the page and in the terminal. On phones the composer’s brand bar is sticky with a Results link (understudio) and the tagline wraps instead of being cut off. Dashboard Overview: one write action only (the card’s Or write a new post next to a terminal-only step such as waiting drafts, which stays terminal-only; the top button otherwise; “Also” no longer repeats it); the ideas hint reads “Pick one and write it in the composer.” Skip links (focused), the sidebar’s Write a new post and the composer’s post links on phones are at least 44 px tall. startnow offersreachweaver studio --openfirst (write a post and see how it did, in one browser app), andstudioreplacesuiin the everyday--helplist (uiandshare --webstill open one app each). The composer and dashboard hints for recording a post made by hand now usereachweaver posted LINK --likes N.shareprepares what it can. When some chosen networks are blocked and others are fine, the fine ones are written and each skipped one is listed with its fix (YouTube skipped: add --title "…" and run again with --platform youtube). Exit codes:0all prepared,1some skipped,2blocked (nothing written). An error that belongs to no single network, or every network blocked, still blocks everything; new--strictkeeps the old all-or-nothing behaviour. Docs: docs/EASY-SHARING.md.share --guidetakes a caption of several lines: type at the>prompt and finish with an empty line or Ctrl-D (an empty first line asks again).share --attacherrors say what to do:Attachment not found: nothere.mp4 (looked in /abs/folder). Check the name or leave it out.(exit 2), with separate plain messages for a folder and a symbolic link.connectbefore any account exists is a status, not an error:No accounts yet, so there is nothing to connect.plus the next steps (account-add bluesky, the other networks,share --guidefor posting by hand) and exit 0 (--json:"accounts": []). In a terminal it asksAdd one now? Which network?and runs the sameaccount-addflow in-process (public details only, same checks and[Y/n]);connect --guidethen continues with that account’s steps. A broken accounts file still stops. The guide’s “More detail” and failure hints link the online docs (https://github.com/MSKazemi/reachweaver/blob/main/docs/...) instead of adocs/path that a workspace folder does not have, and its “Next” draft line uses--textinstead of the repository’sexamples/file. The hidden-inputread -r -s -pcredential lines are unchanged.account-addasks again on a blank answer in a terminal (with an example; three blanks stop, writing nothing). Without a terminal the message is plain:Bluesky needs your handle (like name.bsky.social). Add --handle name.bsky.social.; those example shapes (andyourname,your_bot,@yourchannel…) are refused like the example file’s placeholders if copied as they are.- The composer and the dashboard suggest the short
reachweaver metrics POST_ID --likes N --replies N(the time defaults to now and the source toentered-by-hand), and the dashboard’s “no accounts” texts point toreachweaver account-addinstead of copying an example file.share --webnow honours the global--accountsoption. - Browser composer (
share --web) is easier to use, especially on phones: title “ReachWeaver — Write a post”; the header shrinks to one line under 820 px so the caption box is visible on first load (375×667: caption top at 372 px, was 783 px); the six static step chips are replaced by a Write → Choose → Preview → Save → Post progress bar that follows the real editor state (aria-current="step") with a “Next:” hint; dark mode byprefers-color-scheme; the dashboard’s colours, font, radius and “RW” mark; a focus ring of 6.1:1 (light) and 8.3:1 (dark) on panels, was 2.6:1; a screen-reader status region for Copied/Saved/Recorded; 44 px targets under 640 px (375 px with one saved package: 0 of 34 smaller, was 15 of 31). Saved packages get a readable display name from the caption and time (inPACKAGE.json; the folder name is unchanged), and the save message reads “Saved:(in state/shares/…)” with a Copy folder path button. “Exported” reads “Ready to post”; technical warnings and errors are reworded in plain language with the same meaning. The header and footer show “See how your posts did: run reachweaver ui” with a Copy button. docs/BROWSER-SHARE-COMPOSER.md. - Composer “Mark as posted” checks the link in the page first (adds a missing
https://, plain error “Paste the full link to your post, starting with https://”), offers an optional account choice from accounts.json for that network, and ends with the next step: the exactreachweaver metrics POST_ID --observed-at TIME --source native-export --likes N --replies Ncommand with a Copy button. - Errors say what to do next. A missing accounts file now reads
Missing config/accounts.json: no accounts yet. Add one: reachweaver account-add bluesky (public details only), or set up a folder: reachweaver workspace --init .(the example file is mentioned only when it sits next to the missing file);connectwith no accounts prints next steps instead (see above). A file named on the command line that cannot be opened givesFile not found: nope.txt (looked in /abs/folder). Check the name, or use --text "..." instead.(or a plain line for a folder or a permission problem) instead of[Errno 2] ..., still exit 2 and stillnot_found/permissionin--jsonerrors.sharewith YouTube and no title saysYouTube needs a video title: add --title "…". The terminal-onlyNext:hints cover these cases too. share --guide:Save these files? [Y/n](Enter saves; saving only writes private local files), a newAttach a photo or video? (path, or Enter to skip)question passed as--attach(a missing path is asked again), and an empty or unknown network answer is asked again with the list instead of stopping.- Caption fitting in
sharecuts at the end of the last sentence that fits when that keeps at least half of what a word cut keeps, else at a word with “…”. A closing link (the last word, or a short last line such asRead more: https://...) is kept and the text before it is shortened. The SHORTENED note names the removed passage (its start and end), every removed link (LINK REMOVED:) and cut hashtags.fit()returnscut_at,kept_closing,removed_textandremoved_links. - Plain-language checklists (
share,manual-export, generic manual packages):Status: Not posted yet. Nothing was sent, uploaded or scheduled.; “Why you post this yourself” saysReachWeaver cannot post to Instagram; you post it yourself in the app.(or that a Bluesky/Mastodon/Telegram/LinkedIn package is copy-only, or that a venue is human-only) before the registry details; a needed photo or video readsInstagram needs a photo or video: attach it in the app. ReachWeaver has not checked the file ...; the last step says to keep the post’s link as the proof the post exists.manual-export.jsonkeepsstatus: manual_export_not_publishedandapi_capability.reasonunchanged; the golden fixtures were regenerated for the wording. The Bluesky/Mastodon/Telegram/LinkedIn checklist’s text-limit line now shows the draft/check rule instead of “limit unknown”. account-addshows the entry as plain lines (Network, handle or other public identity, Account name, Credential prefix) instead of raw JSON, its terminal confirmation is[Y/n](a local write, kept as.bak), and it ends with the exact next command.workspace --initno longer seeds four example accounts.config/accounts.jsonstarts as an empty list; in a terminal it asksWhich networks do you use? (e.g. bluesky,instagram — Enter to skip)and adds one placeholder per named network, then prints theaccount-addcommand for each.--with-exampleskeeps the old behaviour. The Python functionworkspace.init_workspace(root)withoutnetworksstill copies the example file.- Dashboard (
reachweaver ui) for creators who post by hand; still GET-only and read-only. The Overview leads with one “Your next step” card (thestartguide’s first step with a Copy button, or “Write a new post” withshare --web --openwhen nothing is waiting, plus at most three others) instead of three lists of the same drafts; a yellow or red banner appears only for a real problem (emergency stop, uncertain or unfinished sends, anything blocked) and is otherwise one calm line (“Automatic sending isn’t set up — you don’t need it to write or post by hand.”); readiness reasons, accounts, the folder check and “Sends that failed” (was “Dead letters”) are folded into “Setup and safety details”. Results gains “This week / 30 days / All” (?since=7d|30d|all), a summary line of recorded exact values and the top three posts, and sits in the phone’s bottom bar (Schedule moves under More when nothing is scheduled). Search lists a post you recorded withmark-shared --urlonce, with the time you posted it. Plain language throughout (“posted by you”, “Not connected (only needed for automatic sending)”, timeline events as sentences, the post’s first words as its heading, handles as typed); a post you posted yourself belongs to Posted and is not offered “Voice-check and tighten this draft”. New “Write a new post” page. Phone fixes: no page wider than a 375 px screen (long labels in owner cards made two pages 62 to 92 px too wide), 44 px touch targets, 44 x 44 menu button; card titles are headings, Esc in Ctrl K returns focus, example dates are computed in the browser. Brand tokens (ui_assets.BRAND,--rw-*CSS properties) for other local pages to share. Newtests/test_ui_narrow.pychecks every page at 375 and 390 px in headless Chrome when one is installed. metricsdefaults--observed-atto now and--sourcetoentered-by-hand(you typed the numbers from the platform’s own insights; never presented as an API or export source). Explicit values work as before. It then prints what was stored and, for a post younger than 6 days, when to record again for the 7-day comparison.reportwithout--format: text at a terminal, JSON when piped or redirected (unchanged for scripts).mark-shared --urlprints one id, the measurable post id, with its exactmetricsline; without--urlit adds “Not counted in reports. Add –url to measure it.”insightsand the report say plainly when results exist but none at the matched age (“You recorded results N hours after posting; insights compares results about 7 days after posting. Record again around DATE or use –age-hours N”; JSONcohorts[].results_at_other_ages), and a cohort without an account is “posted by you (no account)” instead of “account unknown”.- Bare
suggestprints the same view asnext(its--jsonkeeps the suggestions schema, counts only);suggest --include-dbnow includes the open-ideas signal, which points atnext. - Recording a post made by hand is easy to find.
--helpeveryday list:postedreplacescheck(still 16 commands;reviewalready shows each draft’s checks before you decide, andcheckstays in--help all). An emptyreport(also--week), an emptynext, an emptylistat a terminal and the missing-database note say “Posted something yourself? Record it from its link: reachweaver posted LINK –likes N”;startshows it once anything was posted (and in the by-hand path without an accounts file);shareends with “After you post, record it: reachweaver posted LINK –likes N” and OPEN-FIRST.md says the same (was a pointer tomark-shared). - Bare
metrics(no post id) explains instead ofthe following arguments are required: post_id: give a by-hand post’s link toreachweaver posted LINK --likes N, or find an id withreachweaver list. Nothing is created. - Reports name a post recorded without an account “posted by you (no account)” (was “(no account recorded)”); the terminal
reportshows a configured account by its public@handle(example placeholders excluded).listat a terminal shows “—” in the ACCOUNT column for such a post; piped and--plainoutput is unchanged for scripts. --helpeveryday list:nextreplacessuggest(baresuggestnow prints the same view, so the list would show one answer twice;suggeststays in--help all). 132 commands withaccount-removeandposted.next: each open idea’s step is nowreachweaver share --web --open --idea ID(the composer with that idea as the caption; the id, never the text, is in the command) instead ofshare --platform ... --text '...'.- Composer: when exactly one configured account matches a network, Mark as posted preselects it (still changeable; “Not sure / skip” stays); “Your post changed. Preview again” now appears only after a real change since the last preview or save, not after a reload; the chosen networks show as removable chips above the list, and on phones the list flows in the page instead of a small inner scroll box.
- Dashboard Overview: waiting drafts are shown once (the next-step card, plus the count in the All posts bar); the lead line and the extra “posts are waiting” link no longer repeat them.
account-add linkedinwarns (it does not refuse) whenlinkedin_versionis ageing or 12 months old or more, using the same check that makeshealthreportlinkedin_version_unsupported.- Plain words in
share(UX re-measure 2026-10-21, J2/J4/J7): the guide’s YouTube title prompt says(required for YouTube; Enter skips YouTube), asks once more on an empty answer, and a skip readsYouTube skipped (no title). Run reachweaver share --guide again and choose only YouTube to add it.(no flag syntax inside the guide). Media-check lines list only problems found (and sourced advice), elseno problem found, plus one linesome details could not be checked from the file header (that's normal)instead of the checker’s field names (moov_before_mdat,subtitle_formats) andsize unknown, duration unknown; the full list stays inmanual-export.json. Length counters read56 of 2200 characters allowedinstead of56/2200 UTF-16 units, and56 of 5000 bytes allowedwhere the sourced YouTube rule is in bytes. The web composer shows the same media lines. - An unknown option prints only the error and its hint (one line), not the command’s usage block first.
- An empty
listsaysNo posts yet. Write one: reachweaver studio --open (or reachweaver share --guide)(stderr when piped; stdout stays empty for scripts). - A post recorded without text is named by network and day in
reportandnext(Instagram post of 18 Oct; the year is added when it is not this year) instead of a link fragment such asinstagram.com/…/DemoPost123. - The
ideahelp line readsSave a post idea for later: reachweaver idea "text"; list, drop or promote it. shareshows the final text in the terminal after the review: per network a header with its length against that network’s limit in plain words (Instagram (photo post): 72 of 2200 characters allowed,Bluesky: 72 of 300 characters allowed; YouTube’s sourced description rule is in bytes, so72 of 5000 bytes allowed; TikTok’s UTF-16 rule reads as characters and says when an emoji counts as 2) and the text, at most three lines or about 280 characters each with… full text in instagram/caption.txt, 40 lines in all. When every copy is the same it says so once (Same text for all 3: it fits every network, so nothing was changed) instead of implying per-network rewrites; no rewrite is made without a sourced rule (hashtags still never move; Instagram’s existing caption-link note is unchanged).- Terminal UX round 3 fixes (strict re-measure 2026-10-21). (1) A suggested next step repeats the global options you gave (
home.command):--accounts myaccounts.json draft ...now saysAdd one: reachweaver --accounts myaccounts.json account-add bluesky, andaccount-add,connect,start,workspaceand the error hint carry--accounts/--db/--home/--profilethe same way, so following them no longer writesconfig/accounts.jsonand loops (the workspace alternative is left out when you named a file). (2)postedandmetricsaccept--commentsas--replies; “Did you mean” tries the apps’ words first (--comments→--replies,--shares/--retweets/--boosts→--reposts,--impressions→--viewswhere the command has it) before spelling (wasDid you mean --account?). (3)share --attach: findings about the file itself, findings every chosen network shares word for word and the header-check note print once underAttached media:before the networks, not once per network (each CHECKLIST.md keeps them). (4) Plain words:Check what will be created:(wasReview the handoff plan:),Copy and post it yourself (text)(wasMANUAL COPY; format text),Prepared 1 private package to copy from(was1 private manual packages),account-addends withAfter that, write your first post: reachweaver draft --account ID --text '...'(wasThen draft and review as usual.),connectwith no accounts saysreachweaver account-add mastodon (or telegram, linkedin). (5) The terminalreportdrops post ids from the top-posts list and saysRecord numbers again around DATE to compare after 7 days: reachweaver posted LINK --likes N(or themetricsform for posts ReachWeaver sent) instead ofinsights --age-hours. (6)showon a post made by hand printsPosted by you on DATE · LINK, its text or(text not recorded — add it with reachweaver posted LINK --text "..."), its latest numbers with aposted LINKline to update them, and no length meter or approval section (--plain/piped JSON unchanged). (7)draftat a terminal addsNext: reachweaver review (go through your drafts) or reachweaver show ID(scripts keep the one line). (8) Wording only, credential handling unchanged:connect --guidesaysin your own terminal window (not inside an AI chat)and that the variables last only until that window closes (with the ACCOUNT-ONBOARDING.md link);account-addsaysSet these yourself with reachweaver connect --guide (it shows the exact lines); theread -r -slines are byte-identical.
