Skip to content

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 as 2026-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 a window object (since, until, basis) only when --since is given, Markdown a “Window:” line; CSV columns are unchanged. An unreadable value is refused with the accepted forms before the database is opened. --since adds no write. Tests: tests/test_report_since.py.
  • reachweaver help [all|COMMAND]: the same text as --help, --help all and COMMAND --help. Read-only and offline; tagged read_only in the catalog.
  • describe --json marks the everyday commands with a boolean everyday on every command entry (additive; schema_version stays 1). Every command is still listed.
  • Registry freshness: no command silently relies on a stale platform fact. New reachweaver/freshness.py applies one age policy to every dated fact in the five bundled research registries (capabilities, distribution, discovery, profile-audit, sign-up): fresh up to 60 days, aging after 60, stale after 120 (the capability registry’s existing threshold), undated when no checked date is recorded; a date is never inferred. New read-only command reachweaver 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. health prints a one-line summary, adds global.registry_freshness, a per-account research_freshness and the attention reasons research_facts_stale (a configured account’s platform has a stale fact outside the capability registry, which keeps registry_entry_stale) and research_registry_invalid; neither changes the exit code. doctor prints the same line and carries registry_freshness in --json. freshness.warning_line() gives context/start a 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 (default interactions = likes + replies + reposts, the same matched-age snapshot rule as baseline-eval). Each group reports its median and count against the rest; fewer than 5 posts on either side is too little data, anything else is an observation, never a cause. Up to three “try more of / try less of” lines per account are phrased as hypotheses to test with experiment-preregister/experiment-readout; groups made of mostly the same posts are folded into one line. Filters --account, --platform, --since 30d|DATE; --json has a stable schema (reachweaver.insights version 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 blocks OAI-SearchBot, GPTBot, ChatGPT-User, PerplexityBot, Perplexity-User, Googlebot, Google-Extended and Bingbot, 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 checks noindex, nosnippet and max-snippet (meta tags and, online, X-Robots-Tag), Bing noarchive/nocache, title and description, rel=canonical, JSON-LD (whether it parses, and its @type values) and <meta name="fediverse:creator">. /llms.txt is 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). --online fetches only the canonical_url pages of your SEO briefs, their robots.txt and /llms.txt, through the landing-check guard (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_registry enforces this, and it also keeps several facts fixed: citation_guarantee must be false; the search, training and user-fetch roles stay separate; Google-Extended must cite that it does not affect Google Search inclusion; user-fetch agents are never marked as obeying robots.txt; and llms_txt must stay optional_unconfirmed with affects_ranking: false. Bing’s help pages need JavaScript and could not be read with curl, so for Bingbot the registry cites Bing’s blog only and does not state the effect of a block on each Bing surface.
  • profile-audit gains a google_search entry 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 labelled official (new optional check_sources in the registry, validated on load and shown in the checklist), and the report adds an eligibility alert. 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.RobotsCache keeps each robots.txt it reads in documents, so ai-visibility reuses 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_required or unknown), what to tick in the platform’s own composer, the API field ReachWeaver already knows (YouTube status.containsSyntheticMedia, TikTok post_info.is_aigc), whether the platform reads C2PA Content Credentials, the stated consequence and the cited page. --eu adds 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 in china.py. X stays unknown: 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 by ai_labels.validate_registry. Shipped in the wheel and the skill bundle.
  • Media manifests take an optional realistic_synthetic: true|false per asset. Leaving it out changes nothing; a non-boolean value is an error and true adds a warning pointing at ai-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, Mastodon rel="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 --setup file (examples/social-web-setup.example.json); --json uses schema reachweaver.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 by social_web.validate_registry and tests/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.
  • start and context now surface what you learned and what may be out of date. When your own recorded results show a clear pattern, start adds one “What works for you: …” step from insights (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 one WARNING: line under the summary pointing to reachweaver registry-age. context --json gains a warnings list (additive; schema_version stays 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 new health reason codes in plain language.
  • start, bare reachweaver and context are handier for a first-time creator. The browser composer (share --web --open) now comes first as the easiest path, then share --guide. In a folder that is not a workspace and has no accounts file, the next setup step is reachweaver 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 suggests workspace --init on that workspace. Accounts that still carry the example values copied by workspace --init (example.bsky.social, examplePersonId and the others in config/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 suggested draft command. Waiting drafts point to the guided, owner-run reachweaver review (unchanged) instead of list/show/check. Open ideas get an idea list --status open step and recorded metric snapshots a report --since 30d --format markdown step. New reusable accounts.placeholder_fields / placeholder_accounts (and PLACEHOLDER_VALUES, kept equal to every bundled example file by a test) and storage.metric_snapshot_count. context --json keeps its schema (schema_version 1): each accounts.items[] entry gains a placeholder boolean and nothing is renamed or removed. Everything stays read-only: the database is opened mode=ro and never created. Tests: tests/test_start.py, tests/test_agent_interface.py.
  • suggest with no input flag no longer fails. It reads an existing local database query-only, exactly as --include-db does (a missing one is skipped, never created), plus the count of open ideas in the ideas inbox (a new open_ideas P3 item; counts only, never the idea text). With nothing to rank it prints next steps (share --web --open, idea add, start) and exits 0; --json adds a next_steps list in that case. Every explicit input flag behaves as before, including the refusal of --include-db without a database. Tests: tests/test_suggest.py.
  • reachweaver --help is 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 to reachweaver --help all, which prints the full grouped list and the global options as before. reachweaver --help COMMAND prints that command’s own help. reachweaver COMMAND --help is unchanged, every command is still callable, and no behaviour of any command changed. Scripts that read the whole command list from reachweaver --help should use reachweaver --help all or reachweaver describe --json.
  • The “unknown command” hint and the pointer printed by bare reachweaver now name reachweaver --help all for the full list.
  • distribution-plan, account-advisor and discovery-plan now show when each platform fact they present was last checked: JSON gains checked_on, age_days, freshness and freshness_label per channel, recommendation and guidance source (plus freshness_as_of/freshness_policy, and distribution_entry in discovery-plan); text prints checked YYYY-MM-DD and aging - re-verify or stale - re-verify when it applies. All keys are additive. discovery-plan measures age at the input’s as_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 as undated.
  • baseline_eval.matched_snapshot is the shared nearest-age snapshot helper (baseline-eval now 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.