Skip to content

Releases: patl4588/railcall-core

Station v0.27 — headless CLI auth (API keys in the terminal)

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 25 Jul 01:21

RailCall Station v0.27 — headless CLI auth (API keys in the terminal)

Status: cut. Small, focused release on top of v0.26.

v0.26 shipped the marketplace-side API-key surface (create/list/revoke +
BearerAuthGuard on listings.publish). This release closes the loop
by making those keys usable from the CLI without opening a browser —
the actual CI/CD story customers care about.

What's new (CLI-side)

1. railcall market api-keys subcommand. Three verbs, all direct
mappings of the web-UI surface at /marketplace/settings/api-keys:

railcall market api-keys list
railcall market api-keys create <name> [scopes]
railcall market api-keys revoke <id>

Fresh secret prints ONCE to stdout on create (matches the web UI's
one-shot banner). Standard panel() output; scriptable if a caller
wants to grep the rc_ak_live_… line out of stdout.

2. RAILCALL_API_KEY environment variable. Every marketplace-authed
command now checks the env var first and falls back to the interactive
session (railcall market login) only when it's unset. Precedence is
deliberate: if the key is set but rejected, we DON'T silently downgrade
to the session — that would mask credential misconfigs in CI/CD (worst
class of debugging).

Typical CI/CD flow:

export RAILCALL_API_KEY=$(op read op://vault/railcall/api_key)  # 1Password
railcall market publish path/to/module.json                     # signed publish

Zero shell state. No cookies, no session files, no browser.

3. api-keys management endpoints refuse API-key auth. Deliberate
guard against the lateral privilege loop: an API key can't mint or
revoke other API keys. If the CLI detects RAILCALL_API_KEY is set
during an api-keys subcommand, it prints an actionable message
pointing the user at railcall market login OR the web UI, instead of
firing the request and returning a confusing 401.

Also in v0.27 (marketplace + website side, deployed already)

Everything in the "Post-cut additions" section of the v0.26 release
notes remains live and untouched. Nothing on the marketplace side
requires a station re-download to work — the CLI just talks to the
production API. Recap:

  • Session invalidation on member removal / role demotion
  • Admin audit log (OrgAuditLog + /org/audit + /marketplace/org/audit viewer)
  • Vault admin UI + SCIM group-map UI
  • /trust/subprocessors page + SOC 2 status
  • POST /auth/api-keys + BearerAuthGuard wired into listings.publish
  • GET /org/export (GDPR Art. 20)
  • /status live-probe page

Verify

sha256_of_railcall_station.tar.gz  = c519d6b1085fb8e20d9c100baf85754200363d7dc34d46a79105ad5c9d8afa2d
sha256_of_railcall_cli.py          = 1ea60913e9ba5a9ceb8798aa01ac33ac01e3b80eeea2c998a596333070536f1f
sha256_of_railcall_vault_drivers.py = 7ff6896532adcbcf8302039bafe403884f457d8fb2ed87320e8283c61f9df096

Every other file pin (governance package, signer, companion daemon,
vault_io) is unchanged since v0.26 — cross-verified before the cut.

Deferred to v0.28+

  • railcall audit view — CLI wrapper around GET /org/audit so
    admins can grep the audit log from the terminal.
  • railcall org export — CLI wrapper around GET /org/export.
  • Studio session picking up the org identity from the JWT / API key
    (today the Studio side reads ~/.railcall/marketplace_session.json
    directly; API-key-only setups need a small refactor).

Station v0.26 — enterprise readiness (SSO + RBAC + SCIM + configurable vault)

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 25 Jul 00:34

RailCall Station v0.26 — enterprise readiness (SSO + RBAC + SCIM + configurable receipt vault)

Status: cut. Tarball built, install.sh pinned, GitHub release published.

The most significant single release since v0.22 (marketplace/modules launch). v0.25 was the last "solo-user" cut; v0.26 is the first release where a team-sized customer can honestly buy Enterprise:

  • Log in with their identity provider (WorkOS SSO — Okta, Azure AD, Google Workspace, Ping, any SAML/OIDC).
  • Auto-provision + auto-remove users when their HR system flips them (SCIM Directory Sync).
  • Assign roles across their team (owner/admin/publisher/operator/viewer).
  • Publish modules only their team sees (internal-only marketplace visibility).
  • Stream every signed receipt to a shared vault they control (local path, external SSD, NAS mount, USB stick, or an S3-compatible bucket — one config, every seat writes there).

Every existing solo install keeps working unchanged. The vault config is optional, additive, and best-effort — a mirror on top of the local write path that has always been the trust surface. If the vault is unreachable, the local write still happens; the run never fails on a mirror.

What's new

1. WorkOS SSO/marketplace/sso on the storefront + /auth/sso/* on the marketplace API. Enterprise buyer types their work-email domain; browser bounces through their IdP; JIT-provisions User + Membership; mints the same JWT+refresh pair the password flow issues. First user on a fresh WorkOS org auto-lands as owner because they're almost certainly the identity admin who set up SSO in the first place. Degrades cleanly without WORKOS_API_KEY — the SSO routes 503 with an actionable message; every other endpoint keeps working.

2. Multi-seat + RBACOrganization + Membership tables with a five-role ladder (viewer < operator < publisher < admin < owner). Full invitation flow: POST /org/invitations (admin+), invite email with a sha256-hashed token, POST /org/invitations/accept. Last-owner protection prevents the org from becoming ownerless via demote/remove. Frontend: /marketplace/org/members (roster + invite + role dropdown + revoke).

3. SCIM Directory SyncPOST /webhooks/workos signature-verified receiver. Handles dsync.user.created/updated/deleted + dsync.group.user_added/removed. When the customer's IdP flips a user, we mirror it: JIT-create Membership, sync attributes, mark Membership.removed_at on deletion. Group→role mapping via Organization.dir_group_role_map (RailCall staff sets it after the customer creates their IdP groups). Group elevation is additive-only — a manual UI promotion isn't clobbered by an unrelated group event.

4. Internal-only marketplaceListingVisibility enum (public | org_internal) + Listing.owner_org_id. Publisher-role members can publish listings that only members of their org can see + install + purchase. Non-members get 404 (not 403) on both browse and detail so slug enumeration returns nothing.

5. Configurable receipt vaultOrganization.vault_config JSONB + admin surface. Every Studio in the org fetches the config on boot (5-min TTL cache) and mirrors every receipt + audit line to whatever driver the org set. Drivers:

  • local — filesystem path. Covers external SSD, NAS mount, USB stick — the OS mounts, Studio writes.
  • s3 — hand-rolled AWS SigV4 over urllib. Zero deps. Works with AWS S3, MinIO, Cloudflare R2, GCS interop, or any S3-compatible target via endpoint_url. Verified end-to-end against MinIO.
  • network_share — SMB/NFS wrapper. OS mounts; Studio checks mount presence + writes.
  • custom — importlib loader. Customer ships their own driver in ~/.railcall/vault_drivers/; config {driver:"custom", module_ref:"pkg.mod:Cls"} loads it at Studio boot.

Fail-mode is fixed: always fall back to local. Local write happens first (unchanged from v0.25). Vault mirror runs after in a swallowed try/except with stderr logs. Vault failure never breaks a governed run.

Secrets never in the marketplace DB. S3 access keys and custom-driver secrets are configured as references (env:VAR, file:/path, keyring:label) — the Studio-side driver resolves them at runtime. The marketplace explicitly rejects raw *_key/*_secret at the boundary with an actionable error.

Also in v0.26

  • Air-gap install kit (Enterprise plan Week 1) — railcall_station_v0.26_airgap.tar.gz for customers who cannot let outbound traffic reach railcall.ai. Every file listed in MANIFEST.txt with its sha256. Full offline install path.
  • Login unification — the single /signin on railcall.ai now routes to the marketplace login; the CLI's gateway flow lives at /cli-activate. One login story per user.
  • HIPAA trust page/trust/hipaa documents BAA scope, technical controls, receipt-vault architecture. Buyable-tier compliance leave-behind.

Post-cut additions (2026-07-25 same day)

The initial v0.26 cut was extended after Sami's audit turned up
enterprise gaps a CISO would name in a procurement review. All of
these landed the same day, on top of the tagged station tarball —
they're marketplace + storefront side, so they roll out via the
regular deploy chain, not the versioned release.

Session invalidation: User.session_generation bumps on member
removal + role demotion. AuthService.invalidateAllSessions revokes
every refresh token for the target user in the same transaction. Max
window from "you're fired" to "your JWT stops working" = 15 min
(access-TTL grace).

Admin audit log: OrgAuditLog append-only table + write hooks
on every admin mutation surface (invite / role change / member
removal / vault config / SCIM events / org export). Frontend at
/marketplace/org/audit with event-slug filter + keyset pagination.

Vault admin UI: /marketplace/org/vault-config — driver picker
with per-driver form fields. Refuses raw secrets at the input the
same way the API does; only env: / file: / keyring: references
accepted.

SCIM group-map UI: /marketplace/org/dir-role-map — add / edit /
remove (WorkOS group id → OrgRole) rows. Self-serve for the
customer's own admin (the staff endpoint at /admin/orgs/:id/dir-role-map
still exists for support-team bootstrap).

API keys for CI/CD: /marketplace/settings/api-keys — long-lived
tokens with rc_ak_live_ prefix, sha256-hashed in the DB, per-key
scopes, optional expiration, best-effort last_used_at. Wired into
listings.publish (headless CI can publish modules); other endpoints
can adopt BearerAuthGuard when needed.

Data export: GET /org/export — GDPR Art. 20 / CCPA "right to
access" dump of everything the marketplace stores about the org.
Owner-only. Recorded in the audit log itself.

Subprocessor list: /trust/subprocessors — public per-vendor
cards (Render / WorkOS / Stripe / Resend / GitHub / Cloudflare) with
data categories, jurisdiction, notes. Includes vendor-management
policy summary + 30-day new-vendor notification commitment.

Status page: /status — live client-side probes of railcall.ai

  • marketplace API, auto-refresh every 30s.

Verify

sha256_of_railcall_station.tar.gz = e90027bf8c28057fcb461ebda9dff7a577918ee11e764461e6c4c4f2585e6626
sha256_of_railcall_cli.py         = 9a607b4cb41987685573b1624a85f70264819e3a537b43ded3013364604bbc95
sha256_of_railcall_vault_drivers.py = 7ff6896532adcbcf8302039bafe403884f457d8fb2ed87320e8283c61f9df096

Every install.sh downloads is pinned above; a wire tamper fails the pin gate before anything reaches disk.

Deferred to v0.27+

  • railcall_hosted vault driver — requires a marketplace-side vault-ingest endpoint + storage decision. Separate design conversation.
  • Weeks 13-16 of the Enterprise plan (SLA infra, BAA workflow, policy engine).
  • Studio session picking up the org identity from JWT claims (marketplace org membership → Studio session context).

station-v0.25 · publisher trust allowlist (Phase 4a sandbox)

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 24 Jul 15:19

What's new

Publisher trust allowlist (Phase 4a of the module sandbox)

Signature verification proves WHO signed a module bundle. This release adds
the second question: WHICH publishers are allowed to register commands on
THIS install. Two modes:

  • trust_mode: any (default) — historical behavior; any valid
    signature accepted. Existing installs unchanged.
  • trust_mode: allowlist — strict; only publishers in
    <ws>/publisher_trust.json register commands. Rejections surface the
    publisher fingerprint + a copy-pasteable railcall trust add hint in the
    Modules tab.

First-party publishers (Sami's marketplace publisher key 726b327ec6…)
ship pre-trusted in the default allowlist, so first-party modules keep
working when a user flips to allowlist mode.

New CLI: railcall trust

railcall trust list                     mode + allowlist snapshot
railcall trust add <pubkey> [--name]    trust a publisher
railcall trust remove <pubkey>          untrust a publisher
railcall trust mode any|allowlist       flip enforcement mode

New endpoints

  • GET /api/trust/state — mode + allowlist
  • POST /api/trust/add — {pubkey, publisher_name?, note?}
  • POST /api/trust/remove — {pubkey}
  • POST /api/trust/mode — {mode: 'any'|'allowlist'}

All session-gated; auto-trigger a modules reload so newly-trusted (or
newly-untrusted) modules register/unregister live.

Sandbox roadmap

  • 4a (this release): trust allowlist — WHO's allowed
  • 4b (later): subprocess isolation — HOW the still-allowed runs are
    contained (per-module network allowlist, restricted stdlib, timeout,
    memory limit). Defensive against "trusted publisher pushes bad update";
    4a is defensive against "random module from the marketplace runs by
    default".

SHA256

44182d0931e8400f0789152b022484522fd3e9f08174a528b6c3f397f0262b91

Install / update

curl -fsSL https://railcall.ai/install.sh | bash   # fresh
railcall update                                    # existing

station-v0.24 · Licenses tab + paid-module UX loop + Stripe fixes

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 24 Jul 13:18

What's new

Studio surfaces

  • Licenses tab (new sidebar entry) — visual home for module licenses. Cards per license with tier + days-left + grace-warning badges. Activate box (paste JSON or upload file) + per-license Deactivate. Empty state points at the marketplace.
  • Modules tab — license-gated rejections now render Buy license (deep-link to marketplace) + Activate license (jumps to Licenses tab) buttons. Other rejection reasons (bad signature, missing files) unchanged.
  • Marketplace tab — installing a paid module fires a confirm dialog explaining the buy-then-claim ceremony BEFORE the download, so users don't strand themselves at a rejected-module wall. Success card includes a purple "License required" callout with marketplace deep-link + exact railcall market claim command.

Loader

  • _load_modules includes manifest.id in license-gated rejection payloads so the frontend can build marketplace URLs without a second lookup.

Marketplace (server-side, already deployed)

  • Stripe checkout enforces the $0.50 minimum with actionable error messages (e.g. "listing priced at $0.20 is below Stripe's $0.50 minimum"). Free listings unaffected.
  • Stripe's actual error messages now surface to buyers ("card declined", currency mismatch, etc.) instead of the generic "try again".

CLI (unchanged from v0.23 — no re-pin needed)

Still ships license activate/list/verify/deactivate, market claim, connect salesforce.

SHA256

7983ebc49343b3b93ac791bee961ccb634f61da46e3b97866fe94453395cf5c3

Install / update

curl -fsSL https://railcall.ai/install.sh | bash   # fresh
railcall update                                    # existing

station-v0.23 · Local DRM + Salesforce module (Phase 2 goes real)

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 24 Jul 02:36

What's new

Local DRM — sellable modules (the Phase 2 unlock)

  • module_entitlement.py primitive — signed per-module licenses, verified OFFLINE against a pinned issuer key. Twin of entitlement.py (org-tier) but scoped to one module — blast-radius separation between key compromises.
  • Loader gate — modules with license_required: true in their manifest refuse to register commands unless a valid, install-bound, unexpired-or-in-grace license file exists under WS/module_licenses/<safe_id>.json.
  • 7-day grace past expiry — warns but never blocks. Enterprise ops teams must never be gated by billing lag.
  • Install binding — every license carries this install's Ed25519 pubkey inside the signed body. Copy a license to a second machine → refused. Nothing to unlock on the box; the lock IS the machine identity.
  • railcall license CLIactivate <path> / list / verify [module_id] / deactivate <module_id>. Delegates to the station primitive (the ONE audited verify path).
  • Modules tab license badge — tier + days-left when licensed, GRACE warning in the 7-day window past expiry.

First real paid module: railcall/salesforce ($199/mo)

  • Installable from marketplace: railcall market install sami666/salesforce
  • 13 airlock commands covering the full lead-to-cash surface:
    • Leads: sf.lead.create, sf.lead.update, sf.lead.convert
    • Contacts: sf.contact.create, sf.contact.update
    • Accounts: sf.account.create, sf.account.update
    • Opportunities: sf.opportunity.create, sf.opportunity.update_stage, sf.opportunity.close
    • Cases: sf.case.create, sf.case.update, sf.case.close
  • OAuth 2.0 refresh-token flow — bring your own Connected App; token never appears in receipts. Sandbox orgs supported via test.salesforce.com token_url.
  • 14-day free trial available on request.

Also in this cut

  • New loader helpers: _oauth_refresh(provider), _http_get/patch/delete_json — unlocks Salesforce, HubSpot OAuth, Google, Microsoft, and any REST API on grant_type=refresh_token.
  • _vault_save(provider, value) for helpers that need to persist derived state (e.g. OAuth cached access_token) without going through the credential-save airlock.

SHA256

5089c33f7f051d9390ffaa699cac1d01656aece9ffee36a8cf36e811e5e2f68d

Install

curl -fsSL https://railcall.ai/install.sh | bash

Existing installs

railcall update

station-v0.22 · modules system (Modules tab + HubSpot module + hot-reload)

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 23 Jul 22:06

What's new

Modules system (major)

  • Studio Modules sidebar tab — new management surface at #/modules. Cards for every loaded module show publisher fingerprint, version, description, registered commands as chips, file path. Per-module Uninstall; global Reload All. Rejected modules render in a red section with the loader's exact rejection reason.
  • Hot-reload without restart/api/modules/reload re-verifies signatures and re-registers commands live. railcall market install <module> no longer needs a Studio restart.
  • Sidebar badge — Modules tab shows installed-module count.

First real CRM module: railcall/hubspot

  • Installable from marketplace: railcall market install sami666/hubspot
  • Two commands: hubspot.create_contact + hubspot.log_note
  • Auth: HubSpot Private App bearer token (one vault entry, both commands)
  • HubSpot v3 CRM API + association type 202 for note↔contact linkage
  • Reference implementation for third-party CRM modules

Marketplace fixes

  • Publish DTO now accepts listing_type=module (previously the DTO gate blocked at 400 before payload validation)
  • Two new categories: CRM and Modules
  • Reviews eligibility API (/listings/:slug/reviews/eligibility) — free installs (amount=0) still unlock reviews
  • Ratings on public seller profile: per-listing + overall
  • Listing.id refactored to opaque cuid; human-readable Listing.slug now owns the URL path

Also in this cut

  • Marketplace catch-all route [...slug] on railcall.ai so namespaced slugs (sami666/hubspot) route without URL-encoding
  • Marketplace browse in Studio: creator/curated/modules sections with trust badges
  • Programs → Workflows rename across UI
  • Publish button in Workflows with preflight (missing seller profile / unregistered pubkey / no session all surfaced before submit)
  • Reviews section on listing detail page
  • Ratings-aware seller profile page

SHA256

15ef73f16071c2f543ea9d43fe7bfa354d4bb07dbb860bff231e42cd18659286

Install

curl -fsSL https://railcall.ai/install.sh | bash

Existing installs

railcall update

station-v0.20 · marketplace→Studio + rate limits + allowlists + workflow_compose MCP + Publish button

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 23 Jul 11:11

Major push: creator economy loop closes end-to-end, airlock hardens with rate limits + allowlists, MCP surface adds workflow composition, Studio gains one-click marketplace publish.

Ships:

Creator loop

  • railcall market install <id> writes a Studio-consumable receipt with attribution — installed marketplace workflows land in Workflows tab with a purple 'marketplace' badge + 'by ' credit
  • Studio Workflows → new Publish button per user-built row (server-side signs with your publisher keypair + POSTs to your marketplace seller account)
  • Publish preflight — checklist card if any prereq missing (keypair · session · seller profile · key registered), each with the exact CLI/URL fix
  • Compose engine credits command_id-bound steps as audited (bridge-composed workflows now PASS instead of UNAUDITED)

Airlock hardening

  • Per-command daily rate limits (defaults: stripe 5/day, twilio 25/day, github 50/day, discord 200/day, local 500/day). Config: WS/rate_limits.json. Rate-limited attempts return blocked_by_policy WITHOUT consuming the approval.
  • Recipient allowlists per command per field, enforced at Preview time (before approval is offered). Config: WS/allowlists.json. Empty list = deny-all; ['*'] = explicit allow-any.
  • Approval-consume moved to before handler invocation — a failing handler still consumes the approval (single-attempt matches the airlock's one-decision contract)

MCP surface

  • New tool: railcall_workflow_compose — external AI turns English into a typed workflow spec, does NOT persist (returns spec for AI to inspect + human to review)

Studio UI

  • Sidebar 'Sends' tab shows a live badge with the pending airlock queue count
  • First-run wizard on Sends (empty vault + empty queue) — dismissible, links to /docs#airlock
  • Programs tab renamed → Workflows (route unchanged for URL back-compat)
  • Programs Run button (data-file dropdown → POST /api/flow/run → deep-link to Sends if bridged)
  • Prompt secret redaction — 10 formats regex'd out before compose call
  • Versioned workflow filenames (no silent overwrites on rebuild)
  • h`` template escape-bug fix on Sends (wizard/bridged/lone sections)

Sha-256 (verify before pinning):

3af81ebdfdc7b6540634500ad660a5ff094bbf0370a63d0523b8020afb5762ed  railcall_station.tar.gz

engine=6a0fb402 core=73887f55 built=2026-07-23

station-v0.19 · airlock bridge + MCP workflow tools + 10 wired handlers

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 23 Jul 09:35

Studio's Builder now composes bridge-ready specs → each row of a run materializes an airlock preview → human approves → real send + signed receipt.

Ships:

  • Builder → airlock bridge: LLM emits command_id + inputs_template per step, flow_engine substitutes per row, /api/flow/run creates pending airlock previews grouped by workflow_run
  • Approval-replay fix: single-use approvals (attempted once, then invalidated regardless of outcome)
  • MCP workflow tools: railcall_workflow_list, railcall_workflow_run, railcall_pending_list — external AI can drive a workflow; human still gates every write in Studio's Sends UI
  • Vault-backed credential storage with in-Studio Configure UI (no more env-var exports)
  • Programs Run button + inline data-file dropdown
  • Prompt secret redaction (10 formats: stripe/openai/anthropic/github/slack/aws/google/discord webhook/bearer/pk_*)
  • Versioned workflow filenames (no more silent overwrites)
  • Client-side elapsed timer during compose

Wired airlock command handlers (10):

  • local.csv_append, local.file_write — governed local disk writes, atomic
  • discord.post_message, slack.post_webhook — webhook messaging
  • webhook.post_generic — POST to any URL (Zapier catch-hooks, custom services)
  • github.create_issue — Bearer + owner/repo in vault
  • notion.add_page — Bearer + Notion-Version header, database_id in vault
  • linear.create_issue — GraphQL, raw-key auth (Linear quirk)
  • airtable.create_record — Bearer + base/table in vault
  • pagerduty.trigger_incident — routing-key auth, Events API v2
  • stripe.create_refund — Bearer + form-encoded + Idempotency-Key from airlock payload_hash (no double-refund on wire retry)
  • twilio.send_sms — HTTP Basic Auth + form body
  • sendgrid.send_email — Bearer + JSON, X-Message-Id captured for receipt

Auth patterns proven: Bearer, Bearer+version-header, raw-key, HTTP Basic, routing-key-in-body, JSON body, form-encoded body, GraphQL. Any new provider = ~30 line handler in this pattern.

Sha-256 (verify before pinning):

3e19dedb54682b394e32681b5d97957063bb89ac49368fbdc80524a502baed52  railcall_station.tar.gz

engine=f4a0534f3 built=2026-07-23

station-v0.18

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 22 Jul 17:13

Marketplace CLI closes the seller loop.

Ships:

  • railcall market login/logout/whoami — proper credential flow instead of the env-var placeholder
  • railcall market publisher init/register + railcall market publish use the local session with auto-refresh on stale JWT
  • Points at the live marketplace backend at railcall-marketplace-lggm.onrender.com

Sha-256 (verify before pinning):

642005a21a1978eb4e17ece5a2eeab73837af4046eeea9cfdd44ae842198d15f  railcall_station.tar.gz

Companion:

  • Marketplace backend deployed; storefront at railcall.ai/marketplace; admin dashboard at /marketplace/admin

engine=9521956fd core=e3bc577

station-v0.17

Choose a tag to compare

@SamyBchaalia SamyBchaalia released this 22 Jul 11:48

Marketplace Shape 1 — browse + install for the RailCall workflow marketplace.

Ships:

  • railcall market list/get/install CLI — browse 7,240 governed workflow templates, install any of the 50 curated exemplars with one command
  • Live at railcall.ai/marketplace + railcall-core.onrender.com/v1/market/*
  • P0-1 CLI seed_store integration (was landed to main after v0.16 but never cut in a release — this closes that gap)
  • Post-checkout success page now seat-aware for per-seat subscribers

Sha-256 (verify before pinning):

bc80a82ce0fe1c60c40a53cb5bf9be0f903f09bd03ae9ac88b9e0e449938d2df  railcall_station.tar.gz

engine=9521956fd core=680e007