Skip to content

ReachWeaver 0.5.0 release notes

Released on 2026-10-16.

Everything that is yours in one folder, and a readable record of what you posted: a workspace folder you can copy to another computer (workspace, media-relink, a global --home), a posting journal and archive (journal, archive), and the read-only local dashboard with friendlier terminal output (ui, start, completion). 7 new commands (92 in all, none removed). A minor version because it adds commands and a global option.

Upgrade notes (behaviour you may notice).

  1. Nothing changes until you opt in to a workspace. The new .reachweaver-workspace marker file is what makes a folder a workspace; without it every default path stays relative to the folder you run from, exactly as before. To adopt a folder that already has config/ and state/, run reachweaver workspace --init . inside it: it only adds the marker and missing sub-folders and never overwrites or moves anything.
  2. An explicit --db / --accounts, or a REACHWEAVER_DB / REACHWEAVER_ACCOUNTS setting, still wins over a workspace.
  3. After copying a workspace to another computer run reachweaver workspace --repair --apply so attachments recorded by absolute path are found again in media/. Credentials are never stored in the folder and must be set again.
  4. Nothing is archived automatically at send time. archive --copy-files is something you run; changing the send path needs its own security review.
  • One folder for everything that is yours (owner request, 2026-10-16). workspace --init [DIR] creates a single workspace folder (config/, state/ with the database, approval ledger and archive, media/, logs/, a .reachweaver-workspace marker, a README and a secrets.env.example of variable names only) and never overwrites or moves existing files, so an existing config/ + state/ folder is adopted in place. Commands run from inside the folder, from any sub-folder, or with the new global --home DIR use it automatically (reachweaver/home.py resolves the default paths for the database, accounts, opt-out list, caps and retention policy; an explicit flag or REACHWEAVER_* setting still wins, and a folder without the marker behaves exactly as before). workspace --gather [--apply] copies attachments of unsent posts into media/ (hash-verified), and after copying the folder to another computer workspace --repair [--apply] re-finds them in media/ by size and SHA-256 and fixes the recorded paths, so approved posts stay approved. The report also warns about a secrets file sitting in the folder. tests/test_workspace_folder.py (14) walks the whole story: copy the folder, delete the original, repair, and the post is still approved.

  • workspace and media-relink: moving your data to another computer (owner question, 2026-10-16). Your data was already separate from the program: config/ (account metadata, never a secret) and state/ (the database, the approval ledger next to it, the archive), with credentials only in the environment. workspace (read-only, exit 1 when a copy would not work) now says so concretely: where each file is, database integrity, whether the approval ledger still matches the database, a -journal/-wal file meaning a run is in progress, credential variable NAMES missing on this computer, and which recorded attachment files are missing or changed (attachments are stored by absolute path and SHA-256, so unsent posts need them at the recorded path). media-relink --from OLD --to NEW [--apply] repairs that after a move: dry run by default, only posts that are not sent and not in flight, a path is written only after the file at the new location is read and matches the recorded SHA-256, and storage.rewrite_attachment_paths proves in one transaction that the approval hash is unchanged (it rolls back otherwise), so relinked posts stay approved. New accounts.accounts_path() exposes the existing default resolution. See docs/MOVING.md. tests/test_workspace.py (19), including a real copy of a workspace to another folder.

  • journal and archive: a readable record of what was posted (owner request, 2026-10-16). journal is read-only and lists every post that went out or may have (published, sending, needs_review; --all-statuses adds the rest) together with material recorded by mark-shared: the exact text, UTC time, platform and account, status, approver and approval time, the first 12 characters of the approval hash, the link the platform returned, an audit timeline of fixed action codes (the free-text event detail, which can hold provider text, is never shown), and each image and video with path, SHA-256, size, type and whether the file is still on disk (--verify-files also re-hashes it). Filters: --post-id, --platform, --account, --since, --until, --limit; formats: table, markdown, csv (spreadsheet formulas neutralised) and json; --out FILE writes a new owner-only file. archive writes a private folder (0700/0600, state/archive/ next to the database by default): one sub-folder per post with post.txt (the exact text), meta.json and, with --copy-files, copies that are made only if the file still matches the SHA-256 recorded when it was attached, plus index.md and index.csv. It only ever adds, never overwrites a post folder, and refuses a folder that is not an archive. Neither command sends, schedules, approves or contacts anything, and nothing is archived automatically at send time (that would change the send path and needs its own security review). See docs/JOURNAL.md. tests/test_journal.py (18).

  • Read-only local dashboard reachweaver ui, plus friendlier terminal output (experimental). ui serves overview/readiness, a queue with needs_review first, per-post review sheets (exact text, offline platform preview, approval binding, timeline, copyable next-step commands), accounts (names of missing credential variables only) and the offline channel research, on 127.0.0.1 with a per-run token, loopback Host/Origin checks, GET-only routes, a strict CSP and a database opened mode=ro that is never created. The Overview carries a “What to do next” card (same guidance as start, via /api/next), the tab title shows the needs-review count, the Queue has status chips, an account menu, search and empty states, and the header has a light/dark/auto theme switch and an opt-in Auto-refresh (preferences in localStorage, wrapped in try/catch). It cannot approve, schedule, pause, publish or accept credentials. New modules post_view.py (the show assembly moved out of cli.py, behaviour unchanged), ui_data.py, ui_server.py, ui_assets.py. The review sheet and the Post page also show the repeat-guard result of show. start prints the exact next command for your current state (read-only; --json). --help lists commands grouped by task (cli_help.py), schedule/unapprove/cancel gained help text, list prints an aligned coloured table and check colours its verdict only on a terminal (term.py; piped output is byte-identical; new global --plain turns it off), and common errors add a one-line “Next:” hint at a terminal. term.py reads no environment variable, so NO_COLOR is not honoured (the environment-read allow-list is a credential-isolation control). The Post page has a plain-language status card, a length meter against the platform’s own limit, Copy text, previous/next links, relative times and collapsible detail sections; the page has keyboard shortcuts (? lists them) and tables become stacked cards under 640 px. The dashboard shows the stored post text as stored (not redacted) and flags text that looks like a secret. At a terminal, show prints a readable review sheet (JSON when piped or with --plain), the list id column is never shortened, a mistyped command gets a “Did you mean” suggestion, and completion bash|zsh prints a Tab-completion script. An independent review of the first version drove fixes to redaction of the exact text, the skip link, auto-refresh behaviour, /<token> without a slash, 500s for client errors, a malformed request line, idle connections, start on a broken accounts file and control characters in list. Tests: tests/test_ui_data.py, test_ui_server.py, test_start.py, test_term.py, test_cli_help.py, test_show_view.py, test_completion.py. Verified by offline tests and in desktop Chrome (light and dark, shortcuts, and a 400 px-wide frame for the narrow layout); not tried on a real phone or other browsers. See docs/DASHBOARD.md.