Back to Updates

Platform Updates — May 2026

ibl.ai EngineeringMay 31, 2026
Application

65 production image releases (1.7.3 → 1.25.0): field-level credential encryption, a full CRM domain, tiered chat-privacy controls, LiveKit voice call agents, an LLM-as-Judge evaluation surface, and Microsoft SSO in the provisioning CLI.

Production image releases 1.7.31.25.0 (65 releases, May 2026).

serviceimage / pinversion span
dmiblai-dm-pro4.243.24.266.0-ai
osiblai-os-spa0.58.10.70.0
lmsiblai-lms-spa0.20.00.35.0
edxiblai-edx-prosumac.2.16.2sumac.2.30.13
cliiblai/infra-cli1.5.41.10.1

iblai-dm-pro4.243.24.266.0-ai

Credential encryption and sensitivity-aware access. The Data Manager gained field-level encryption for every sensitive credential model — LLMCredential, GlobalCredential, IntegrationCredential, ConnectedService, MCPServer, and MCPServerConnection now carry encrypted shadow fields backed by new EncryptedTextField, EncryptedJSONField, and EncryptedFieldsMixin primitives in dl-core-app (Fernet symmetric encryption). Transparent secure_* properties and updated get_cred()/aget_cred() utilities read through the encryption, and lifecycle management commands (backfill_encrypted_fields, verify_encrypted_fields, cleanup_plaintext_fields) handle migration. Django admin now masks both plaintext and encrypted credential fields, gated by a new MASK_CREDENTIALS GlobalConfiguration setting (default True).

Integration-credential schema V2. Integration credentials moved to a sensitivity-aware model: students see only drive/dropbox/onedrive credentials with sensitive fields stripped, while admins see all credentials with sensitive values masked (e.g. G*****). A new FK from IntegrationCredential to IntegrationCredentialSchema drives per-field sensitivity via a V2 schema format carrying is_sensitive metadata, with V1 backward-compatibility retained. Phase 2 cleanup (0321_convert_credential_schema_to_v2_and_backfill_fk) rewrites every schema row to the V2 shape and makes sensitivity fail-closed — when the FK is missing or the schema isn't V2, every field is treated as sensitive. The legacy V1 schema endpoint now returns Deprecation: true and an RFC 8594 Link: …; rel="successor-version" header.

Voice and LiveKit call agents. voice_provider, google_voice, and openai_voice became read/write on the agent settings endpoints (POST /mentor-with-settings/, PUT /mentor//settings/), accepting openai or google. LiveKit call agents now receive the agent's configured Langchain tools through a new CallAgentToolFetcher that reuses the chat-side BaseAgentToolFetcher pipeline (tool-matrix gating, output sanitization, MCP OAuth + retries, rate limits) for both inference (separate STT/LLM/TTS) and realtime sessions; clients subscribe to the "tool" data-channel topic to receive OAuth prompts and rate-limit notices during a call. The deprecated gemini-2.0-flash-exp was retired from call paths in favor of gemini-2.5-flash-native-audio-preview-12-2025 (realtime) and gemini-2.5-flash (inference), alongside a livekit-agents 1.3.10 → 1.5.11 dependency bump.

CRM domain, RBAC, and notifications. A full CRM domain landed in ibl-dm-crm-app — Platform-scoped Pipeline, PipelineStage, LeadSource, Deal, Activity, and Tag models with a row-locked deal state machine (move_deal_to_stage, mark_won, mark_lost) that serializes concurrent transitions under select_for_update(), writes an audit Activity per move, and dispatches deal_stage_changed/deal_won/deal_lost events. Deal.status and Deal.closed_at are service-managed (read-only via the API, derived from stage is_won/is_lost flags), and REST endpoints cover pipelines/, nested stages/, lead-sources/, deals/, deals/{id}/move-stage/, and activities/. A new Ibl.CRM/* RBAC namespace seeds four policies per platform (CRM Viewer, CRM User, CRM Manager, CRM Inviter), and Person/Organization endpoints resolve platform scope from the auth token via a shared BaseCRMMixin. Three notification types (CRM_PERSON_CREATED, CRM_DEAL_STAGE_CHANGED, CRM_PERSON_LINKED_TO_USER) ship with a new RecipientsConfig routing dataclass whose modes (platform_admins_only, object_owner_only, platform_admins_and_object_owner, custom) are filtered by active UserPlatformLink so notifications can't leak cross-tenant.

Tiered chat-privacy controls. A strict four-tier privacy hierarchy (agent → tenant gate → session → user → default) is now enforced by a single pure resolver in ibl_ai_mentor/services/chat_privacy.py, where each lower tier can only further restrict history. A new Session.disable_chathistory field lets sessions be created already-private; a one-way mid-session toggle endpoint (POST …/sessions/{session_id}/disable-chathistory/) nulls Session.student when flipped on and rejects re-enabling with 400; and GET …/chat-privacy-effective/ returns { mode, source, is_locked }. In DISABLED mode no rows are written or surfaced for LLM context. A separate fix to IBLChatMessageHistory.preprocess_message replaced the substring page-content stripper with a non-greedy re.DOTALL regex per envelope and added context-metadata (METADATA_PREFIX/METADATA_SUFFIX) stripping, closing a customer-visible leak where the metadata envelope was persisted verbatim into chat history.

Evaluation, observability, and the LLM registry. Evaluation API responses became frontend-grid-friendly — dataset items expose trace_input/trace_output, experiment detail embeds input/expected_output/actual_output/trace_id/scores per run item, and a new local EvaluationTaskRecord table surfaces pending/in-progress Celery tasks with a full status lifecycle. New LLM-as-Judge list endpoints (…/evaluate/, …/judges/) were added, and read paths now hit Langfuse's Postgres and ClickHouse directly via managed=False reflection models, cutting experiment detail from N ClickHouse round-trips to a constant 1 PG + 2 CH queries. A new ChatRunTracker model records per-request timing breakdowns, LLM provider info, fallback usage, and failure categories, linked to ChatMessageHistory.generation. LLMModelRegistry gained a per-model kwargs JSONField for init overrides (temperature, streaming, reasoning, use_responses_api) editable from Django admin, a check_model_parameters command that runs a one-shot chat against every active model, and registrations for Anthropic claude-opus-4-7 and OpenAI gpt-5.5.

Monetization and billing. A new Platform.enable_monetization boolean separates the merchant-of-record/Stripe-Connect role from show_paywall enforcement, provisioned alongside show_paywall and backfilled from it for existing platforms. Auto-recharge is enabled by default for all credit accounts (configurable default $10) with a payment-method guard to prevent failed charges. ReconciliationService now sums managed-OpenClaw LLM usage (fetched via WebSocket RPC) alongside ClickHouse and self-hosted usage so previously-invisible managed-claw spend is billed, with a provision_mode parameter to scope reconciliation to managed or self-hosted instances. An anonymous platform-config endpoint was added for catalog gating.

Notifications and course signals. Course schedule-change notifications now email enrolled learners when a course's start date, pacing, or certificate-availability date changes, and grade-posted notifications alert learners when a subsection grade is posted or updated (with debounced or first-only dedup). Notification templates gained a three-dimension taxonomy (content / audience / action) stored as prefixed strings in the existing tags JSONField, with a controlled vocabulary in notification_consumer/taxonomy.py and Content/Audience/Action admin filters.

Search, catalog, and OpenClaw client hardening. Agent search fixed an N+1 (prefetch_related("categories")), added a paginated GET /api/catalog/resources/search/ endpoint, and made the mentor_include_community_mentors opt-out a hard cross-tenant gate on /api/ai-search/mentors/; anonymous ?platform_key= and ?tenant= now return identical results after a fix to V2GlobalMentorSearchView that was clobbering the requested tenant to None. The OpenClaw client now negotiates a protocol-version range (default v3–v4) instead of pinning v3, tolerates a trailing slash on server_url, provisions device-identity keys with fingerprint display on the ClawInstance admin, and honors the ClawMentorConfig.auto_push flag on agent-config edits.

Security hardening and fixes. All Langchain tool results are now run through a new ToolOutputSanitizer (HTML stripped, content wrapped with prompt-injection markers) with a per-tool clean_output toggle; a follow-up fixed a RecursionError when sanitized tools ran under LangGraph's ToolNode by patching tool methods in-place. Additional fixes closed a SQL injection in the create_ai_user command, added authentication/authorization to the GuidedPrompts and UserChatFeedback endpoints, removed a deprecated GitHub PR-review webhook, upgraded starlette to 1.1.0 for CVE-2026-48710, and corrected multimodal .docx parsing by moving to markitdown[all]. The default AI agent was renamed mentorAIagentAI on the main tenant and new tenants in a backward-compatible way (name__in=("agentAI", "mentorAI") lookups keep rolling deploys and existing tenants working), and the Mentor model gained show_catalogue/show_reasoning booleans plus a seeded twenty (Twenty CRM) integration credential schema.

iblai-os-spa0.58.10.70.0

Credits and commerce. A credit-coin / credit-balance component was integrated into the header navbar alongside an ecommerce update, and the is_enterprise flag was replaced with show_paywall for gating.

Chat and accessibility. The chat surface added a new-chat post-message event for iframe handlers, forwarding of the ?prompt= URL param into useAdvancedChat as an initial prompt, Markdown rendering for suggested prompts in the welcome and advanced-chat views, a labeled chat-input textarea, aria-labels on icon-only composer buttons, and a narrow-viewport composer reflow with a skip link. Voice autoplay of AI messages was added, driven by a voice-event-completed signal.

Agent editing and tenancy. The edit-agent experience gained OpenClaw tabs, a privacy tab, and an "Enhance Document Retrieval" toggle in settings. Cross-tab tenant switching now syncs via a BroadcastChannel and an ibl_tenant_switching cookie set during the switch.

Embedding. The embed tab added a "Show Catalogue" toggle, gated sidebar-logo navigation on show_catalogue in embed mode, validated the Website URL input as origin-only (no trailing slash), and hid the Close "X" when the chat is not iframed.

Desktop (Tauri) and security. The macOS desktop build removed the network.server entitlement per App Store review and patched Cargo alerts. Security fixes restricted and sanitized postMessage target origins to prevent XSS, looped HTML-tag stripping to prevent incomplete sanitization, patched 32 (plus 6 follow-up) Dependabot alerts, pinned qs (CVE-2026-8723) and uuid (CVE-2026-41907), and replaced xlsx with write-excel-file to close a prototype-pollution vector. UI labels were normalized — "Learner/Instructor" became "User/Admin", settings-tab labels were unified to nouns, and the Agent AI banner copy was updated.

iblai-lms-spa0.20.00.35.0

Monetization. The bulk of the LMS work was a programs-and-courses monetization feature — a paywall surface for programs and courses, a programs detail page, and a migration of the gating flag from show_paywall to enable_monetization (with a matching iblai-js bump).

Agent mode and assessment. Agent mode now fires a proactive agent message on initial course load, and an agent-autoplay feature drives voice autoplay off the Studio agent_autoplay flag and the enable_course_voice_autoplay tenant metadata. An assessment feature was completed, with agent-xblock CSS that hides all other UI except the agent in assessment mode. A new-chat button triggers a fresh agent session over postMessage.

Authoring, memory, and tenancy. An authoring tab was added to course pages, memory was enabled on the profile component, and a direct course link from another tenant now auto-switches the user to the correct tenant instead of showing a 403. The app also gained an overall suspense loader and a set of env-flag-gated UI updates. The Tauri desktop build uses an iblai-skills:// deep link as its auth redirect URL.

iblai-edx-prosumac.2.16.2sumac.2.30.13

edX signal relay expansion. The ibl-edx-signal-relay-app now relays five additional upstream edX signals to the Data Manager via core/signals/edx/SUBSECTION_SCORE_CHANGED, SUBSECTION_OVERRIDE_CHANGED, COURSE_START_DATE_CHANGED, COURSE_PACING_CHANGED, and COURSE_CERT_DATE_CHANGE — with the DM endpoint accepting unknown signal_type values as a no-op so it can deploy ahead of consumers. Operator kill-switches at the emit_remote_signal boundary (IBL_RELAY_ENABLED, IBL_RELAY_DISABLED_SIGNAL_TYPES) fail safe, and the relay gained per-type log tagging and warning-on-non-2xx observability.

Security hardening pass. A run of theme and XBlock security fixes landed: the LMSX theme header.html was rewritten to emit user-controlled values through a JSON data island (json_script-style </>/& escaping) instead of per-field JS-string interpolation (XSS-LMSX-THEME-01); ibl-edx-scorm-xblock 1.2.1 replaced its regex "sanitizer" with bleach.clean and a scheme allowlist to close stored XSS in the SCORM navigation menu; ibl-edx-custom-emails-app 1.4.1 introduced a restricted SafeEmailFormatter to fix str.format server-side template injection; and ibl-edx-third-party-auth 2.4.1 added Phase-1 nOAuth account-takeover hardening on the Keycloak, Google, and Entra ID backends (opt-in reject_unverified_email() plus audit logging on every email-keyed lookup, gated by IBL_TPA_REQUIRE_EMAIL_VERIFIED, default False). A dead OAUTH_ENFORCE_SECURE = False setting flagged as a false positive was also removed.

Dependency and CVE remediation. The Sumac chain moved Django 4.2.264.2.30 (closing 15 CVEs, the terminal 4.2 LTS release) and pinned urllib3==2.7.0 (6 CVEs) via runtime pins, without rebuilding the base image and without touching the Olive Python 3.8/Django 3.2 chain. Both shared themes bumped axios 0.21.40.32.0 plus overrides for lodash/fast-uri/follow-redirects/picomatch/minimatch, and the CMS theme also pinned postcss 8.5.15. The theme-build Node was upgraded 16.17.120.20.2 (fixing a latent nvm-PATH bug where builds silently ran on the base image's Node), unlocking serialize-javascript@7.0.5 and taking npm audit to zero.

Magic-link login and Studio agent config. ibl-edx-magic-link-login 1.8.0 added long-lived allowlisted test emails and an idempotent re-request path — when both flags are on and a valid unexpired token exists, request_magic_link reuses it instead of minting a new one (critical for the Apple App Review workflow), preserving the single-active-token invariant under SELECT FOR UPDATE. In Studio, ibl-edx-mentor-xblock 4.0.0 renamed the rendered web-component tag from to (a breaking element-name change; attributes unchanged), 4.0.1 exposed enable_chat_action_popup as an editable Studio field, and an "Agent Autoplay" checkbox (agent_autoplay) was added to the "Agent & Content Mode" section so the SPAs can speak agent responses aloud automatically.

Build-infrastructure fix. A Sumac-only typo — the lmsx-theme lib-build guard checking vendor-manifest.json instead of the emitted vendor.manifest.json — was silently skipping npm run lib on every Sumac image, so iblxlib.js was never produced and course iframes (HTML-XBlock completion tracking, ORA grading, JWT bootstrap) degraded with a MIME/ReferenceError. Fixing the guard (and bumping ibl-edx-lmsx-addon-theme 0.1.40.1.5 as a release marker) restored the working bundle.

iblai/infra-cli1.5.41.10.1

The infrastructure CLI shipped five May releases. 1.7.0 added optional Microsoft (Azure AD) SSO setup via a new microsoft_sso_config ansible role that patches IBL_EDX.IBL_EDX_BASE_OAUTH_SSO_BACKEND, creates the azuread-oauth2 OAuth2ProviderConfig row idempotently, and introduced a top-level SetupConfig.platform_name plus --platform-name/--microsoft-sso-* launch flags. 1.9.0 added .env-driven provisioning — iblai infra provision-env -f .env (fresh single-server Terraform provision, no AMI) and iblai infra setup-env (non-interactive, idempotent Ansible bootstrap) — with .env.provision.example/.env.setup.example templates and a fix for an ansible-core 2.19 parser error that had blocked six roles. 1.10.0 added an ibl_tenant_platform role that launches a tenant Platform through the full run_launch_steps state machine (not a raw create) when PLATFORM_NAME != main, made Microsoft SSO also patch IBL_SPA.AUTH, added an INSTANCE_RAM_GB 32 GB warning and a 100 GB minimum root-volume gate, and — a behavior change — now writes IBL_SPA.MENTOR.STRIPE_ENABLED=false unconditionally so Stripe deployments must explicitly re-enable billing UI post-setup. 1.10.1 raised the SPA-ready wait budget from 150 s to 450 s, and 1.5.4 pinned direct runtime dependencies to the running freeze.

The companion iblai-cli-ops pin advanced across the month from 5.9.05.23.0, carrying the field-encryption FIELD_ENCRYPTION_KEY auto-generation, nginx upstream/server blocks for agent.{BASE_DOMAIN} and skillsai.{BASE_DOMAIN} (gated by RUN_AGENT_SPA/RUN_SKILLSAI_SPA), the surfacing of agent_content_mode/course_content_mode/agent_autoplay through the DM COURSE_METADATA_KEYS/COURSE_METADATA_PUBLIC_KEYS defaults, and the hqos SPA-image rename (reading images.spa.os/courseai/videoai from the catalog).