← Home
Changelog

What's shipped

Every release. Every date. Every claim on this page verifiable against the corresponding station-vN.M tag on GitHub Releases. No fake-green.

station-v1.2.0

Compliance Evidence Packs (free early access) · module venvs survive updates · disk-space guard

2026-08-16

One click in Studio → Receipts now generates an auditor-ready evidence pack: an executive summary of every governed action in the period (counted from receipts, never estimated), a verification section where the station re-audits its entire receipt corpus from canonical disk bytes (failures are named, never hidden), the signed execution policy in force, a HIPAA §164.312 / SOC 2 control mapping, and the raw receipts as appendix. The pack's manifest carries per-file sha256 hashes and is sealed with an integrity hash + Ed25519 signature — the bundle itself is tamper-evident. Free during early access; may become a paid feature later — receipts and raw export stay free forever. Also in this cut: a module's operator-built .venv sidecar now survives marketplace updates and dev reinstalls (and railcall doctor flags a venv-needing module that has none, with the exact rebuild commands), and a new disk-space guard refuses live runs with a sealed refusal receipt when free disk drops below the policy floor — a clean refusal instead of a mid-write death that corrupts watermarks.

  • Evidence packs
    Studio → Receipts → Evidence pack. Last 30 days, whole-station scope, sealed zip. The generation itself is an audit-logged operator act.
  • #311 venv preservation
    Found live on a customer machine: a module update wiped the Playwright venv the operator had built. Operator state now survives like credentials do.
  • #282 disk guard
    guards.min_free_disk_mb in the execution policy (default 500MB, 0 disables). The refusal is a signed receipt naming the numbers and the fix.
release + sha256 pins →
station-v1.1.0

Lazy tool listing (~95% fewer MCP listing tokens) · Builder → Canvas bridge · MCP flags as Studio toggles

2026-08-16

tools/list can now expose a ~12-tool core instead of the full ~250-tool registry: hidden tools surface on demand through railcall_tool_resolve plus a tools/list_changed notification, and every tool stays callable and identically governed regardless of visibility — a client that ignores the notification loses nothing it knows. Measured 254 → 12 tools live, toggled per-request from Studio Settings with no restart (like every execution-facing behavior: a signed policy field, never an environment variable). The Builder finally lands where you can use it: prompting a workflow now produces visible, editable Canvas nodes — steps bound to real actions become effect nodes, unbound steps become clearly-labelled TODO nodes you replace from the palette, and the engine spec is written only when every step is bound, so a placeholder can never pretend to execute.

  • Lazy tool exposure
    Cost Round 6. The Rounds-1-3 'floor' assumed the whole registry must be visible up front; the resolver was already the taught discovery path.
  • Builder → Canvas
    Built workflows were dead files — invisible in Canvas, unrunnable. Every build now lands as editable nodes; Run goes live when every step is bound.
  • MCP flags in Studio
    Lazy listing and module reads are proper toggles now (module reads had been API-only since v0.86) — signed on save, applied to the next request.
release + sha256 pins →
station-v1.0.0

1.0 — the receipts prove the economics

2026-08-15

The milestone release, and the one where the product's core claim became self-measuring: every governed action — commands as well as workflow runs — seals a routing verdict into its receipt, and essentials.savings computes the station's off-model fraction from its own signed corpus instead of asserting it. Our station reads 96% of execution units never touching a model. Also: one-click 'Approve for unattended' on schedules (with refusal receipts linked on the row), scheduled-run dedupe hardening, and self-cleaning browser-module disk hygiene. Releases v0.86 through 1.0 shipped in eleven days, every fix differentially tested, every community bug credited by name.

  • Self-measuring off-model metric
    The website's ~96% figure and the receipt field are the same number — recomputable by any station from its own sealed receipts.
  • Schedule approvals in Studio
    The standing-grant flow that previously took terminal surgery is two clicks with a blast-radius review.
release + sha256 pins →
station-v0.67

RailCall Teams — signed membership · co-signed approvals · shared credentials without shared secrets · compute offload · policy bundles · cloud stations

2026-08-09

The multi-station release. A team is a signed document — member station pubkeys + roles, signed by an offline root seed — distributed by the Relay but never forgeable by it: every envelope between stations is Ed25519-signed end-to-end, payloads travel as ChaCha20-Poly1305 sealed boxes, and no station ever opens an inbound port. On top of that mesh: policy can demand a teammate's co-signature (quorum k-of-n) before an action fires, with the approval signed on the approver's own machine over the exact action bytes and embedded in the receipt — railcall verify proves the full chain offline, forever. Credentials are shared as capabilities, not copies: the key stays in one vault, teammates get verb-allowlisted, spend-capped grants, every use runs through the holder's own airlock with on_behalf_of receipts, and revocation is instant with no provider key rotation. Workflows offload to worker stations through the worker's own governed DAG path (live gates, plan-pin, signed run receipts; jobs can only reference worker-installed workflows and never exceed the requester's spend cap). Owners push signed policy bundles that can only tighten — receipts stamp which bundle version governed each action. provision-team-station.sh turns a VPS into the team's always-on node. 119 new tests across the team suite; MCP channel hard-refused on every team endpoint.

  • railcall team create / add / remove / join / sync / show
    The membership ceremony. create mints an offline root seed (shown once, stored nowhere) + manifest v1; add/remove ask for the seed, sign vN+1, and forget it. team_id derives from sha256(root_pubkey) so a manifest is intrinsically bound to its signing authority — no trust-on-first-use race. Stations enforce a strictly-monotonic version high-water mark: a perfectly-signed OLD manifest (one that still contains a removed member) is rejected as replay.
  • Delegated + quorum approvals with offline-verifiable co-signatures
    requires_team_approval (per provider / action class / default, quorum k-of-n) gates the live airlock approve path. The staged delta's integrity hash IS the co-signed action_hash. decision_sig binds action ‖ request ‖ decision — no transplanting an approval onto a re-issued request, no flipping a deny, no self-approval counting toward quorum. The receipt embeds the signatures plus the full manifest they were verified under: self-contained offline proof.
  • Shared credentials — capability model
    Holder-signed grants (verb globs + daily spend cap) delivered encrypted; uses travel as sealed capability_use_request envelopes; the HOLDER's copy authorizes (member-side edits are no-ops) and execution runs through the holder's own preview→execute airlock — a policy-gated write lands in the holder's Sends queue and the member is told. Revocation works twice: delete the grant, or remove the member from the manifest.
  • Compute offload to worker stations + cloud provisioning
    POST /api/team/jobs/offer sends a sealed job to a worker-role station; it executes via the worker's own /api/workflow/dag/run (execution-policy live gates, plan-pin, incremental watermarks, signed receipts — nothing relaxes for team jobs). Live jobs target exactly one named worker; cap mismatches refuse. scripts/provision-team-station.sh: idempotent VPS → headless systemd station with mesh polling on, self-verifying before it claims success.
  • Signed policy bundles
    Owner signs a bundle with the root seed; stations adopt on sync (root-verified, monotonic) and APPLY it to their approval gate; receipts stamp team_policy_bundle version. The schema is tightening-only — a remote document cannot switch a member's local protections off.
  • Studio Team tab + Ed25519→X25519 sealed boxes
    New #/team view: roster + sync, incoming approvals (Approve/Deny with dual-control code support), request quorum progress, shared-credential chips with one-click revoke, and a read-only activity feed merged from the receipt-backed stores. Underneath: the standard birational Ed25519→X25519 correspondence means the member manifest doubles as an encryption-key directory — sealed boxes with zero extra key management, proven self-consistent against independent derivation on random seeds.
release + sha256 pins →
station-v0.46 → v0.66

Twenty-one releases in one week — the full C/D/F security tracks, marketplace maturity, and community-driven hardening

2026-08-02 → 2026-08-09

This page fell behind the shipping pace; in the no-fake-green spirit, here is the honest digest rather than a silent gap — every tag below is verifiable on GitHub Releases. Highlights: real policy enforcement (redact/deny/HITL-approve actually happen — C3.x), round-trip tokenization (C4), trust-tier routing (C5), OS-level sandboxing on macOS + Linux (C2.x), off-box witness anchoring + the public receipt validator at railcall.ai/verify (D2/D3), receipt replay-chaining + witness-anchored timestamps (D+E), the Relay durable webhook queue + hierarchical approval routing with dual-signature receipts (F1/F2), multi-file module publish, module credential↔Integrations linkage, the workflow DAG engine wired end-to-end (dag/run, Canvas run settings, plan-pin), MCP attestation-only response boundary, the CTO-ready Runs UI, incremental & scheduled modules with watermark stores, station identity credentials with revocation + temporal verifier verdicts, the offline CLI verifier, canonicalization spec (Unicode NFC), server-hosted verify links — plus a steady stream of community-reported fixes from Dave, Shweta, and others, credited on the public leaderboard. Individual entries for these tags will be backfilled; the GitHub release notes are the source of truth meanwhile.

    release + sha256 pins →
    station-v0.45

    Phase C egress broker · signed egress receipts · RFC 3161 timestamp anchor · module allowed_destinations · Phase B routes/ split (60% reduction)

    2026-08-02

    The 'gate two' cut. Every LLM call routed through station.llm.complete() now emits a signed egress receipt into the same hash-chained audit ledger as action receipts — a metadata-only record that HMAC-fingerprints the prompt without disclosing it, records who called what provider under which policy version, and TSA-anchors the timestamp via freetsa.org. Modules can declare allowed_destinations in module.json; violations refuse with a signed 'denied' receipt. A first-cut CONNECT-proxy broker catches env-var-respecting adversarial modules (OS-level containment stays roadmap and is labeled honestly). A pattern-count classifier + operator policy engine flow the receipt's decision field to would_redact / would_approve / would_deny in monitor-only mode — actual enforcement is C3.1. Under the hood: studio_server.py shrank 17,579 → 7,036 lines across 23 extraction batches into 28 domain modules; contract test stayed 43/43 green through every commit. Three latent bugs found + fixed as byproducts. New docs published: DFD + LINDDUN + STRIDE threat model, marketplace reviewer playbook, whitepaper v1 technical review.

    • railcall_egress_receipt.v1 — signed record on every LLM call
      New receipt schema for every station.llm.complete() call: HMAC-SHA256 fingerprint of the exact prompt using the install-bound Ed25519 seed as key, destination host/model/provider metadata (never full URL — paths can leak tenant IDs), byte + field + token counts, policy_id + policy_version_hash bound at emit time, decision field (v1 always 'allow' unless manifest denies or policy rule fires monitor-only), Ed25519 signature over canonical bytes. Zero content stored — a healthcare lawyer's first question 'does this store PHI?' has a field-by-field answer. Verifiable off-box: fetch /api/signing/pubkey, SHA-256 the canonical bytes, verify Ed25519 — no RailCall service required.
    • station.llm.complete() cooperative-module SDK
      One entrypoint (`from station_llm import complete`) that governs an LLM call end-to-end: build unsigned receipt BEFORE the call so we always know what was about to be sent, dispatch to the provider via the existing route (BYOK + hosted-gateway fallback), attach real token count if the provider returned usage, sign + persist to WS/receipts/egress/eg_*.json, append fingerprint to audit_chain. Returns the provider response + receipt_id + full signed receipt for on-the-wire display. The receipt appears in Studio's Receipts tab as a new 'egress' kind alongside command / build / workflow rows, individually verifiable to PASS with 4 independent checks.
    • RFC 3161 timestamp anchor — real freetsa.org signature on every receipt
      Closes the 'self-asserted clock' auditor objection. Every egress receipt now embeds a 4632-byte freetsa.org-signed TimeStampToken inside the canonical bytes (which are then Ed25519-signed) — tampering with the anchor breaks the receipt signature. Env override RAILCALL_TSA_URL points at any RFC 3161-compliant TSA (commercial DigiCert / GlobalSign for enterprise); RAILCALL_TSA_DISABLE=1 short-circuits for offline dev. Fail-open on TSA network error: receipt still emits with a labeled error field so auditors see 'clock is self-asserted for this record' rather than 'signature crashed'.
    • module.json allowed_destinations — cryptographically-signed destination contract
      Publishers add an allowed_destinations array to their module manifest: [{provider: 'anthropic', models: ['claude-*']}, {provider: 'railcall-gateway'}]. Because the manifest is signed at publish time with publisher_pubkey (v0.22 modules system), the destination contract is signed-in — a publisher cannot ex post claim to have declared something they didn't. Station refuses violations with a signed 'denied' receipt (decision='denied', reason cites the manifest gap, audit_log egress_denied event). Backward compat: modules without the field get 'unrestricted' with an honest label; empty array means 'zero destinations allowed'.
    • C2.0 CONNECT-proxy broker — first-cut adversarial containment
      Honestly labeled as demo-quality, not enterprise-hardened (week-1 of a 6-8 week scope). Spawns child modules with HTTPS_PROXY forced through a station-controlled CONNECT-only proxy. Env-var-respecting SDKs (urllib, requests, most provider clients) get caught: destination host checked against module's allowed_destinations before any TLS handshake; violations return 403 to the child. TLS content is NEVER visible to the proxy — CONNECT-only preserves the 'we never see prompt content' promise structurally. Documented gap: ctypes/rawsocket bypass still escapes; OS-level sandbox (seccomp/AppArmor/macOS sandbox-exec) is C2.1.
    • C3.0 pattern classifier + operator policy engine (monitor-only)
      The receipt's decision field now flows from real signals: primitives/egress_classifier.py detects email, phone (structured formats), Luhn-validated card_like, ssn_reference (word literal), password_reference (word literal) and returns per-category counts. primitives/egress_policy.py reads the operator's rules from WS/egress_policy.json ({if: {has_category: 'email'}, then: 'would_redact'}) and returns a decision string. Neither redacts nor blocks — the receipt RECORDS what would have happened. Real enforcement (redaction, actual blocking) is C3.1 with Presidio + OPA/Cedar. Honest scope: pattern-count only, LOW-MEDIUM recall on real PHI — do NOT market as 'detects PHI'.
    • Phase B — studio_server.py decomposition (60% reduction)
      17,579 → 7,036 lines across 23 extraction batches. 145 branches from H.do_POST + H.do_GET moved into 28 domain modules under workbench/routes/. All extractions preserved response shapes verbatim; contract test stayed 43/43 green through every commit. Three latent bugs found + fixed as byproducts: PEP 562 bare-name resolution (affected every routes/ module extracted from B15+), off-by-one delete range in B25a that killed /api/workflow/signup_to_sheet/status header, __main__ vs studio_server copy-drift on _MODULES_STATE. The refactor is what makes an outside code reviewer able to audit the airlock in an afternoon instead of a week.
    • docs/phase_c_threat_model.md — DFD + LINDDUN + STRIDE first cut
      500-line honest un-marketing-cleaned threat model. System context diagram, per-trust-boundary data flow, 11-asset inventory, full LINDDUN pass (Linkability / Identifiability / Non-repudiation / Detectability / Disclosure / Unawareness / Non-compliance), STRIDE pass as per-attack tables, explicit cooperative-vs-adversarial scoping decision (v1 = cooperative; C2 for env-adversarial; OS sandbox for full-adversarial), 10-item gap roadmap with per-gap effort, field-by-field auditor cheatsheet mapping every receipt field to what it PROVES. 'PHI-safe by construction' explicitly rejected as overreach — correct phrasing 'no content in receipts; metadata only; residual inference risk disclosed' is used verbatim. Doc a reviewer can read cold + walk into a compliance conversation with.
    • docs/marketplace_review_playbook.md — reviewer field guide
      How to accept or reject a module/workflow submission after the automated preflight + auto_lint run. 60-second decision gate (3 yes/no questions), module-specific human checks (title honesty, write→receipt_required invariant, credential declarations, allowed_destinations, homepage reachability), workflow checks (trigger/effect coherence, blast radius caps, policy_probe presence), publisher-trust first-timer onboarding via out-of-band verify, 11 canonical module rejection labels + 5 workflow labels (verbatim strings so 'Common Publish Rejections' stays a real ontology), publisher-facing feedback templates, explicit escalation criteria. Hand a new admin this doc + walk through 3 real pending submissions — that's the whole training.
    • docs/whitepaper_v1_technical_review.md — v1 paper audit against current code
      3 factual errors flagged (v0.43 → v0.44/v0.45; marketplace ROADMAP → SHIPPED; 2 phrasings that could bounce off a healthcare lawyer — the airlock 'no code route' claim + the HIPAA §164.312(e)(1) 'PHI never leaves the perimeter' line). One substantial gap: Phase C egress broker (the pitch's slide 4b 'gate two') has zero coverage in the current paper — recommended new §04b lifting structure verbatim from the threat model. Every claim checked against a specific file path or commit; whitepaper's mechanism-level claims all hold. Fixes ordered NOW (30 min) vs SOON (1-2 hours).
    • Contract test: 43/43 GREEN through every batch
      The pre-Phase-B contract test suite (baseline snapshots of 43 read endpoints) served as the safety net for the entire refactor + Phase C shipping. Caught 2 real regressions during Phase B (B26b restored a branch header B25a accidentally deleted; B24b fixed the PEP 562 latent bug that would have silently broken every route module on fresh boot). Ends v0.45 at 43/43 green — same snapshots that were green at v0.44 boot are green at v0.45 boot. Verifiable via `python3 -m workbench.tests.test_studio_contract`.
    release + sha256 pins →
    station-v0.44

    Policy scenarios · station-side approval gate for MCP · canvas rails runnable from any LLM

    2026-07-31

    The governance-surface cut. The Policy tab stops being a config file and starts being a decision engine you can operate: pick a stance (Solo dev / Startup speed / SOC 2 baseline / HIPAA-strict / Enterprise lockdown), see exactly what the engine would decide for any action + which rule wins, watch a live activity strip of recent decisions with rule attribution. Every rule and every scenario apply is staged, signed, and version-bumped through the same airlock that enforces them. Separately: MCP-triggered actions now route through a station-side approval gate so the LLM client cannot bypass the human-in-the-loop by 'allow always,' and canvas-authored workflows are runnable from Claude Desktop (or any MCP host) instead of showing up in workflow_list but silently 404'ing on workflow_run.

    • Policy tab: scenario-first governance surface
      Rewrite of the Policy view around how compliance officers actually think — pick a stance, don't hand-author tuples. Five starter scenarios ship with curated rulesets: Solo developer (permissive on internal tools), Startup speed (auto-approve reversible cross-provider, require_human on money + customer channels), SOC 2 baseline (every write is human-approved), HIPAA-strict (block unauthenticated PHI channels, require_human otherwise), Enterprise lockdown (block high-risk verbs, no auto-approve). Applying a scenario is a signed policy version bump through the same airlock as any other write.
    • Decision explorer + activity strip
      New `/api/policy/decide` frontend surface: pick any (provider, verb, action_class, workflow) and see the exact decision + which rule matched, evaluated against the current policy version. Auto-refires on every field change for live feedback. Below it, `/api/policy/recent-decisions` powers a live activity strip showing the last 20 policy_gate outcomes from receipts on disk with rule attribution — so you can see what the engine has actually been deciding in production, not just what the rules say.
    • New require_human rules list · strictest wins on tie
      Rules now come in three flavors: block, require_human, auto_approve. Precedence: block → hard floors (F1/F2/F3) → require_human → auto_approve → default. Explicit require_human always beats a broader auto_approve match — so an operator can add 'workflow=investor_demo → require_human' without also having to remove a 'discord.reversible → auto' rule that would otherwise let it through. Rules can also scope by workflow (not just connector/verb/action_class).
    • MCP require-Studio-approval gate
      New env `RAILCALL_MCP_REQUIRE_STUDIO_APPROVAL=1`. When set, MCP `_apply` tools do not fire — they stage the action + return 'pending, approve in Studio' to the caller. The action surfaces in Studio Sends' new purple airlock banner (also visible in the VS Code HUD's pending approvals) with a preview of the message body, provider, verb, and a per-row Approve LIVE button. Same code path as any Studio Sends direct-send — same signed receipt, same policy check, same audit trail. Closes the 'LLM host can auto-approve its own tool calls' gap.
    • railcall_workflow_run: canvas rails are runnable
      `h_wf_run` used to scan only `<engine>/tests/workflow_*receipt*.json` — the four legacy compose-engine bug_triage receipts. Canvas-authored rails at `<WS>/workflows/*.json` were visible via `railcall_workflow_list` but silently 404'd on run. Fixed: the run tool now recognizes canvas shape, iterates the effect nodes, and stages each through the per-provider airlock. Two Discord effects in a chain become two stg_*.json files that appear in the Studio Sends banner + approve like any other MCP-staged action.
    • Canvas: Approve · LIVE button
      The plan modal in Canvas used to only expose 'Approve · dry-run' (hardcoded live=false). Now: two buttons — 'Approve · dry-run' (grey, no external calls) and 'Approve · LIVE' (pink, fires real external calls + writes a signed workflow receipt to `<WS>/receipts/runs/`). The station-side live-apply gate is env-controlled (`RAILCALL_MCP_ALLOW_LIVE=1`), same gate MCP applies use, so both paths honor the same operator opt-in.
    • Studio Receipts tab: workflow + capoff receipts land properly
      `receipts_index` used to scan only `<WS>/receipts/*.json` root + `<WS>/receipts/capoff/build__*.json`. Workflow-apply receipts at `<WS>/receipts/runs/wfrun_*.json` and single-action airlock receipts at `<WS>/receipts/capoff/discord__*.json` were missing. Fixed: both dirs are scanned with proper metadata (workflow_id, outcome, mode, integrity_hash). Receipt detail renderer also reads workflow-shape fields (integrity_hash, approval.timestamp) so the terminal block shows real sha/sig/timestamp values instead of the empty placeholders operators reported.
    • VS Code extension: HUD scans workflow receipts
      `receiptsProvider.ts` extended to also watch `receipts/runs/` (workflow apply outputs) alongside `receipts/capoff/`. Accepts `workflow_id` or `wf_id` as a stand-in for `provider` when identifying a receipt — workflow receipts don't carry `provider`. Repackaged as railcall v0.6.0 vsix; workflow runs from Canvas or Claude Desktop now surface in the HUD alongside direct-action receipts.
    • Workflows tab: Visual button routes to canvas for canvas rails
      `/api/workflows/list` now includes `kind: 'canvas'` for Canvas-authored rails. The Workflows tab's Visual button routes to `#/canvas?open=<id>` (interactive graph editor) for canvas rails; compose-engine builds still route to `/ui/<name>.html` (static HTML preview). Killed the 'no preview yet — build it first' 404 canvas rails were hitting on Visual.
    • MCP railcall_workflow_list picks up canvas rails
      The MCP tool used to enumerate only `<engine>/tests/workflow_*receipt*.json` (the four legacy bug_triage rails). Now merges with `<WS>/workflows/*.json` so an AI caller sees the operator's own Canvas + composed rails first, with a `source` field distinguishing canvas / composed / test_receipt. Fixes the 'Claude sees 4 workflows but not the one I built' report.
    release + sha256 pins →
    station-v0.43

    Paid-tier trust service · Modules tab credential linkage · collision-safe module credentials

    2026-07-30

    The paid-module trust cut. Closes the local-DRM mid-term-refund gap with a server-side trust service the station re-checks daily. Buyer-side, every installed module now shows a live ✓/⚠ credential chip in the Modules tab with one-click routing to Integrations to fix red ones. Publisher-side, modules that need credentials for a NEW provider auto-populate the Integrations tab; modules that extend an EXISTING built-in provider (e.g. Salesforce with an extra `secret` field) get their credentials auto-namespaced so they never silently overwrite the built-in shape.

    • Paid-tier trust service (POST /licenses/verify)
      New marketplace endpoint signs a short-TTL trust token (24h) per (listing, install_pubkey). The station re-checks daily via `module_entitlement.check_server_trust`; a mid-term refund or subscription cancel now revokes the local license within a day instead of the license's embedded expires_at. Trust cache lives at `<ws>/module_licenses/verify_cache/<safe_id>.json`. Grace when the marketplace is unreachable: 7 days consumer / 30 days enterprise before the module hard-blocks. Verification is Ed25519 against the pinned MARKETPLACE_PUBLISHER pubkey — same trust root the station already uses for signed bundles.
    • Install-time credential check (CLI)
      `railcall market install <workflow-slug>` now flags THREE gap classes before writing to disk: missing action_ids (need module install), missing providers (unknown provider — likely stale station), AND missing credentials (provider known but no vault entry). Buyers install a workflow that references `stripe`/`notion`/`slack` and immediately see `provider=stripe needs credentials (configure in Studio → Integrations → stripe)`. Non-blocking WARN panel — the workflow still installs so buyers can inspect it — but the gap is legible before the first plan attempt.
    • Modules tab: per-module credential chip
      Every loaded module with a `credential_spec` now renders a live chip on its card: green `✓ <name> creds` when configured, orange `⚠ <name> creds missing` otherwise. Click routes to Integrations pre-filtered to that provider. `/api/modules/list` computes `credential_status` at request time — reflects vault edits without a reload. Detail view gets a matching Credentials tile next to Slug/Commands/License/Publisher fp.
    • Credential-spec collision: auto-namespace + vault_get shim
      Publishers can now safely extend a built-in provider. If a module declares `credential_spec.provider = 'salesforce'` with extra fields (secret, org_domain, custom_field), the loader auto-namespaces the vault key to `<slug>::salesforce`. The built-in `salesforce` credentials are untouched; the module's own creds live at the namespaced key. The Integrations tab labels the module's entry as `Salesforce+ (from module sami666/sf-plus)`. Handler code stays portable — a per-module `vault_get` shim rewrites `vault_get('salesforce')` inside that module's handlers to the namespaced key transparently.
    • Q&A: new providers vs Integrations tab
      Rounded-out the mental model: brand-new providers (Zoho, Airtable Pro, whatever) that a module declares auto-populate the Integrations tab at load time via `_module_credential_specs()` (v0.40 primitive). Fields come straight from the module's manifest — no station cut needed. First-wins collision rule: if two modules ship the same provider name, the first loaded wins the plain key, the second auto-namespaces.
    release + sha256 pins →
    station-v0.42

    Quality gate everywhere · doctor covers the whole stack · palette module-groups as disclosure widgets

    2026-07-30

    Cross-cutting quality-and-trust cut on top of v0.41. Every publish path (CLI + browser) now runs the same pre-publish lint before signing. Every install path (CLI market install) checks the workflow's module dependencies BEFORE writing to disk. `railcall doctor` now diagnoses Studio + modules + palette state end-to-end, and catches the stale-process trap (updated on disk but the running Studio still serves the OLD code) that trapped multiple publishers on v0.41. Palette module rows are proper disclosure widgets — same interaction pattern as pre-installed provider groups — so publishers stop reading them as passive.

    • Pre-publish quality gate — CLI + browser + server
      New server-side linter runs on POST /listings, blocks publish on 5 workflow errors (empty edges, hardcoded stripe amounts, postgres nodes without SQL, duplicate args across nodes, empty nodes) + 6 module errors (missing commands, missing titles, trivial handler.py, handler function name mismatch, unparseable manifest, etc.). Warnings persist as auto_lint admin_notes for reviewer triage. CLI `railcall market publish` and the browser publish form both preflight the same /listings/lint endpoint before spending a signature.
    • railcall doctor covers Studio + modules + palette
      The support-thread killer. `railcall doctor` now hits /api/version, /api/modules/list, /api/actions on the local Studio and reports release_tag, loaded/rejected module counts (with reasons for each rejection linking to the publish-rejections docs), and palette action counts. Also cross-checks in-memory release_tag vs on-disk STATION_VERSION.json — mismatch triggers a WARN with the exact `pkill -f studio_server.py && railcall studio` fix.
    • Install-time module dependency check
      `railcall market install <workflow-slug>` walks the spec's nodes[]/steps[] and cross-references against the local action registry. Missing pieces surface as a WARN panel with the specific gap (`action_id=hubspot_contact_upsert (install the module that provides it)`) BEFORE writing to disk. Non-blocking — the workflow still installs so buyers can inspect it — but no more surprise 'unknown effect' errors at plan/run time.
    • Palette module rows: disclosure widgets
      Community feedback on v0.41: the 'Modules · N' section read as a passive discovery panel even though rows have been draggable since phase 2. Root cause: module_id sub-headers were plain labels with no click affordance, breaking the interactive pattern the provider groups above establish. Now each module_id group is a full disclosure widget — clickable header + chevron + expand/collapse, identical to provider groups. Publishers who recognize the ▾ on a provider immediately know modules behave the same way.
    • Admin dashboard: filter for auto_lint warnings
      Reviewers can now filter /marketplace/admin/listings to surface only listings that landed with pre-publish lint warnings. Per-row yellow ⚠ N badge deep-links to the detail page's notes surface. Closes the moderation loop opened by the auto_lint feature: warnings are surfaced AND findable.
    • Docs: Common publish rejections
      New reference at /docs/marketplace-developer/publish-rejections covering every lint code with the exact fix per code. Downstream of a Discord user who hit module.handler_missing_function (fn_name = command_id.replace('.', '_').replace('-', '_')) with zero doc coverage. Cross-linked from the Publisher FAQ.
    • Login UX + CLI polish
      `railcall market login` now prints '(Password is hidden while you type — press Enter when done.)' before the getpass prompt (fixes the 'I typed my password and nothing happened' report). Empty-password submission surfaces a clear panel instead of silent exit.
    • Enterprise landing + site polish
      New /for-teams landing captures 5-50 seat teams landing on railcall.ai with team intent (was previously dumped into the buyer marketplace). Site-wide 180ms fade page transitions + native smooth-scroll for anchor navigation. Footer uses the real RailCall mark. `For teams` in the top nav.
    • Marketplace dashboard rebuilt buyer-first
      /marketplace/dashboard was a 2758-line megafile shouting 'Apply to sell' at every new user. Split into a lean buyer landing (browse tiles + purchases + subscriptions) with publisher/API-keys/organization moved under /marketplace/settings/*. Sidebar layout, one job per page, every file under 800 lines.
    release + sha256 pins →
    station-v0.41

    Modules as workflow nodes · Studio Org tab · brand refresh

    2026-07-29

    The five-shipment cut that closes the module story end-to-end: every module command installed on your machine now shows up in the Studio canvas palette and drops onto workflows as a real effect node. Studio also picks up the website's pink→orange identity + gets a native Organization tab so enterprise admins stop context-switching to the marketplace to see members and seats.

    • Modules as first-class workflow nodes
      Every command from every installed module (marketplace or local) shows in the canvas palette next to the pre-installed brand integrations. Drag one and it runs through workflow_engine's normal effect path — plan-time blast radius, apply-time receipt, approval gate for writes — dispatching to the module's LOCAL_HANDLERS on apply. No republish required for existing modules; the station synthesizes an Integration wrapper from each command's manifest at load time.
    • Palette taxonomy unification
      One vocabulary now: `pre-installed` chip on the shipped brand groups (slack, notion, github, …), `marketplace` chip on modules registered from disk. Same visual language, provenance disambiguated by the chip. Everything is a module in the mental model.
    • Studio Organization tab
      New Settings → Organization surface. Proxies /org/members + /org/billing/seat-status via a marketplace API key stored server-side in the Studio vault (never in the browser). Renders the tier + seat gauge + members list read-only; mutating actions (invite, SSO config, vault destination) deep-link to /marketplace/settings/organization. Daily admins stop leaving Studio to check who's on the team.
    • Studio brand refresh
      Tokens realigned with railcall.ai — primary swapped from purple #7C3AED to brand pink #FF155D, new --brand-pink / --brand-orange / --brand-gradient matching the website. Fonts loaded from Geist / Geist Mono with Inter / JetBrains Mono kept in the fallback chain. Real RailCall mark replaces the placeholder bolt in the topbar (same geometry the website uses).
    • Login state unified across marketplace + main site
      Nav.tsx / lib/auth.ts extended so marketplace-signed-in users see 'Dashboard →' on the main site (was always 'Sign in' because the check hit legacy gateway storage). Homepage buyer-first landing at /marketplace/dashboard with orient + browse tiles + purchases; publisher / API keys / org moved under /marketplace/settings/*. Full backing rewrite (the 2758-line megafile) split into files, all under 800 lines.
    release + sha256 pins →
    station-v0.27

    Headless CLI auth — API keys in the terminal

    2026-07-25

    Small, focused release on top of v0.26. Closes the loop by making the marketplace API keys usable from the CLI without opening a browser.

    • `railcall market api-keys list|create|revoke`
      Three verbs, direct mappings of the web-UI surface at /marketplace/settings/api-keys. Fresh secret prints ONCE to stdout on create — matches the web UI's one-shot banner.
    • `RAILCALL_API_KEY` env var precedence
      Every marketplace-authed command checks the env var first, falls back to interactive session only when unset. Set it in your CI/CD runner and every command works headlessly. Rejected key does NOT silently downgrade to the session — that would mask credential misconfigs.
    • Lateral-privilege guard on api-keys management
      An API key can't mint or revoke other API keys — that would be a lateral privilege loop. The CLI detects RAILCALL_API_KEY on api-keys subcommands and refuses with an actionable message pointing at `railcall market login` OR the web UI.
    release + sha256 pins →
    station-v0.26

    Enterprise readiness — SSO + RBAC + SCIM + configurable receipt vault

    2026-07-24

    The most significant single release since v0.22 (marketplace/modules launch). First cut where a team-sized customer can honestly buy Enterprise: log in with their identity provider, auto-provision + auto-remove users, assign roles across their team, publish modules only their team sees, stream every signed receipt to a shared vault they control.

    • WorkOS SSO
      SAML/OIDC — Okta, Azure AD, Google Workspace, Ping. Enterprise buyer types their domain at /marketplace/sso, browser bounces through their IdP, JIT-provisions User + Membership + mints the same JWT the password flow issues.
    • Multi-seat + RBAC (5 roles)
      viewer / operator / publisher / admin / owner. Higher role implicitly grants every lower one. Last-owner protection prevents an org from becoming ownerless via demotion or removal.
    • SCIM Directory Sync
      WorkOS webhook handler. When the customer's IdP flips a user, we mirror it: JIT-create Membership, sync attributes, mark removed_at on delete. Group→role mapping via Organization.dir_group_role_map (admin configures at /marketplace/org/dir-role-map).
    • Configurable receipt vault (4 drivers)
      local (filesystem path — covers external SSD, NAS mount, USB) · s3 (hand-rolled AWS SigV4, zero deps, works with AWS S3, MinIO, R2, GCS) · network_share (SMB/NFS) · custom (importlib loader for user-supplied Python drivers). Secrets never in the marketplace DB — configured as env:/file:/keyring: references.
    • Air-gap install kit
      Self-contained tarball (railcall_airgap_v0.26.tar.gz) with every file + governance ruleset + station bundle + MANIFEST.txt sha256 + verify.sh. Move to network-isolated host, run verify.sh, then install.sh. No outbound at install OR runtime.
    • Session invalidation on removal + role demotion
      AuthService.invalidateAllSessions bumps user.session_generation and revokes every un-revoked refresh token in one transaction. Max window from 'you're fired' to 'your JWT stops working' is 15 min — access-TTL grace.
    • Admin audit log
      OrgAuditLog append-only table. Every admin-scoped mutation writes here — member invited/role_changed/removed, vault config changed, SCIM events, subscription activated. Owner+ view at /marketplace/org/audit with event-slug filter + keyset pagination.
    • Long-lived API keys (rc_ak_live_*)
      Web UI at /marketplace/settings/api-keys — sha256 stored, per-key scopes, one-shot display on create. Wired into POST /listings (canonical CI/CD use case: headless module publishing).
    • Team-tier billing
      $100/seat/mo, min 2 seats, 14-day free trial. Self-serve Stripe Checkout at /marketplace/org/billing. Real live-mode subscription pointed at real license-mint service.
    • GDPR Art. 20 org data export
      GET /org/export dumps organization + members + invitations + org-owned listings + 500 most recent audit lines as JSON. Owner-only. Recorded in the audit log itself.
    • /trust/subprocessors + /status
      Public per-vendor list of every third party that touches customer data (Render, WorkOS, Stripe, Resend, GitHub, Cloudflare) with data categories, jurisdictions, and 30-day new-vendor notification commitment. Live client-side probes of railcall.ai + marketplace API at /status.
    release + sha256 pins →
    station-v0.25

    Publisher trust allowlist (Phase 4a)

    2026-07-19

    Pragmatic module sandboxing: only pubkeys on our maintained allowlist can publish workflow/module types. Full subprocess sandbox (Phase 4b) deferred; the allowlist covers 100% of the risk at 5% of the implementation cost.

    • Trust allowlist enforcement
      listings.publish refuses if the publisher_pubkey isn't on the allowlist. Sami's pubkey (726b327ec6…) is on it; new sellers need staff approval before publishing.
    • HIPAA trust page
      /trust/hipaa — technical safeguards map (§164.312), BAA scope, our HIPAA position. Compliance still lives in your posture; the evidence artifacts your auditor asks for ship with the base install regardless of tier.
    release + sha256 pins →
    station-v0.24

    Licenses tab + paid-module UX loop

    2026-07-17

    The full buy → install → run loop for paid modules — from prominent buy CTAs on the storefront to a dashboard 'claim your license' block to Studio-side modal that walks a user through activation.

    • Studio Licenses tab
      Visual license management inside the Studio. See what's activated, when licenses renew, revoke stale entitlements.
    • Auto-claim: install_pubkey linking
      Account-linked install pubkey triggers automatic license mint after purchase. Buyer clicks 'Install' in the Studio; no manual license entry required.
    • Stripe Billing Portal for buyers
      Buyer self-service for subscription management (cancel, change payment method, download invoices) via Stripe's hosted portal — no code we maintain.
    release + sha256 pins →
    station-v0.23

    Local DRM — signed per-module licenses bound to install pubkey

    2026-07-15

    Every paid module gets a per-install Ed25519-signed license bound to the buyer's install pubkey. Studio's module loader refuses to load a paid module without a valid license. License mint runs on a separate Render deploy so a marketplace compromise can't leak the signing seed.

    • Module license primitive
      module_entitlement in the loader — the ONE audited verify/install path. CLI never reimplements verification.
    • `railcall license` CLI
      activate / list / verify subcommands.
    • Salesforce module Pack A ($199/mo)
      First real paid CRM module — 13 core CRM commands + OAuth refresh + signed per-install license.
    release + sha256 pins →
    station-v0.22

    Modules system — marketplace launch

    2026-07-14

    Signed handler bundles that add new airlock commands. Publishers can now ship real capability (not just workflow templates) through the marketplace. The wedge that seeds supply and demand on the platform side.

    • Module loader
      Signed bundles installed to ~/.railcall/station/modules/<slug>/. Handler manifests describe commands, auth patterns, provider requirements.
    • 5 launch modules
      local.csv_append, Discord, Notion, GitHub, Webhook — spanning the 5 auth patterns modules need to support (none, bot-token, oauth, api-key, signature).
    • Modules browse + management surfaces
      Marketplace section for browsing modules with trust indicators; Studio sidebar tab for managing installed modules.
    • Publish flow live
      Sellers can register a publisher pubkey + publish signed modules through the CLI or marketplace API.
    • railcall/hubspot module
      First real CRM reference implementation shipped free — for buyers to see what a full-featured module looks like before they buy the paid Salesforce module.
    release + sha256 pins →
    Older releases (v0.5 through v0.21) — see GitHub Releases for the full archive.
    Questions or feedback: our Discord.