Skip to Content

STML Release Notes

4.0.23 ​2026 08 25


Release Notes - STML Version 4.0.25

Release Date: September 2026

  • Highlights

          • Exact Online ↔ Odoo invoicing (stml/exact-odoo 0.1.20 on platform/exact-online 0.2.10). One administration configuration maps one Odoo company to one Exact division (a single Exact login serves many). The setup wizard finishes its own wiring: sales/purchase journals, tunable VAT and GL maps, payment mode and schedule times, the pinned webhook + schedule triggers, the x_exact_* fields in Odoo, an "Exact Online" payment journal, and two company-scoped Odoo automation rules (invoice sent → webhook, vendor bill confirmed → webhook) — idempotent, re-run any time, pick an existing administration to edit in place. send-invoice pushes the document into Exact as a sales or purchase entry with the PDF and every attachment, writes the Exact entry number back, idempotent on x_exact_ref. poll-payments (daily 15:00) compares Exact's open receivables/payables with each sent document's Odoo residual and registers the difference as a real, reconciled Odoo payment — or forces payment status only, per the configured mode. The production client does full OAuth2 token rotation, OData calls with 429 rate-limit handling (60/min), a typed error hierarchy that steers retry logic (auth/validation never retried), and token redaction in errors. The app page ships three views — administrations + activity ledger with CSV export, setup grid with per-connection tests, and a test-payment helper that lists open Exact invoices and books cash-journal entries.

          • Rotating credentials for headless flows (platform/runtime 0.20.0, the platform gap Exact surfaced — its refresh token rotates on every use). app.update_connection_params(slug, patch) backs a new /runs/{run_id}/update-connection-params/{slug} endpoint and RPC, gated by the run's connection token and the app-scoped slug (same access rule as resolve-connection). Patch-merge semantics (None deletes a key, blank overwrites, absent keys kept), unit-tested; plaintext values are never logged or returned — the response names the updated keys only.

          • GS1 Nederland → Odoo product onboarding (stml/gs1-odoo 0.1.14 on platform/gs1 0.1.3). Scan, type or paste GTIN/EAN codes — the page is built for keyboard-wedge scanners (auto-focus, client-side check-digit validation with a green/red flash, beep on scan, paste-a-column import) — and every code is looked up in the GS1 registry (brand, description, image, net content, GPC category, brand owner) and upserted into Odoo keyed on barcode: GPC category tree created, brand owner added as a supplier, products tagged "GS1", images re-encoded for Odoo (new Pillow dependency). Idempotent — re-scanning updates, never duplicates — with a dry run, a color-coded outcome table, an activity ledger with CSV export, and a printable sandbox scan sheet (9 GTINs) for demos and testing.

          • Docs: platform introduction diagrams (architecture and building blocks), and the Exact Online rollout's open follow-ups tracked in the roadmap backlog.

        • Migrations

          One, applied to local dev; test/prod via supabase:db:migrate:<env> at release:

          • 20260903100000_update_connection_params_for_run.sql — update_connection_params_for_run RPC: run-token-gated patch of an app-scoped connection's encrypted parameters, backing app.update_connection_params.

Release Date: September 3rd, 2026

 

4.0.24 ​2026 09 02


Release Notes - STML Version 4.0.24

Release Date: September 2026

  • Highlights

        • Flat configuration values — record replaces the parameters bag (023 rev 8, platform/runtime 0.19.0). A configuration's values are now stored once, as a flat {field: value} record, instead of duplicated under every node that happens to render them. Libraries can declare a schema with app.config_type("administration", fields=[...]) — statically extracted at deploy into the app_config_types registry — and consuming flows seed matching fields by name via the flow topology (wizard forms, pinned sessions, and trigger fires all explode the record the same way). Legacy runtimes keep sending node-keyed data; every write path flattens it transparently, and pre-flight validation proved zero conflicting-value cases before the switch. Terminology follows the model: "parameters" → "values" across MCP, tools and the page SDK, and a new configurations.rename RPC does identity-only renames (slug and values untouched). First adopter: yuki-odoo's administration record, collapsed from three duplicated node slices to one flat record.

        • Untyped by default (rev 8.1, decided 2026-09-01). Course correction on 4.0.23's typed configurations: type stays in the model but is now opt-in. By default an app has one shared pool of configurations visible in every flow's dropdown; only apps that genuinely keep distinct kinds declare the runs_config/configures manifest verbs. Verb-less flows no longer stamp an implicit flow-name type on rows they create; the read side keeps the flow-name fallback, so existing backfilled rows stay visible and updatable, and the unpinned upsert prefers a flow's legacy typed row over creating an untyped duplicate.

        • Rename forks, edit edits (rev 8.2). The wizard's save step can carry a reserved configuration_name field that the platform prefills with the pinned row's real name — so a divergent name is always deliberate, and pin-as-target now honors it: same (or empty) name = rev-6 edit-in-place, changed name = save a copy under the new name with the original untouched. Two same-day playground findings shipped with it: the reserved field is session state and is now stripped from every record write (self-healing rows it had already polluted), and "Save as new…" captures the form as the user sees it — the frontend passes its merged submitted-⊕-pending values, so unsubmitted edits are no longer lost.

        • Default pointer can't cross flows anymore. Setting is_default on a typed row used to sync flows.default_configuration_id to the row's stamped flow_id even when that flow didn't consume the row's type; the sync trigger now checks the effective-type match (and existing mismatched pointers were retro-cleaned).

        • Configurations table stops lying about "never ran". The list shows each row's last run, but the page's realtime feed only covers the newest 50 sessions per app — configurations whose last run predated that window showed as never used. A new invoker-rights RPC returns the single latest session per configuration regardless of age; the live window overlays it.

        • Configuration playground (config-demo 0.1.12) — a standalone demo app with three coffee-brewing flows (design-profile / brew / taste-panel) and an interactive page of eight experiments walking the typed-configuration lifecycle: declaration, create-by-running, cross-flow seeding, edit-in-place, Save changes vs Save as new, defaults as flow pointers, and legacy coexistence — with the exact config_type() / manifest-verb snippets inline.

        • Yuki↔Odoo 0.5.7 — production hardening from the first live tenant: purchase VAT codes corrected to Yuki's documented schema (11 = voorbelasting 21%, 5 = verlegd at zero, 18 = 0%), a _clean() pass folding pandas NaN and Odoo's False sentinels to None (no more 'nan' country codes or 'False' emails), country enforced on sales invoices, send-invoice guarded by company_id so multiple administrations sharing one database can't cross-fire, creditor-side payment reconciliation for vendor bills, invoice PDFs forwarded on the sales route, chatter posts on skip/success/failure, and unchanged-partial detection to silence payment re-announcements. Adopts the typed administration record. Open follow-ups (automation-rule teardown on Remove, multi-administration e2e against real domains, stale AGENTS.md) are tracked as solution-009 item 36. platform/yuki-api 0.2.16.

        • LoonPro: stml3 migration tooling (solution 013 §Migration). A pure, offline-tested transform layer (stml3_migrate.py) plus an interactive driver (scripts/migrate-stml3-loonpro.py): reads stml3 via PostgREST and the get-vault-details deployment-secret hop, then writes stml4 through the normal surfaces — connections by driving the odoo connector flow in API-key mode, configuration rows via the configurations API, one drop box per administration via ensure_file(). Dry-run by default with a per-company before/after report; all writes idempotent; secrets exist only in process memory (reports show key last-fours). Alongside it, loonpro configurations moved to code-valued account mappings — chart-verified but human-readable and hand-editable, instead of server-specific ids — and the wizard pre-seeds its connection and name fields for pinned edits.

        • Operational notifications, designed (new feature story 037): platform-emitted lifecycle events (a flow can't report its own crash) on an internal event spine, with notification rules as subscriptions — email + generic webhook in v1, one workspace-level toggle with recipients and an immediate/daily-digest choice, throttling as platform constants, recovery notices on by default. Email transport resolved: Scaleway Transactional Email over HTTPS (the instance SMTP block stops mattering). Exploration only — nothing shipped yet.

      • Migrations

        Six, all applied to local dev; test/prod via supabase:db:migrate:<env> at release:

        • 20260901100000_default_pointer_consumer_guard.sql — default-pointer sync only when the flow's effective type matches the row's (or the row is untyped); retro-cleans mismatched pointers.
        • 20260901120000_latest_session_per_configuration.sql — invoker-rights RPC: latest session per configuration regardless of the realtime window.
        • 20260901140000_flat_configuration_values.sql — the rev-8 flattening: all values into record, node-keyed p_parameters flattened on write, parameters kept as an empty-default column for rollback safety.
        • 20260901160000_untyped_by_default.sql — verb-less flows stop stamping implicit types; flow-name fallback retained on the read side; unpinned upsert prefers a legacy flow-name-typed row over creating a duplicate.
        • 20260901170000_pin_fork_on_rename.sql — pin-as-target honors a deliberately changed configuration_name by saving a copy.
        • 20260902100000_save_as_inputs_and_reserved_strip.sql — strip the reserved configuration_name from every record write (self-healing); p_inputs override so "Save as new…" captures pending form edits.

Release Date: September 2nd, 2026

 

4.0.23 ​2026 08 24


Release Notes - STML Version 4.0.23

Release Date: August 2026

  • Highlights

      • Typed, app-scoped configurations (023 rev 5). Configurations get a nullable type facet and live at app scope: uniqueness is (app, type, name), flow_id is demoted to legacy metadata, and flows declare their relationship to a type in the manifest — runs_config (consumes) / configures (authors). Selection is a filter, not a fence: a flow's dropdown lists rows matching its effective type (runs_config → configures → flow name) plus untyped rows. One configuration row can serve several flows — a setup wizard edits the same row its import flow consumes. The migration is invisible to existing apps: every row's type is backfilled to its owning flow's name, making the new uniqueness exactly equivalent to the old per-flow rule (verified: all rows typed, zero selector/pointer mismatches, apps on pre-0.16 runtimes untouched).

      • Pin-as-target editing (023 rev 6) — a flow can create, use and edit a configuration. A pinned session's terminal ensure_configuration targets the pinned row and preserves its name — picking an administration in the wizard's dropdown IS the edit loop, and a typo in the name field can no longer fork a duplicate. Renames happen on the Configurations screens, never in the wizard; "Save as new" covers duplication. Unpinned sessions create (upsert by name) exactly as before. Saves merge node-granularly (stored || new per step), loads project — each flow sees only the nodes its steps declare. Defaults became a flow pointer (flows.default_configuration_id, at most one by construction; is_default stays dual-written for old readers), and runners auto-pin the default while configurators deliberately open unpinned. Runtime 0.17.0 adds App.pinned_configuration() so wizard code can tell editing from creating.

      • App-level Configurations, Triggers & Connections views with a working icon language. Both tiers (app + per-flow) share the same screens: Type and Flow columns, "via editor" provenance, trigger attribution ("flow X · config Y"). Per row: hover pencil = rename (inline, for connections, configurations and triggers alike), workflow icon = open the authoring wizard (resolved editor_flow_id → configures declaration), settings icon = the settings dialog — and a single-click Run button per configuration that fires the row trigger-style and shows the run in its session column. Bulk "Run selected" / "Run all enabled" ride the same endpoint.

      • Connection editing that works. Edit on a connection re-routes through the connection's own connector_flow_id (library-exported connectors were a hard 400 before). The wizard seeds only non-secret fields — credentials are never decrypted into session inputs — and the save applies a blank-keeps merge on edit-targeted sessions: an empty password field means "keep the current secret", which is exactly what lets every existing connector flow support editing without a code change. Creation saves verbatim, unchanged. Plus PATCH /connections/{id} rename and a rename_connection tool on both assistant surfaces — renaming no longer means retyping credentials.

      • Trigger config_mode all replaces all_active. "Run every configuration" now fires one run carrying the flow's configuration-id list in trigger_source; the flow enumerates via App.configurations() (runtime 0.16.0) and matches payloads itself, failing loud on no match — the platform does no routing, and a webhook burst no longer fans out N sessions. Existing all_active triggers are converted by the migration (prod rollout pre-check: confirm none rely on the old N-session fan-out).

      • App.ensure_file(name) (runtime 0.18.0) — run-token-gated create-or-get of a file card on the running app, the file sibling of ensure_configuration. A setup wizard can now finish its own wiring: loonpro's save creates each administration's drop-box card, so the Files tab reads as the company list and the app page always has a card to upload to — no manual Files/Triggers steps, no triggers at all. Concurrency-safe get-or-create against the app+name unique (racing losers return the winner's row).

      • Session input integrity. set-input now merges field-wise into the node instead of replacing it — a partial submit (e.g. a page setting one flag) no longer amputates sibling fields mid-run; fixed on both the HTTP route and the assistant tool, which had drifted apart. The wizard's dirty-check compares values structurally (jsonb key reordering had pinned focus on mapping-grid steps forever), and file fields re-seed after a configuration pin replaces pending inputs (entering a wizard via an Edit link no longer strands Run on "required fields missing").

      • Wizards show every step again. The flow page parses steps from the Python source client-side; its regex required def immediately after @app.step(...), so a flow stacking any additional decorator (e.g. an error-handling wrapper) collapsed to a single visible step. The parser now tolerates stacked decorators — topology data was always correct, the display now matches it.

      • Declared config types — flat records (023 rev 7 Phase 1, runtime 0.19.0). A library declares a configuration type's schema once, in code (app.config_type("administration", fields=[...]) — statically extracted at deploy, like step fields; no secret kind, credentials stay in connections). Typed rows then store their values flat and once in app_configurations.record; every consuming flow's matching fields seed from it by name — wizard forms, pinned sessions, and trigger fires alike (the fire path explodes the record into node inputs via the flow's topology). ensure_configuration(values=...) writes it. The node-keyed parameters bag remains the untyped model and the per-field fallback — precedence is record-wins, never a merge — so existing apps and old runtimes are untouched; adoption is opt-in per type. First adopter: yuki-odoo 0.4.0, whose administration record went from three duplicated node slices to one flat record.

    • Migrations

      Seven, all applied to local dev; test/prod via supabase:db:migrate:<env> at release (pre-check: no all_active triggers on prod):

      • 20260823100000_typed_app_scope_configurations.sql — type column + flow-name backfill, (app, type, name) uniques, flows. default_configuration_id + dual-write trigger, flow_id demoted, runs_config/configures columns, projected/merged load/save/revert-session-configuration, all_active → all.
      • 20260823110000_pin_as_target_configurator.sql — ensure_configuration_for_run v3 (pin defaulting, name preserved, node-granular merge), get_run_pinned_configuration, target_configuration_id dropped.
      • 20260823120000_connection_edit_reroute.sql — get_run_target_connection (token-gated read backing the blank-keeps merge).
      • 20260824100000_ensure_file_for_run.sql — token-gated create-or-get of an app file card.
      • 20260824130000_ensure_file_for_run_fix_ambiguous_name.sql — the concurrency guard's ON CONFLICT column list collided with the RETURNS TABLE out-column name (42702, PL/pgSQL variable substitution); replaced with a unique_violation handler.
      • 20260824150000_config_type_records.sql — app_config_types schema registry (+RLS), app_configurations.record, p_record on ensure/save RPCs, record in the read RPC shapes, get_app_config_type + get_flow_topology_public for the anon fire path.
      • 20260824140000_trigger_ensure_typed_membership.sql — the trigger-ensure RPCs' configuration check goes from the legacy flow_id stamp to the typed selector rule, so one shared administration configuration can pin triggers on every flow that runs its type (first consumer: yuki-odoo 0.3.0).

Release Date: August 24th, 2026

 

4.0.22 ​2026 08 18


Release Notes - STML Version 4.0.22

Release Date: August 2026

  • Highlights

    • Named configurations from setup flows (platform/runtime 0.12.3 → 0.15.0 across this release). New App.ensure_configuration(flow_name, name, parameters, is_default=False, configuration_id=None) — the general form of ensure_default_configuration (now a thin wrapper). Setup wizards can keep several configurations side by side instead of ping-ponging one default: upsert is by (app, flow, name), or by exact row when configuration_id is passed (rename included), so re-configuring administration B can never touch administration A. is_default=False never demotes an existing default; rename collisions surface as a clean 409 (configuration_name_taken). The new ensure_configuration_for_run RPC also stamps app_configurations.editor_flow_id — which flow authors the row (NULL = the owning flow's own wizard) — so future app-level configuration lists can offer both "Run" and "Edit" without the user hunting for the right flow.

    • Triggers pinned to a configuration from the runtime. ensure_webhook_trigger / ensure_schedule_trigger gain configuration_id=: the trigger is created (or re-pinned in place, secret and URL preserved) with config_mode='single', giving each configuration its own webhook/schedule — one automation per administration instead of everything firing the flow's default. Deleting a configuration now deletes the triggers pinned to it (BEFORE-DELETE trigger); previously the FK's ON DELETE SET NULL collided with the single ⇒ configuration_id NOT NULL check constraint, making a pinned configuration effectively undeletable.

    • Pin-first trigger matching — human trigger names that survive renames (runtime 0.15.0). The trigger name doubled as the ensure calls' idempotency key, which forced wizard-managed triggers into slug-based names: renaming would have minted a duplicate while the old trigger kept firing. When configuration_id is given, the ensure helpers now match the trigger pinned to that configuration first — renaming (and re-timing/redirect-refreshing) it in place, secret preserved — with the name match kept as the fallback that adopts unpinned legacy triggers. So a setup flow can name triggers "scheduled sync — Bakkerij Jansen" and renames follow. Verified end-to-end: same trigger UUIDs across a rename.

    • App.delete_schedule_trigger(flow_name, trigger_name, configuration_id=None) (runtime 0.14.0) — the inverse of ensure_schedule_trigger, for wizards whose schedule choice includes "none": re-running setup with the schedule off now removes the schedule it created earlier instead of leaving it firing forever (there was no runtime trigger-delete at all). Idempotent ({deleted: bool}, missing trigger is not an error); the optional configuration pin finds the row even after a rename changed its name.

    • Searchable dropdowns in the flow wizard. Mapping-grid rows and any select field with more than 10 options swap the native <select> for a custom combobox (SearchableSelect.vue): substring search anywhere in the label, case- and diacritic-insensitive, identical behavior in every browser — native type-ahead only matches the label prefix and varies per browser, useless for finding an account by NAME when labels lead with the code. Arrow/Enter/Escape keyboard support; small lists keep the native control.

    • Platform assistant now steers Odoo writes through the sync engine. agent_instructions.md gained an explicit rule: steps that create or update Odoo records use sync_odoo with a declared (STEP_DECLARES-bound) mapping — idempotent keys, natural-key relation resolution, o2m building, preflight, duplicate-safe retries — with read_odoo for reads and execute_odoo only for non-write verbs; configurations store natural keys (codes/refs), never record ids.

    • Page SDK: multi-config app pages (020 M2 active bridge).

      • app.sessions.list({flow, configuration_id, status, limit}) — recent runs with status, first error line, configuration_id, and the published output map (headlines like "2 created, 0 skipped"), so a page renders per-configuration run history without session.get loops.
      • app.configurations.delete(flow, {id|slug|name}) — RLS-gated (owner/admin), pinned triggers cascade.
      • app.openFlow(flow, {seedInputs}) — prefill the target wizard's form (node-keyed, same shape as configuration parameters) via the flow-return ticket; the seed survives into session mode and each step still halts for review. This is how "Re-configure" opens the setup wizard with every step filled from a saved configuration of another flow — which the ?config= pin can't express. openFlow(flow, {configuration}) passes a same-flow pin through as ?config=.
    • resolve-connection failures are diagnosable. A run resolving a deleted/replaced connection got an opaque 500 (the 2026-08-11 incident's first symptom). Missing connections now 404 with a message naming the slug and the configuration that references it; unreadable stored credentials (half-created rows) 422 instead of crashing on decrypt.

  • Migrations

    Three, all applied to local dev; test/prod via supabase:db:migrate:<env> at release:

    • 20260812000000_multi_administration_config.sql — editor_flow_id column, ensure_configuration_for_run, both trigger-ensure RPCs re-created with p_configuration_id, pinned-trigger delete cascade, get_run_configuration_context.
    • 20260813000000_delete_trigger_for_run.sql — token-gated trigger delete (generic over trigger type; schedule is the consumer).
    • 20260813010000_trigger_ensure_pin_first.sql — pin-first matching in both ensure RPCs (rename in place, name match as legacy fallback); delete_trigger_for_run gains the optional pin match.
  • Added 2026-08-14 → 18 (same release)

    • Push reconciles library-dependency pins. stml push (and the /api/app-source/push route behind it) now re-resolves app_library_dependencies from the pushed pyproject.toml before the folded-in deploy, with the same conservative resolver install and update use. Previously a pushed manifest that added or re-ranged a library dependency left the pin table stale — the deploy bundle omitted the new library and the flow failed at import time until the operator added the dependency by hand (observed with xaf-to-odoo 0.5.0's new report dep). Resolution problems (e.g. issuer-ambiguous names) are reported in the push result, never fail the push. Regression-tested both ways.

    • Pages know their app version. The page bridge's init handshake now carries the app's pinned library (manifest) version, exposed to custom pages as app.info → { slug, name, version } — a page can print its release number without duplicating it into the page source. Scratch and detached apps report an empty version.

    • Odoo sync engine 0.1.31 — one2many child identity is overridable per scope, and a bugfix for FK-keyed parents whose o2m grouping could batch children under the wrong parent. Regression-tested in test_engine.py.

    • New connector library: GS1 Nederland (platform/gs1 0.1.0) — client-credentials OAuth and Basic Product Data retrieval, with unit tests plus an opt-in live sandbox suite.

    • Live library test runner — npm run test:libs:live executes @pytest.mark.live suites against external sandboxes, reading credentials from per-library gitignored .env files and skipping cleanly when absent.

Release Date: August 18th, 2026

 

4.0.21 ​2026 08 04


Release Notes - STML Version 4.0.21

Release Date: August 2026

  • Highlights

    • Odoo sync engine: real timeouts, duplicate-safe writes, faster o2m (platform/odoo 0.1.28 → 0.1.30). Three releases in one arc:

      • 0.1.28 cuts RPC overhead on one2many updates: child reads are batched per parent set instead of per row, and nested relationships are prefetched.
      • 0.1.29 makes x2many diffing honest: a new _is_x2m_commands helper and tightened _values_equal logic stop command-valued fields from diffing as "always changed", refining m2o/m2m/o2m reconciliation (with regression tests for m2m reloads).
      • 0.1.30 fixes a timeout hole that had been there all along: the legacy jsonrpc transport (every Odoo ≤ 18 connection) passed no timeout to httpx, so its 5-second default ruled every RPC — far shorter than a routine batch create, and the module's DEFAULT_TIMEOUT patch targeted a variable the pinned odoolib never reads. Surfaced in production as a 1,000-row product import crawling at 2 rows/s with ~800 false "barcode already assigned" errors. The transport is now re-wired per connection with phase-split timeouts: 10 s connect (dead servers fail fast), 30 s for idempotent read RPCs (the engine retries those), and the full author-set timeout (default 120 s) for creates/writes/arbitrary execute calls — on a write the client must outlast the server, because a timed-out create is not a failed create. Which is the second half of the fix: timed-out batch creates are never blindly re-sent; the engine re-matches by key and counts rows that already landed instead of duplicating them, and xml_id-keyed plans (unverifiable before ir.model.data registration) record explicit "outcome unknown" errors rather than gambling.
    • Dependency management no longer breaks for consumers outside the issuer org. Two production-observed failures in PUT /apps/{id}/dependencies (the Add dependency dialog replays the app's full dependency set through it): (1) a version yanked after an app pinned it blocked every later dependency edit — yank now follows the standard contract (blocks new pins, carry-forwards pass with a warning in the response); (2) issuer resolution did a direct organizations select, which org RLS hides from non-members — for any consumer org pinning e.g. an stml/… library this raised out of .single() as an unhandled 500 (reaching browsers as a CORS-less "NetworkError"). Resolution now goes through the same accessible_library_issuer_slugs SECDEF map the MCP tool path already used, and zero-row lookups return clean 400s.

    • App updates survive a flow module move. perform_update matched existing flow rows to the new manifest by entrypoint only, so a library version that moved a flow's module while keeping its name crashed the whole update on the flows_name_per_app constraint. Matching is now two-pass — entrypoint first across the full set, then a name fallback against unclaimed rows, updated in place including the new entrypoint — so the flow's id and slug are preserved and configurations, triggers, and sessions follow the move. Regression-tested for the move and the rename+move swap.

    • The Prefect worker no longer eats its own disk. Every flow run extracts its bundle into a per-run /tmp/stml4-run-* dir whose cleanup was registered via atexit — which multiprocessing children never run (they exit via os._exit()). One leaked bundle dir per run filled the infra host's disk twice in five days, taking flow execution down each time. Ownership is inverted: the worker parent creates the dir, passes it to the child, and deletes it after the child exits — covering crashes and SIGKILLed (wall-clock/rlimit) children — with a startup sweep of stale dirs as self-healing after a worker crash.

    • stml pull returns the complete source of attached apps (stml CLI 0.1.8). Pulling an attached app now merges the un-forked base library files (marked from_base) with the overlay — overlay wins per path — so the folder on disk is the app's real effective source, not just its fork delta. Pull also refreshes the stored manifest's exports block from the live flow rows, preserving authored content around it.

  • Changed

    • platform/report 0.1.5 — a row's final status now prioritizes write actions over validation severity, fixing a regression where incremental re-runs with warnings discolored rows that were in fact written; covered by new status-scenario tests.
    • runtime 0.12.3 — input-node halting refactored around _awaiting_input, distinguishing absent from empty submissions.
    • Session views track task states across runs — AppFlowView switches to the new useSessionTaskStates composable, aggregating live task states session-wide instead of per single run.
    • Uploads up to 100 MiB — the Supabase service-wide file size limit is raised to match the largest bucket limit (app-files), so large uploads are no longer silently rejected below the bucket's own cap.
  • Under the hood

    • BACKEND_URL is injected into the Scaleway environment and the infra compose now fails fast on a missing .env.
    • Assistant instructions require plain literals for declared lists/mappings so input panes render correctly.
    • Implementation plan committed for the stml_sync Odoo companion module (Phase B) and sync-engine throughput work.
    • Pytest configuration and automation refreshed across projects.
    • Frontend and dashboard versions bumped to 4.0.21.

Release Date: August 4th, 2026

 

4.0.19 ​2026 07 27


Release Notes - STML Version 4.0.19

Release Date: July 2026

  • Highlights

    • stml_report — a composable Excel report toolbox. New platform library (platform/report, import stml_report) that supersedes the report builders baked into stml_pipeline (0.3.4 keeps them as frozen shims for existing flows — new and customised reports depend on report directly). Three layers: blocks that take their data at construction and their environment at render, pages assembled with page(name, [blocks]) → save_workbook(target, pages) (target may be a path or io.BytesIO — no temp files), and the standard two-tab data-quality report as a recipe (dq_report). Customising means copying the recipe and editing the copy — there are deliberately no insert/replace/move methods and no post-processing of a written xlsx. Iterated to 0.1.4 within this window: a quality view that breaks down the validation results of excluded rows (0.1.3), and a coverage metric per attribute row with blank keys excluded from distinct counts and percentages (0.1.4).

    • The Odoo connector now works for restricted users on Odoo 19 (platform/odoo 0.1.27). The json2 protocol proxy mapped positional arguments to named parameters via the server's /doc-bearer introspection document — which stock Odoo 19 serves 403 to non-admin users (and which omits deprecated methods entirely). Net effect: every positional call failed for exactly the locked-down integration users the platform recommends. _Model and OdooClient now call kwargs-only (with ids= as the record-ids key; jsonrpc forwards kwargs to execute_kw unchanged, so one shape serves both protocols), backed by exhaustive protocol tests covering both jsonrpc and json2 behaviour.

    • Undeployed changes are now impossible to miss. An overlay write (set_app_source_file / set_flow_source / delete) is inert until deploy_flow — runs keep executing the previously deployed bundle while the Code view already shows the new source, the single most misleading state in app editing ("I added the rule but runs ignore it"). The frontend now detects it (new useUndeployedChanges composable) and shows an inline banner on the code view plus a sidebar badge on the app; MCP/chat tool responses append an explicit "not live until deploy" note to every source write, and the assistant's instructions require ending an editing session with a deploy or saying it deliberately didn't. Only page/ files are exempt — the app page serves live.

    • stml pull now always returns a publishable folder (stml CLI 0.1.7). A scratch app (and an attached app, whose manifest lives in the base library files rather than the overlay) has no pyproject.toml row, so its pulled folder couldn't go back through stml publish → install. The backend now synthesizes one from the platform's live state — provenance name/version/description when the app has a library origin, a scaffold from the display name otherwise — and the CLI labels generated manifests in its output. Pull → edit → publish now round-trips for every app shape.

  • Changed

    • platform/nmbrs 0.3.0 — journal entries from fetch_recent_journal_entries now carry run_date (the calendar date of the Nmbrs RunAt timestamp, or None — new parse_run_date helper, never guessed) alongside the period-end date. This lets consumer apps book payroll entries on the run date instead of the period end. Verified against the SOAP WSDL that Nmbrs provides no period dates at all (RunInfo's PeriodStart/PeriodEnd are period numbers), so the period-end computation stays — unchanged — and no period-start mode was added. The lib also gained its first unit tests (period math for monthly / 4-weekly / weekly, RunAt parsing).
    • stml init scaffolds a new library: src/ layout with a runnable example flow, tests, and a ready-to-publish pyproject.toml.
    • stml push no longer ships tests/ — test directories are excluded from the overlay like other local-only artifacts, matching what stml publish packaging already did.
  • Under the hood

    • Visual documentation added under docs/diagrams/: migration-app role-based access control and client-driven migration data flows.
    • uv.lock files are now committed (starting with cli/); virtual-env directories added to .gitignore.
    • The production demo Odoo compose mounts the OCA product_dimension module (parity with the demo images that gained it in 4.0.18).
    • Frontend and dashboard versions bumped to 4.0.19.

Release Date: July 27th, 2026

 

4.0.18 ​2026 07 24


Release Notes - STML Version 4.0.18

Release Date: July 2026

  • Highlights

    • Failures now lead with the message, not the noise. Persisted step, node, and run errors used to be head-clipped at 2000 characters — and a long (often chained) Python traceback puts the one line that matters, the exception message, at the end. A flow's carefully worded guardrail error could be entirely invisible in the UI, which showed three screens of frame noise cut off mid-line. The runtime (0.12.2) now clips the other way: the stored error opens with the exception message, followed by the traceback's tail (the deepest, relevant frames). Every surface benefits — session status, the wizard's task pane, and app pages — whether it shows the head or the last line of the stored error.

    • App pages can show real run history. New sessions.list bridge RPC in the page SDK: an app page can list its app's recent sessions — flow name, run number, status, timestamp, and the error's first line — under the same app-scoped, RLS-gated trust model as connections.list (ids never leave the parent; fields are display-safe). This replaces per-visit run logs that vanished on reload — and unlike a "flow writes a summary record" approach, it includes crashed runs, which never reach the step that would have written the record.

    • The CLI now refuses a backend it isn't logged in to. A cached stml session is minted by ONE backend; sending its token elsewhere yielded bare "Internal Server Error" responses — while stml whoami --backend … happily decoded the cached token and claimed a login that wasn't valid there. The CLI (0.1.6) now calls the mismatch out on every command with the exact login command to run. One session file means logging into another backend replaces the current session — the message says so.

    • App updates no longer trip over overlay residue, and keep your renames. Two fixes to the update path:

      • Overlay rows that are byte-identical to a shipped version's file are residue, not customisation — after an update they would silently pin the outgoing version's code over the new release. Update now detects them (sha-matched against both the outgoing and incoming tarballs, tolerant of the flat ↔ src/-wrapped layout ambiguity) and cleans them up, so a fork-then-update app actually gets the new code.
      • Flow display names follow a refresh-if-untouched policy on update: a row still carrying its default (the row name, or the previous manifest's title) picks up the new manifest title; a name you set yourself in flow settings is preserved — the manifest never clobbers a user rename.
  • Changed

    • App page & asset routes accept the app slug. The page-URL and static asset endpoints matched the app strictly by UUID; a slug — the identifier every external caller naturally holds — blew up in the id cast and surfaced as a 500. A shape-aware resolver now routes UUIDs and slugs alike (404 when neither matches), with bucket paths and page tokens always keyed on the canonical UUID.
    • Sessions sidebar shows the date. Session timestamps in the flow view rendered time-only, which made older sessions indistinguishable; they now include day and month.
  • Under the hood

    • Runtime 0.12.1 was a broken intermediate build (a mis-scoped helper left StatusWriter without its report methods — every run failed at startup); 0.12.2 supersedes it. Don't pin 0.12.1.
    • Demo Odoo images gain the OCA product_dimension module.
    • CLI build artifacts ignored in cli/; a generic migration-process diagram added under docs/diagrams/.
    • Frontend and dashboard versions bumped to 4.0.18.

Release Date: July 24th, 2026

 

4.0.17 ​2026 07 19


Release Notes - STML Version 4.0.17

Release Date: July 2026

  • Highlights

    • XAF → Odoo: mapping an administration is now a round-trip, not a one-shot. A new collect flow reads the chosen administration's chart of accounts and journals plus the source chart from the auditfile, and matches accounts in three passes — exact code, exact description, and AI only for the genuine remainder (the AI one-shot caps its list, so obvious matches never depend on it). The mapping grid, the saved configuration, and the import flow now agree end to end:

      • Your saved configuration is authoritative. Re-analyzing a saved administration restores every saved mapping untouched — AI suggestions only fill accounts the configuration doesn't cover, and accounts you already mapped are skipped by the matching passes entirely (including the slow AI call, so re-analysis is much faster).
      • Typed codes always save. Mapping an account to a code that doesn't exist in Odoo yet is a deliberate choice: it saves under your code and becomes a will-create account (red will create badge), instead of being silently dropped or replaced by a derived code.
      • Journal default accounts persist. The per-type default accounts (sales / purchase / bank) are stored in the configuration itself, so they survive the historical journals coming into existence — previously they vanished from the config after the first live run.
      • Your chosen configuration stays chosen. Opening a configuration to edit it no longer gets swapped for another configuration that happens to target the same company.
    • Dropped files survive the page. A file dropped on an app page now uploads into the app's file card immediately (a new version per drop) — nothing runs until you press Run, but the file is no longer lost when you navigate away (for example the connector-wizard round-trip, which destroys the page's browser memory). Coming back, the page restores the dropzone from the uploaded version and runs or analyzes against it — no re-drop needed.

  • Changed

    • Honest dropzone copy. The XAF import page now says the file uploads right away and survives navigation — the old "held in your browser" promise was exactly what made the connector round-trip lose it.
    • Mapping grid badges. Red rows now distinguish a deliberate will create mapping (code filled in, account created on import) from a truly unmapped one; rows stay red as long as the account doesn't exist in Odoo yet.
  • Under the hood

    • Pages can read their app's files. New app.files.list() in the page SDK (backed by a files.list bridge RPC): the app's file cards with latest-version metadata — never bytes — under the same app-scoped, RLS-gated trust model as connections.list. This is what powers the dropzone restore; degrade is graceful on older platforms.
    • The collect flow's analyze step takes a known_map (the configuration's account_map) and excludes those accounts from every matching pass; the import flow's configure step gains a journal_default_accounts field so the new config key round-trips, with a legacy fallback for configurations saved before this release.
    • XAF library records/mappings reworked for the consolidated historical journals + account-map translation, with the test suite extended to match.
    • Frontend and dashboard versions bumped to 4.0.17.

Release Date: July 20th, 2026

 

4.0.16 ​2026 07 18


Release Notes - STML Version 4.0.16

Release Date: July 2026

  • The stml partner CLI. You can now work on apps from your own machine with a command-line tool. stml pull <app> downloads an app's source into a folder, you edit it in your own editor, and stml push sends it back and redeploys. stml publish releases a library, stml init scaffolds a new one, and stml login signs you in through the browser — no API keys to hand around. Install it with pipx install stml-cli; it defaults to production and talks to the platform over the same JWT-authenticated endpoints the assistant uses. stml list shows every app you can reach — with its organization, workspace, mode, and the exact URL you pull/push by — so two apps with the same name are easy to tell apart.

  • Apps now have a lifecycle: attached · detached · scratch. Every app has a mode. An app installed from a library is attached — pinned to a version, deploying the library plus your overlay, and able to take library updates. stml detach (or the platform) forks it into a detached, self-contained copy you fully own: the whole source is materialised and the library pin dropped. stml revert goes the other way — it discards your changes and restores the clean library version, or re-attaches a detached app to the version it forked from. Reverting is destructive, so it names the target and confirms first. Apps built from nothing are scratch. stml status and stml list show the mode.

  • Yuki: inbound purchase-invoice & payment testing. New tooling to exercise inbound payment workflows end to end — generate test bank slips, sync open invoices, and simulate partial payments — with PurchaseInvoices.xsd validation and explicit precision handling. The Yuki connector also moved into a shared platform/yuki-api library, so the Odoo app and its test flows run off a single implementation.

Changed

  • The App Store leads with apps. An organization's App Store now defaults to browsing apps rather than connectors.
  • Save a configuration from a page. App pages can persist or update a flow's configuration directly through the page SDK (configurations.save).
  • Activity ledger. Adds a CSV export and shows the most recent 10 entries.
  • Odoo 19 demo image. A custom image bundling python3-xmlsec so NL accounting (l10n_nl_reports) works on the demo servers.

Under the hood

  • App detach/revert lifecycle (035) ships with full test coverage, backed by a new in-memory Supabase fake that exercises the attached → detached → attached state transitions.
  • CLI distribution. stml-cli publishes to PyPI through a manual, keyboard-only flow (npm run cli:release); the PyPI token lives in the macOS keychain (npm run cli:login), the package version derives from a single __version__, and npm run cli:update upgrades a local install. stml pull now also fetches binary assets and enforces the packaged src/ layout.
  • scripts/stml_lib.py retired — the stml CLI (stml_cli.packaging) is now the single implementation for building library tarballs.
  • New architecture diagram documenting the app-authoring model (stores, operations, actors) under docs/diagrams/.
  • Frontend and dashboard versions bumped to 4.0.16.

Release Date: July 18th, 2026

 

4.0.15 ​2026 07 17


Release Notes - STML Version 4.0.15

Release Date: July 2026

Highlights

  • Safer destructive assistant tools. Deleting things through the assistant is now guarded. delete_organization no longer deletes at all — organization removal isn't offered through the assistant; the tool just resolves the org and hands back the archive link (Organization → Settings), a password-gated soft-delete with a 30-day grace window. delete_flow and delete_configuration are clearly marked destructive and irreversible: the assistant must name the exact target and confirm first, and will never delete something inferred from an ambiguous request. (Deleting a flow keeps its source file in app_source_files, so it can be recreated — delete that file separately for a fully clean tree.)

  • The chat follows the conversation. The assistant panel now sticky-scrolls while a reply streams in: if you're at the bottom it keeps new content in view, but if you've scrolled up to read it no longer yanks you back down. Reloading or reopening the panel lands you on the newest message.

Changed

  • delete_flow / delete_configuration descriptions now spell out the irreversibility, the confirm-and-name-the-target requirement, and (for flows) that the retained source file must be removed separately for a fully clean tree. Configuration deletes note that pinned sessions lose their pin but keep their copied inputs.
  • delete_organization is advisory only — it never mutates; calling it returns archive guidance the assistant can relay directly. Assistant instructions were updated to match.

Under the hood

  • New test_tool_schemas coverage asserts the delete tools signal their destructiveness (tool descriptions + input-schema wording), so the safety framing can't silently regress.
  • Frontend and dashboard versions bumped to 4.0.15.

Release Date: July 17th, 2026

 

4.0.14 ​2026 07 16


Release Notes - STML Version 4.0.14

Release Date: July 2026

Highlights

  • CPQ configurator for Odoo. A new stml/cpq-odoo library turns Odoo into a guided quote configurator. A catalog step expands a product catalogue with brand/chassis compatibility, discount tiers and product-specific overrides; an interactive configurator front page walks a salesperson through the options with live business-rule validation; and a create-quote flow writes the result back into Odoo as a sale order. Ships with seed / prepare / create-quote flows and a full rules test suite. (User story docs/user-stories/solution/010-cpq-configurator-for-odoo.md.)

  • app.output.read — uncapped bulk outputs on the page. Task output and the records ledger stay capped (64 KB / 500 rows) so the live feed stays cheap. A flow that produces a large dataset now writes it to a named output file (app.output(slug).put(...)), and a front page reads the whole thing with await app.output.read('catalog') — parsed JSON by default, or { as: 'text' } for raw. Every read is authenticated and audit-logged, and a page can only reach its own app's outputs. This is what lets the CPQ page load a full product catalogue client-side.

  • Connections are app-scoped. Connection management moved from workspace scope to app scope — list_connections, test_connection, edit_connection, delete_connection and friends now take app_name instead of workspace_name, so each app owns and manages its own connections. Assistant instructions and tool input schemas were updated to match.

  • The assistant builds interactive front pages for real. The agent now knows the app-page SDK (import { app } from '/sdk/v1.js'): it wires a page's buttons to actually run flows (app.session.create / run), stream live per-step output (app.on('update')) and show run activity — including background/webhook runs (app.on('activity')) — instead of treating pages as render-only and simulating a run. It also has clearer guidance on filling flow inputs by node/field rather than misusing listeners.

Added

  • Yuki connection testing + auto-discovery. A dedicated Yuki connection-test flow validates credentials from the UI and auto-discovers the administration during setup, and invoice XML is now validated against a bundled SalesInvoices.xsd schema. Flow records switched from data to payload. Libraries stml/yuki-odoo and stml/yuki-api updated.
  • Fan-out field mappings. Odoo mappings accept a list-of-pairs fields form so one source column can populate several non-key targets, with stricter validation that rejects multiple identifying targets and ambiguous explicit keys.
  • Short-ID conversation lookup on /mcp/admin. Admin conversation search and retrieval now accept an 8-character ID prefix alongside a full UUID or slug, with disambiguation when prefixes overlap (migration 20260714000000_admin_conversation_short_id).
  • Redis health in the detailed health endpoint, so a degraded Redis (Streams / assistant worker) shows up in diagnostics instead of surfacing only as a downstream failure.

Changed

  • Connection tool signatures take app_name, not workspace_name (see Highlights) — the one breaking change for anything driving the connection tools directly.
  • Stricter App runtime validation. Invalid @app.step / interface usage fails fast with clearer error hints, backed by new flow-lint and tool-schema tests.

Fixed

  • Background runs could fail with a name-resolution error. PREFECT_API_URL is now set explicitly in the compose files for the scheduler and agent-worker. Without it, schedule- and webhook-fired runs (and the agent's deploy_flow / run-status calls) fell back to the dev orb.local default and failed to resolve the Prefect API. Service dependencies were also tightened for startup stability.

Under the hood

  • New tests across the board: runtime app interface, flow linting, connection step resolution, publish layout, connector test-flow export/pairing, and shared-source-column mappings.
  • _exports_toml_from_flows now recognises connector helper flows, so test/introspect pairing and flow recreation on install stay accurate.
  • 2BA UniFeed pricing/end-dating framing clarified (gross-only pricing; in-app net price calculation deferred) for the OCS demo.
  • Frontend and dashboard versions bumped to 4.0.14.

Release Date: July 16th, 2026

 

4.0.13 ​2026 07 15


Release Notes - STML Version 4.0.13

Release Date: July 2026

Changes since 4.0.12 (the 4.0.13 version bump was internal and is folded in here).

Release Date: July 15th, 2026

 

4.0.12 ​2026 07 13


Release Notes - STML Version 4.0.12

Release Date: July 2026

Highlights

  • Yuki ↔ Odoo, end to end. A new stml/yuki client library speaks Yuki's SOAP API (WSDL-based session handling against api.yukiworks.nl), and a reusable stml4 app ships flows for invoices and payments. A one-shot setup flow provisions the whole integration in a single run: default configurations, the x_yuki_* custom fields on the Odoo side, triggers, schedules and an automation rule. Documented as a user story (docs/user-stories), built for VDH.

  • Scheduling moved to its own always-on worker. Cron ticks no longer depend on a scale-to-zero backend happening to be awake: a dedicated scheduler container fires schedules reliably, single-instance, with at-most-once execution — the inline scheduler is gone. Schedule-fired and webhook-fired runs now also resolve their configuration mode identically, via a shared _fire_trigger_with_config_mode helper, so the same trigger behaves the same regardless of what fired it.

  • Worker dependencies are baked, not pulled. Deploy-time pip install is removed everywhere; every third-party package a flow needs ships pre-baked in the worker image (lxml and requests joined for SOAP support). Deploys get faster and deterministic, and a flow can no longer crash mid-run on a module the image never had.

  • Redeploying a flow resets its stale sessions — everywhere. public.flows is now published over Supabase Realtime, so the flow view auto-resets open sessions the moment a new version deploys. The assistant path does the same (stale sessions cleared, deployed_at stamped), so neither chat nor UI can keep driving a wizard from a version that no longer exists.

Added

  • 2BA imports you can watch. Every imported record and image now carries a detailed status, a live activity feed shows progress on the app page, and a finalize step closes out the run. The importer also feature-detects the per-supplier UoM field across Odoo generations (product_uom ≤16, product_uom_id 17/18, gone in 19) so a write never references a column the target lacks. Library stml/2ba 0.3.5.
  • Triggers are editable in place. The app triggers view reuses the create dialog for updates — no more delete-and-recreate to change a trigger.
  • A first-class Connection handle in the runtime. app.connection(slug) returns an opaque, dict-compatible handle carrying the connection's stable identity (slug, connector) alongside the decrypted parameters, with slug-based caching and a repr that redacts secret-looking values so logging a connection can't leak an API key. Fully covered by new tests.
  • Sessions idle out after 8 hours by default, with warning limits derived from the timeout — plus a dev-only override to disable idle logout locally.
  • deploy:agent commands — scoped agent-worker redeploys that stay aligned with the backend image tag.

Changed

  • Odoo helpers no longer accept a bare slug string. read_odoo, sync_odoo and friends require the resolved object from app.connection(slug); passing a slug now fails fast with a message that says exactly that, instead of failing obscurely downstream.

Fixed

  • 2BA supplier creation on Odoo 19. New suppliers are created with is_company: true instead of the computed company_type field, which Odoo 19's JSON-2 endpoint rejects (older endpoints tolerated the indirection). Same end state on every supported Odoo version.

Under the hood

  • Prefect worker requirements gained lxml and requests (SOAP transport) under the bake-only dependency policy.
  • Frontend and dashboard versions bumped to 4.0.12.

Release Date: July 13th, 2026

 

4.0.11 ​2026 07 11


Release Notes - STML Version 4.0.11

Release Date: July 2026

Highlights

  • From "read the platform" to "find the pain" — client friction analysis. The Admin Analytics MCP (/mcp/admin) grows a whole insight layer on top of last release's read tools. Every conversation is distilled into a conversation_insight row, and the ones where the interaction met resistance — a failed flow, a tool error, friction language, or the user trailing off unanswered — are flagged with the verbatim failed tool return as evidence, so the fix is usually visible without opening the transcript. admin_client_friction rolls this up per client (organization) with a transparent, weighted score and each org's most-recurring errors; admin_list_friction_conversations is the conversation-level shortlist. All heuristic for now (no LLM), and every signal is explainable. Operator guide: docs/runbooks/admin-analytics-mcp.md.

  • Assistant turns now run on a dedicated async worker. The in-browser assistant no longer executes its turn inline on the request path. A dedicated agent loop and worker process turns off a Redis queue, with tool-result caching, usage logging, resource-cap enforcement and mid-turn cancellation checks. The visible payoff is a chat that stays responsive on long, many-tool turns instead of stalling.

Added

  • admin_find_user — resolve a person from a UUID, email, or display-name fragment. Emails are unique; display names are not, so it returns all candidates ranked by match quality and never silently picks one. Every curated result now also carries user_email / user_display_name next to the raw user_id.
  • Sharper conversation reads. admin_get_conversation is now lean by default (tool-call names only, per-message character cap, paging) so a transcript no longer costs a token flood, and admin_search_messages adds full-text search across message content — the needle-finder that skips downloading whole transcripts.
  • Insights refresh themselves. A turn-end lifecycle trigger recomputes a conversation's insight automatically, so the friction view keeps up with live chat instead of waiting for a manual recompute pass.
  • 2BA UniFeed — daily supplier-price refresh. A new flow refreshes 2BA supplier prices on a schedule, with unit-of-measure resolution, WP4 import logic, a template identity key and fallback tagging — plus test coverage for unit resolution, pricing rules and import idempotency.
  • Org admins can self-manage workspace access. From the organization members screen, an owner/admin can grant a member access to any workspace and revoke it from the workspace pills — including on their own row. Workspace names (not slugs) now show in the members list.
  • OAuth-powered trigger redirects. A new /redirect handler returns a 302 into an authenticated destination, backed by the get_trigger_redirect_context lookup. Runtime bumped to 0.12.0.
  • File new tickets from the ticket skill. A create command drafts a ticket (review before send), with tags, customer linking and team priority.

Changed

  • Workspace access is less rigid for org admins. The "no self-add" rule and the "can't remove the last admin" guard are both waived for org owners/admins — they hold authority over every workspace in their org and can re-appoint an admin at any time, so the guards were friction, not protection. Both rules stay in force for plain workspace admins.
  • "Copy link" works in Chrome on custom app pages. Sandboxed app-page iframes are now granted clipboard-write.

Fixed

  • Stale-migration collision in the e2e reset. The isolated e2e stack now prunes its migration folder before refreshing it, so a migration renamed or renumbered in the repo can no longer leave a duplicate behind and make migration up re-apply an applied version.

Under the hood

  • The insight layer runs as a dedicated insights_rw role via gated, SECURITY-DEFINER RPCs; friction vocabulary replaced the earlier "attention" naming across schema, RPCs and tools; cross-client error-pattern views back the triage tools. All behind the same platform-admin gate and audit trail as the rest of /mcp/admin.
  • supabase.sh migrate:up accepts extra pass-through arguments for local migrations.
  • New infra:agent:rebuild script stages legal docs and rebuilds the agent-worker container.
  • Frontend and dashboard versions bumped to 4.0.11.

Release Date: July 11th, 2026

 

4.0.10 ​2026 07 09


Release Notes - STML Version 4.0.10

Release Date: July 2026

Highlights

  • Admin Analytics MCP. Platform operators can now point Claude (or any MCP client) at a dedicated admin surface — /mcp/admin — and analyse the live platform in plain language: search any user's assistant conversations, read a transcript, inspect a run or session, list runs stuck past a threshold, or ask the long-tail question with one ad-hoc read-only SQL statement. The surface is read-only by construction: queries execute as a dedicated database role with an explicit SELECT allow-list, so writes, DDL and credential columns fail with a permission error rather than a policy promise. Only accounts with the platform-admin role get in (403 for everyone else, checked again inside every RPC), and every call — including each SQL statement verbatim — lands in the admin audit log under the operator's identity. Operator guide: docs/runbooks/admin-analytics-mcp.md.

Added

  • The consent screen now says which surface you're authorizing. The admin endpoint advertises its own OAuth resource, so the authorize page shows a platform-admin banner (cross-tenant read access, everything audited) instead of the generic prompt, plus a Surface row with the exact URL — a built-in check against confusing environments or elevations. A non-admin authorizing the admin URL is told up front their account lacks the role: they may still approve, and the connection starts working automatically if the role is granted later.

Changed

  • Smoother wizard inputs. Submitting a step now gives immediate feedback — a spinner, dimmed fields and disabled controls while the run is in flight — and the Run button distinguishes a fresh start from a resume.

Fixed

  • Wizard focus no longer bounces. Input nodes queue as pending instead of being marked completed, so focus stays where it belongs while a run advances.
  • SUPABASE_URL fallback now uses the configured constant instead of a hardcoded localhost URL.

Under the hood

  • Dev reset tooling: per-database module lists, Accounting app seeding moved into reset_db, clearer logging.
  • Two new migrations back the admin surface: curated analytics RPCs and the admin_analytics_ro role + admin_sql function.
  • Frontend and dashboard versions bumped to 4.0.10.

Release Date: July 9th, 2026

 

4.0.9 ​2026 07 08


Release Notes - STML Version 4.0.9

Release Date: July 2026

Highlights

  • XAF → Odoo import, revamped. The auditfile import gets a guided front page: pick an existing Odoo connection (or create one) from a dropdown, then drop the XAF into a live drop zone that shows upload and per-stage progress as the six import stages light up. Imports are tied to the connection you choose, so one app can target different Odoo instances.

Changed

  • Auditfile lines no longer merge. Each transaction line is imported as its own journal line (via a per-line sequence), so lines within a single account.move entry stay distinct instead of collapsing together.

Fixed

  • Multi-flow apps resolve the right default configuration. The default lookup is now scoped by flow, so an app with several flows no longer picks an arbitrary flow's default — and webhook triggers resolve the correct one.
  • Concurrent deploys no longer race. Worker run directories are isolated per run, preventing races when several deployments run at once.

Under the hood

  • Reader-facing release notes for 4.0.1–4.0.8 added under docs/release-notes/.
  • Platform library version bump: xaf-to-odoo 0.1.6.
  • Frontend and dashboard versions bumped to 4.0.9.

Release Date: July 8th, 2026

 

4.0.8 ​2026 07 08


Release Notes - STML Version 4.0.8

Release Date: July 2026

Highlights

  • XAF auditfile → Odoo import. A new solution app imports a Dutch XAF 3.2 auditfile — plain or compressed (.xac zip / .gz) — into Odoo across nine steps: chart of accounts, VAT codes & journals, customers & suppliers, the opening balance, and every transaction, posted as balanced account.move entries. It proves the file balances (debit = credit) and that its references resolve before it writes anything, ships a hero front page with a drop zone and live per-entity progress, and produces a downloadable Excel report. Composed from a new stml/xaf reader library plus stml/pipeline and stml/odoo.

  • on_match write policy for the Odoo sync engine. A mapping can now say what happens when a source row matches an existing record — on_match: update | skip | error — on top of the existing mode. {"mode": "insert", "on_match": "skip"} is INSERT … ON CONFLICT DO NOTHING: create new rows, quietly skip existing ones, for idempotent create-once loads (e.g. immutable posted journal entries). insert on its own still errors on a duplicate.

  • App-level live records feed. Apps gain a real-time ledger — a records API, an export endpoint, and activity subscriptions — so a custom front page can stream synced items as they happen and download the full history as CSV.

Added

  • stml/xaf — a pure, streaming, dependency-free reader for Dutch XAF 3.2 auditfiles (auto-detecting plain / gzip / .xac zip) plus the structural integrity checks XAF guarantees (balanced transactions, matching totals, referential integrity, dates within the year).
  • Yuki ↔ Odoo demo — a front page with a live sync log and CSV export, with the Yuki mock added to the production demo stack.
  • Nmbrs → Odoo — invoice date stamping, with refined journal and account language handling.

Changed

  • CSV exports are capped at 50,000 rows and warn when the range is truncated.
  • App page content is centered by default inside the iframe.
  • Nmbrs 0.2.0 — strict fiscal-period validation with clearer error handling and logging for undated financial periods.
  • Payroll sync scrolls the progress card into view so live steps stay visible.
  • The help-tour beacon uses a limited "ping" instead of an infinite pulse (accessibility).

Under the hood

  • Platform library version bumps: odoo 0.1.26 (on_match), xaf 0.1.0 (new), xaf-to-odoo 0.1.2, nmbrs 0.2.0, runtime 0.11.0 (live records).
  • Frontend and dashboard versions bumped to 4.0.8.

Release Date: July 8th, 2026

 

4.0.7 ​2026 07 06


Release Notes - STML Version 4.0.7

Release Date: July 2026

Highlights

  • Centraal Boekhuis → Odoo integration. A new stml/cb connector library and demo import book data from Centraal Boekhuis into Odoo, backed by a cb-mock service that stands in for the real webservice. The cb-import flow publishes inline per-book results as it runs and produces a downloadable Excel summary.
  • Hardened Odoo connector. API-key authentication, conditional field visibility (visible_if) with auto-advance, richer input validation and field descriptions, and whitespace trimming on entered values to stop copy-paste artifacts from breaking logins. Non-sensitive fields are now surfaced in step outputs.
  • Odoo Helpdesk ticket skill. Triage, reply to, and manage support tickets directly from the assistant.

Added

  • stml/cb — Centraal Boekhuis connector library + Odoo demo, with a cb-mock stand-in service for the CB webservice.
  • Downloadable Excel report step for the cb-import flow, plus inline per-book results published during the import.
  • API-key authentication for the Odoo connector.
  • visible_if conditional field visibility and auto-advance in the task pane.
  • allow_custom and placeholder passthrough in the flow parser and renderer.
  • Odoo Helpdesk ticket skill for triaging, replying, and managing tickets.
  • Wall-clock as a configurable per-run resource cap.
  • External-user proof-of-concept for Odoo portal integration.
  • Smoketest scenarios and documentation for platform validation.

Changed

  • The Odoo connector trims whitespace from username / password (and guidance now emphasizes trimming all user-entered values) to prevent copy-paste login failures.
  • Non-sensitive Odoo fields are surfaced in task step outputs (security review).
  • The task pane uses a generic tone in place of the domain-specific severity.
  • Simplified the flow-level declares structure.
  • Reachability fallback for containerized workers, with unit tests.
  • The dashboard /users view navigates via SPA routing.
  • Custom app pages: the active bridge is enabled in production for the flowers-to-odoo pilot (behind VITE_APP_PAGE_ACTIVE_BRIDGE).
  • More robust CSV parsing in the spreadsheet library.

Under the hood

  • Platform library version bumps: odoo 0.1.25 (API key, visible_if), spreadsheet 0.1.2, parts-onboarding 0.2.0, pipeline 0.3.3.
  • Frontend and dashboard versions bumped to 4.0.7.

Release Date: July 6th, 2026

 

4.0.6 ​2026 07 02


Release Notes - STML Version 4.0.6

Release Date: July 2026


Highlights

  • Nmbrs → Odoo payroll sync. A new nmbrs connector (Nmbrs SOAP API) plus a nmbrs-to-odoo app that syncs payroll journals into Odoo automatically.
  • AI-assisted field mapping. Mapping fields can now draw from dynamic sources and suggest defaults via AI, backed by new AI-matching endpoints with token metering — so a flow can propose account / analytic matches without an API key in the flow itself.
  • set-images flow. Fetches and updates product main images in Odoo, with live result publishing surfaced in the frontend.

Added

  • nmbrs — connector library for the Nmbrs SOAP API (v3).
  • nmbrs-to-odoo — app for automated payroll journal syncing into Odoo.
  • set-images flow — fetch and update product main images in Odoo, with live result publishing and frontend integration.
  • AI-matching endpoints for runtime use, with token metering.
  • Mapping fields with dynamic sources and AI-based default suggestions.
  • Connector filtering, and flow-name resolution by ID.

Fixed

  • Platform connector publishing — RLS policies updated to support platform-admin authentication.

Under the hood

  • Runtime bumped to 0.9.0.
  • Frontend and dashboard versions bumped to 4.0.6.

Release Date: July 2nd, 2026

 

4.0.5 ​2026 07 02


Release Notes - STML Version 4.0.5

Release Date: July 2026


Maintenance release. 

  • Maintenance release. Frontend and dashboard versions bumped to 4.0.5, tagged shortly after 4.0.4 — no functional changes.

Release Date: July 2nd, 2026

 

4.0.4 ​2026 06 30


Release Notes - STML Version 4.0.4

Release Date: June 2026


Fixed

  • Multi-flow apps can now be run from the AI assistant. create_session, session_step, session_run, and session_rerun accept a flow_name; when an app has several flows and none is given, the assistant returns a clear "specify which flow" message instead of a cryptic Tool error: 'session_number'.
  • Reject broken Python library tarballs missing the src/ layout at publish time.
  • More informative error reporting for edge/block errors in the admin users list.

Added

  • Partner Data Quality app — a graded spreadsheet workflow.
  • Admin conversations view — browse assistant conversations from the dashboard, with a backend API.
  • Centralized auth-error handling for API calls.
  • Enterprise mode for the Odoo 19 production demo.

Changed

  • Clarified the signup-confirmation email copy (states its purpose; "ignore if it wasn't you").
  • Webhook URLs resolve via public_backend_url (retired the PUBLIC_BACKEND_URL alias).
  • License views hide libraries that have no installable versions.
  • Removed the "forked" provenance chip from the workspace apps view.
  • Raised the Scaleway chat-agent container timeout 60s → 300s (interim, pending the durable worker).
  • Platform library version bumps: flowers-to-odoo, partner-data-quality, invoices-to-odoo, spreadsheet 0.1.1, pipeline 0.3.2.

Removed

  • Retired the deprecated 2BA and excel-to-odoo libraries (added a new 2BA setup page + assets).

Internal

  • New technical user stories: durable chat-agent worker architecture, deployment latency improvements.
  • AGENTS.md documentation for the platform libraries.

Release Date: june 30th, 2026

 

4.0.3 ​2026 06 28


Release Notes - STML Version 4.0.3

Release Date: June 2026


Highlights

  • Admin yank / un-yank of published library versions (RPC + tool + UI), plus a "Show yanked" toggle.
  • New invoices-to-odoo flow (import + transform spreadsheets into Odoo) with a data-quality report download.
  • Live connection schema introspection (inspect_connection_schema) with Redis-backed caching and prefetch on connection-test success.
  • Richer Odoo sync: one2many / many2many with configurable on_extra policies and nested-relation auto-create.
  • Block now revokes the user's session immediately (cascade auth.sessions delete from the is_blocked trigger).
  • Custom app pages: VITE_APP_PAGE_ACTIVE_BRIDGE enabled in prod for the flowers-to-odoo pilot.

Release Date: june 28th, 2026

 

4.0.2 ​2026 06 25


Release Notes - STML Version 4.0.2

Release Date: June 2026


Highlights

  • Custom app front pages rendered in a sandboxed iframe, with the active-bridge phases (page → session/files hand-off) and the "Flowers → Odoo" reference page + assets.
  • Guided product tours and a help beacon.
  • Library tarballs split into lean code vs binary assets; license library bundles made mutable post-mint.
  • Responsive sidebar and a floating menu button for mobile navigation.
  • Larger chat token budgets (16K streaming / 32K non-streaming) to prevent truncation.

Release Date: june 25th, 2026

 

4.0.1 ​2026 06 23


Release Notes - STML Version 4.0.1

Release Date: June 2026

The first release of the STML4 4.x line, and the starting point for these release notes.

What's New

Agenetic loop

Generate with AI instead of hand coding

MCP

Bring your own AI, want to use self hosted, self procured LLM's as long as your LLm of choice supports the MCP we are good to go.

App based

Phone style App's where you can do almost all on a single attractive screen. Our wizards will guide you through the setup steps of your connections and absolve you from the difficult configuration work. Get results quickly and robustly!

App Store

Look for a solution, install, configure and run. sounds easy, now it is.

Want to publish a app you build to share or sell it to the world, you can.


Supported Integrations

  • Odoo (15.x, 19.x) — full read/write with metadata discovery
  • Nmbrs — payroll data synchronization
  • Generic REST APIs — via configurable connection profiles
  • Custom systems — write Python tasks, push to Git, and they appear in the task library

Domain-specific packs available for 2BA, Tuindeco, Twinfield, Valbo, HiveCPQ, and BigQuery, Exact, Yuki.

Release Date: April 2nd, 2026

 

The release notes apply to all versions of STML

  • Cloud
  • Dedicated
  • Private (ofcourse only if you deploy)