ReachWeaver 0.14.0 release notes
Released on 2026-10-21.
Handier, smarter and aware of newer distribution paradigms. A short everyday --help, a first run that starts in the browser composer, report --since, and a suggest that works with no flags. insights learns what works from your own results. Every platform fact shows how old it is. ai-visibility checks what your own pages tell AI answer engines, ai-label-check gives per-platform AI-content label rules, and social-web-plan maps your reach across the fediverse, Bluesky and bridges. 125 commands (6 more than 0.13.0, none removed). Everything new is read-only or advisory; no live adapter is added.
report --since WHEN.24h,7d,30d(hours or days, up to 3650 days), a date such as2026-10-01(midnight UTC) or an ISO 8601 time with a timezone. The report then covers only posts whose send started in the window and, for each, the latest snapshot observed in it (a post with only older snapshots counts as unknown, never 0); replies are filtered the same way. JSON gains awindowobject (since,until,basis) only when--sinceis given, Markdown a “Window:” line; CSV columns are unchanged. An unreadable value is refused with the accepted forms before the database is opened.--sinceadds no write. Tests:tests/test_report_since.py.reachweaver help [all|COMMAND]: the same text as--help,--help allandCOMMAND --help. Read-only and offline; taggedread_onlyin the catalog.describe --jsonmarks the everyday commands with a booleaneverydayon every command entry (additive;schema_versionstays 1). Every command is still listed.- Registry freshness: no command silently relies on a stale platform fact. New
reachweaver/freshness.pyapplies one age policy to every dated fact in the five bundled research registries (capabilities, distribution, discovery, profile-audit, sign-up):freshup to 60 days,agingafter 60,staleafter 120 (the capability registry’s existing threshold),undatedwhen no checked date is recorded; a date is never inferred. New read-only commandreachweaver registry-age [--registry NAME] [--platform P] [--all] [--as-of YYYY-MM-DD] [--json]lists the aging, stale and undated facts with their source, the counts per registry and the oldest checked date per platform; it reads only the bundled files, never creates the database and always exits 0.healthprints a one-line summary, addsglobal.registry_freshness, a per-accountresearch_freshnessand theattentionreasonsresearch_facts_stale(a configured account’s platform has a stale fact outside the capability registry, which keepsregistry_entry_stale) andresearch_registry_invalid; neither changes the exit code.doctorprints the same line and carriesregistry_freshnessin--json.freshness.warning_line()givescontext/starta one-line warning to call later. Docs: PLATFORMS.md#registry-freshness. insights: “What works for you” (read-only, offline). Compares your own published posts, per account, by time of day, weekday, weekday/weekend, text length, link, format (text/image/video), hashtag count, opening hook (question/number/statement) and each hashtag, using the result recorded about 7 days after posting (defaultinteractions= likes + replies + reposts, the same matched-age snapshot rule asbaseline-eval). Each group reports its median and count against the rest; fewer than 5 posts on either side istoo little data, anything else is anobservation, never a cause. Up to three “try more of / try less of” lines per account are phrased as hypotheses to test withexperiment-preregister/experiment-readout; groups made of mostly the same posts are folded into one line. Filters--account,--platform,--since 30d|DATE;--jsonhas a stable schema (reachweaver.insightsversion 1, see docs/INSIGHTS.md). With too little data, or no database yet, it exits 0 and explains how to record results (metrics-fetch,import-metrics,metrics). It opens the database read-only, never creates or migrates it and has no network or send path. The dashboard’s Results page shows the same lines under “What works for you”. Tests:tests/test_insights.py(synthetic data only).ai-visibility: what your own pages ask AI answer engines and search crawlers to do. New read-only command. For each page it reports whether robots.txt allows or blocksOAI-SearchBot,GPTBot,ChatGPT-User,PerplexityBot,Perplexity-User,Googlebot,Google-ExtendedandBingbot, and whether the file names the crawler or only reaches it through*. The matcher follows RFC 9309. Each crawler is shown with its role (search, training, or user-initiated fetch) and the operator’s own words on what a block means. A blocked search crawler is a warning; a blocked training crawler or user-fetch agent is information. The report also checksnoindex,nosnippetandmax-snippet(meta tags and, online,X-Robots-Tag), Bingnoarchive/nocache, title and description,rel=canonical, JSON-LD (whether it parses, and its@typevalues) and<meta name="fediverse:creator">./llms.txtis reported as information only and labelled “optional; no major engine has confirmed it reads it”; Google says Search does not use such files. Offline (the default), it reads a saved page and robots.txt (--url URL --html F --robots F, or--briefs F --page-id ID).--onlinefetches only thecanonical_urlpages of your SEO briefs, their robots.txt and/llms.txt, through thelanding-checkguard (robots.txt honoured, redirects inspected, size caps, IPv4 first). No database, and nothing is drafted or sent. The report lists the operators’ measurement tools (Search Console Generative AI performance report, Search Console platform properties, Bing Webmaster Tools AI Performance), and it quotes Google: meeting every requirement does not mean a page will be crawled, indexed or served. Guide: docs/AI-SEARCH-VISIBILITY.md.- Sourced AI-search registry
reachweaver/ai_search_registry.json(packaged and mirrored into the skill). Every crawler, page signal and measurement entry has an official URL, a verbatim quote and the checked date 2026-10-21.ai_visibility.validate_registryenforces this, and it also keeps several facts fixed:citation_guaranteemust befalse; the search, training and user-fetch roles stay separate;Google-Extendedmust cite that it does not affect Google Search inclusion; user-fetch agents are never marked as obeying robots.txt; andllms_txtmust stayoptional_unconfirmedwithaffects_ranking: false. Bing’s help pages need JavaScript and could not be read withcurl, so forBingbotthe registry cites Bing’s blog only and does not state the effect of a block on each Bing surface. profile-auditgains agoogle_searchentry with two checks: “Claim your Google Search profile (only where eligible)” (search_profile_claimed) and “Check Search Console platform properties for your TikTok, Instagram, X or YouTube accounts” (search_console_platform_properties). Each check carries official sources labelledofficial(new optionalcheck_sourcesin the registry, validated on load and shown in the checklist), and the report adds aneligibilityalert. Google’s help lists Search profiles as available in Canada, India and the United States for people aged 18 or over with 10,000+ followers on YouTube, Instagram, X or TikTok, and Search Console says platform properties are rolling out gradually. Existing registry entries are unchanged.sources.RobotsCachekeeps each robots.txt it reads indocuments, soai-visibilityreuses the same response instead of making a second request. Its verdicts are unchanged. Tests:tests/test_ai_visibility.py(32 offline tests; every online path is mocked).ai-label-check(offline, advisory, read-only): for a draft, variant or campaign file, or a stored post (--post-id, database opened read-only), tells you per target platform whether its AI-generated-content rule asks for a label (required,recommended,not_requiredorunknown), what to tick in the platform’s own composer, the API field ReachWeaver already knows (YouTubestatus.containsSyntheticMedia, TikTokpost_info.is_aigc), whether the platform reads C2PA Content Credentials, the stated consequence and the cited page.--euadds the EU AI Act Article 50 duties for deepfakes and for AI text on matters of public interest, including the human-review exemption (wording from a secondary site, not legal advice; applies from 2 August 2026). Chinese platforms reuse the CAC labelling rule inchina.py. X staysunknown: its policy page could not be read. Never blocks, approves or sends; exits 0 after a check. See docs/AI-CONTENT-LABELS.md.reachweaver/ai_disclosure_registry.json: sourced rules for YouTube, Instagram, Facebook Pages, Threads, TikTok, LinkedIn and X plus the EU AI Act Art. 50 entry, each with URL, exact quote and checked date (2026-10-21), validated byai_labels.validate_registry. Shipped in the wheel and the skill bundle.- Media manifests take an optional
realistic_synthetic: true|falseper asset. Leaving it out changes nothing; a non-boolean value is an error andtrueadds a warning pointing atai-label-check. social-web-plan(new, offline, read-only): the open social web. Maps your accounts onto ActivityPub (Mastodon, Threads with fediverse sharing, Ghost 6, WordPress ActivityPub, Pixelfed, Lemmy, Misskey, PeerTube, Flipboard), the AT Protocol (Bluesky), Nostr, Farcaster, Matrix and diaspora*, and onto the Bridgy Fed bridge. It recommends a canonical home (owned ActivityPub site first; an editorial hypothesis), warns when a bridge or Threads sharing makes the same text reach some people twice, and lists identity steps (fediverse:creator, Mastodonrel="me"links, a domain as your Bluesky handle) and gaps. Input:config/accounts.json(public metadata),--presence,--bridged,--fediverse-sharing,--site/--site-kind, or a--setupfile (examples/social-web-setup.example.json);--jsonuses schemareachweaver.social-web-plan.v1. It never contacts a network, reads a credential, opens the database or touches the send queue. Guide: docs/OPEN-SOCIAL-WEB.md.reachweaver/social_web_registry.json(new, shipped in the wheel and the skill bundle). 14 platforms keyed by distribution registry ids, 6 protocols, the Bridgy Fed bridge, 3 identity checks and 4 site options; every fact quotes an official page fetched 2026-10-21. Unverified points (whether a given Flipboard account is federated, Minds’ default federation, the current Threads beta status) are labelled as such. Validated bysocial_web.validate_registryandtests/test_social_web.py(bridges and Threads federation must stay opt-in).social_web.bridge_duplicate_risk(presences): the duplicate-reach warnings as data for other planning code. Advice only; it is not connected to sending, the send queue or the repeat guard.
Changed
Section titled “Changed”startandcontextnow surface what you learned and what may be out of date. When your own recorded results show a clear pattern,startadds one “What works for you: …” step frominsights(the strongest line only, with its post counts; an observation to test, not a cause), and when bundled platform facts are aging or stale (or a research file fails its checks) it prints oneWARNING:line under the summary pointing toreachweaver registry-age.context --jsongains awarningslist (additive;schema_versionstays 1). The placeholder-account summary is shortened to “N with example placeholders”; the instruction to edit the file appears once, as a step. The dashboard explains the two newhealthreason codes in plain language.start, barereachweaverandcontextare handier for a first-time creator. The browser composer (share --web --open) now comes first as the easiest path, thenshare --guide. In a folder that is not a workspace and has no accounts file, the next setup step isreachweaver workspace --init .;cp config/accounts.example.json ...is suggested only when that file is actually in the folder (a pip install has none), and inside a workspace whose accounts file is missing it suggestsworkspace --initon that workspace. Accounts that still carry the example values copied byworkspace --init(example.bsky.social,examplePersonIdand the others inconfig/accounts.example.json) are no longer counted as configured: the summary and a step say “N account(s) still use example placeholders — edit config/accounts.json”, and a placeholder account is never used in the suggesteddraftcommand. Waiting drafts point to the guided, owner-runreachweaver review(unchanged) instead oflist/show/check. Open ideas get anidea list --status openstep and recorded metric snapshots areport --since 30d --format markdownstep. New reusableaccounts.placeholder_fields/placeholder_accounts(andPLACEHOLDER_VALUES, kept equal to every bundled example file by a test) andstorage.metric_snapshot_count.context --jsonkeeps its schema (schema_version1): eachaccounts.items[]entry gains aplaceholderboolean and nothing is renamed or removed. Everything stays read-only: the database is openedmode=roand never created. Tests:tests/test_start.py,tests/test_agent_interface.py.suggestwith no input flag no longer fails. It reads an existing local database query-only, exactly as--include-dbdoes (a missing one is skipped, never created), plus the count of open ideas in the ideas inbox (a newopen_ideasP3 item; counts only, never the idea text). With nothing to rank it prints next steps (share --web --open,idea add,start) and exits 0;--jsonadds anext_stepslist in that case. Every explicit input flag behaves as before, including the refusal of--include-dbwithout a database. Tests:tests/test_suggest.py.reachweaver --helpis now short. It lists 16 everyday commands (start, share, idea, draft, check, review, publish, list, report, metrics-fetch, suggest, ui, connect, workspace, update, help) with one plain-language line each, then points toreachweaver --help all, which prints the full grouped list and the global options as before.reachweaver --help COMMANDprints that command’s own help.reachweaver COMMAND --helpis unchanged, every command is still callable, and no behaviour of any command changed. Scripts that read the whole command list fromreachweaver --helpshould usereachweaver --help allorreachweaver describe --json.- The “unknown command” hint and the pointer printed by bare
reachweavernow namereachweaver --help allfor the full list. distribution-plan,account-advisoranddiscovery-plannow show when each platform fact they present was last checked: JSON gainschecked_on,age_days,freshnessandfreshness_labelper channel, recommendation and guidance source (plusfreshness_as_of/freshness_policy, anddistribution_entryindiscovery-plan); text printschecked YYYY-MM-DDandaging - re-verifyorstale - re-verifywhen it applies. All keys are additive.discovery-planmeasures age at the input’sas_of.- Registry date tests no longer pin exact dates: a checked date must be a real date no earlier than the research batch that added it, no later than its snapshot and not in the future (
tests/freshness_support.py), so re-verifying a fact does not break a test. The eight profile-audit entries without an official source (Discord, Indie Hackers, Peerlist, Bilibili, Zhihu, OSCHINA, Snapchat, WhatsApp) stay undated and are reported asundated. baseline_eval.matched_snapshotis the shared nearest-age snapshot helper (baseline-evalnow calls it through_matched_rate; output unchanged).
No change to approval, dry-run, emergency-stop, credential isolation, the send queue or ambiguous-send reconciliation, and no database schema change.
