Skip to content

v0.3.0

Choose a tag to compare

@NetDevAutomate NetDevAutomate released this 20 Sep 08:21
· 682 commits to main since this release

v0.3.0

The provider-aware second-brain launcher: the web app's Today panel can now
take you to your second brain — one honest action, one explicit click,
nothing automatic. Under it sits one launch-policy owner, one atomic
configuration-mutation owner, and release evidence that exercises the launcher
from the installed wheel rather than the source checkout.

StudyLoop 0.3.0 follows the documented source-checkout installation flow. CI
builds and installs wheel/sdist artifacts as validation evidence; this release
does not advertise GitHub or PyPI binary distribution.

Changes

  • Today launches your second brain. A read-only
    GET /api/second-brain/launch-target route (never cached) reports the
    selected provider's honest launch state; the Today panel renders at most one
    launcher action from prefetched state and navigates only inside the click
    handler. xTiles opens once in a new noopener,noreferrer tab; Obsidian
    hands the current tab to the obsidian:// link without leaving an empty tab
    behind. Nothing navigates during page load, refresh, publication or
    wind-down, and no server module launches, redirects, or contacts a provider.
  • Obsidian is same-device honest. The action is enabled only when the
    browser runs on the device running StudyLoop, decided from the direct
    request peer — behind a reverse proxy it stays safely disabled with the
    reason. An enabled click opens <vault>/<folder>/Today.md when that note
    exists inside the vault, falling back to the vault root.
  • The assistant destination handoff. studyloop brain destination set --provider xtiles --url URL retains a reviewed, connector-returned page URL
    without changing provider consent; destination clear removes it. The
    validator accepts HTTPS on exactly xtiles.app/app.xtiles.app with a real
    page path and nothing else — no userinfo, port, query, or fragment, Unicode
    and IDNA lookalikes rejected — and a rejected value is reported by reason
    only, never echoed. Only the host is ever shown; Settings never displays the
    full retained URL.
  • One atomic configuration writer. mutate_raw_config() is now the only
    read-modify-write seam: exclusive sibling lock, reread after locking,
    whole-config validation, synced 0600 temporary sibling, atomic replace
    preserving the destination's mode. brain enable and both destination
    commands share it, so concurrent StudyLoop writers cannot silently lose each
    other's update.
  • Settings explains, never launches. One card per provider — active for
    the selected provider, muted otherwise — carrying the launch API's own
    reason as guidance, or the CLI command that would select a muted provider.
    No web form writes configuration.
  • Installed-wheel launcher evidence. just smoke-web (wired into
    just release-check) builds the wheel, installs studyloop[web] into an
    isolated environment outside the checkout, asserts the installed package
    does not import from the checkout, starts the installed application,
    requests the launch-target route, and loads every launcher asset reachable
    from main.js's import graph.
  • Session memory became an installer/doctor invariant across all five
    harnesses, topic exercises moved behind an explicit --dev preview flag,
    and release validation now runs without the three warning classes found
    during the 0.3.0 readiness pass (see CHANGELOG for detail).

Verification

  • just preflight — 4882 passed, 4 skipped (ruff clean, Pyright 0 errors,
    JS 105/105, docs build strict, release consistency and spec validation pass)
  • just e2e — 515 passed, 20 skipped
  • just smoke-web — 3 passed (installed-wheel launcher smoke: isolated venv
    outside the checkout, launch-target route, full launcher asset graph)
  • just smoke-installed, just smoke-extras (9 passed), just shellcheck,
    just audit, just audit-full — all pass

Connector-shape evidence (redacted)

A live page URL returned by the authenticated xTiles MCP connector on
2026-09-05 was checked against the strict destination validator. The URL
itself is deliberately not recorded here — only its shape:

  • scheme https, host exactly xtiles.app, default port
  • no userinfo, no query, no fragment, ASCII-only, well under 2,048 characters
  • path is a single opaque page-id segment (non-home)

resolve_second_brain() accepted that exact value unchanged (provider
selection untouched), and rejected the same value with a query appended
and with a fragment appended, each with a reason-only error that does not echo
the value — confirming the strict validator matches what the connector really
returns, with no contract revision needed.

Tag status

v0.3.0 is cut at the release commit 34f06d70 (2026-09-06, the commit that bumped the
version and added this note). The tag was created on 2026-09-14 during the congruence
review, once the release gate had learned to run before a tag exists; the CHANGELOG heading
carries the tag's commit date.