Skip to main content

Release history

RSS

Everything that has shipped, newest first. 58 releases and counting.

v1.1.15.0“Heard Right”October 1, 2026

Everything added since September 21, cut as its own release.

Everything added to 1.1.14.2 since September 21 — twenty-two amendments — cut as its own release. The thread that runs through it: agents hear what was said. Phone agents listen in their line's language and stay in it, a menu branch can carry its own voice and language, chat voice input runs on the same recognizer as the phone with silence and hallucinations filtered out, a blind model borrows eyes from a vision-capable sub-agent, and the public SIP port is defended in the kernel with fail2ban and a per-source rate cap. Around it: one Platform Health for every component, storage that reads the bucket, conversations that are never lost to retention or to a tab pinned to the wrong workspace, removed extensions in Trash, MCP and A2A on every agent, and a Builder that reviews itself. There was no tenant delete at all: the only lifecycle action was suspend. Super admins can now delete a tenan

Improved
  • Platform Health → Phone shows the kernel layer per node — (sip-defence-status.sh + cron on each app node, node-agent sip_defence, registrar snapshot kernel_* fields): sources held out by fail2ban (24 h) and repeat offenders (1 week), packets dropped by the ban chain and by the per-source rate cap, and a warni

  • The storage reconciler reads the object store — (storage_reconciler.go, migration 000483): every bucket is walked every 6 h — documents, avatars, exports, imports, team files, call recordings (attributed through the call's tenant), diagram outputs, Studio media, models, datasets, backups. Ledger rows whose object

  • Free-tier storage limit seeded — billing periods whose storage limit was NULL (three tenants showed 0 GB of 0 GB) take the plan's limit.

  • Platform Health → Storage — (GET /admin/platform-health/storage, POST …/storage/reconcile, POST …/storage/orphans/attribute, POST …/storage/orphans/delete): totals with an estimated monthly cost (STORAGE_COST_PER_GB_MONTH), per-bucket rows, orphans with Attribute / Delete, per-tenant usage bars with c

  • Tenant purge covers every bucket — the 120-day purge now deletes the tenant's prefixes in team files, exports and imports too.

  • platform_alerts + platformalerts.Raise — (migration 000484): every detector that used to page on its own — the workflow failure sweep, the message-queue canary, phone health, stale handoffs, governance's infrastructure probes, storage, billing operators' notices and the Builder weekly audit — writes one record

  • Platform Health → Signals — (GET /admin/platform-health/alerts, POST …/alerts/:id/ack, …/resolve): a state strip per component (ok / warning / critical from open signals — the summary PROPOSAL-097 reads), open signals grouped by component with Acknowledge / Resolve, and the window's history with who was p

  • Every extension removal is a soft delete — now, history or not: the row stays, the number is freed, credentials / groups / embed sessions / messaging suspensions are dropped. Removed extensions (GET /phone/extensions/removed) lists them under the directory with Restore (`POST /phone/extensions/:id/restore

  • In a workspace — owner and admin see every conversation; every other role sees only their own — as before. In the System tenant every operator now sees only their own conversations: super_admin is a platform role, not a licence to read a colleague's chats. **The same rule now guards a single conversation, its m

  • GET /workspace/health — and a Workspace health card at the top of the dashboard: the component states a workspace admin can act on — connectors' latest probes (red streaks), storage against the plan with the retention in force, phone (calls, live now, unanswered team rings) and messaging (undelivered) when th

  • Pagination on every tab — (components/super-admin/pager.tsx): agents by agent, workflows and their failures, tools and their events, data tables, integrations, studio runs and failures, the Twilio binding table, signals (open and history), storage tenants and orphans, phone rooms / bans / carrier, containers, the

  • Platform Health → Logs — container logs from any node (node and container pickers, tail, level and text filters, follow, download — the node agent serves them whichever app node answers), and recent errors by component read from each component's own error ledger (`GET /admin/platform-health/errors?component=&ho

  • internal/observability/components.go — registers every observed component — key, name, owner, ledgers, signals, probe, page, improvement loop — eighteen of them. The gate (internal/observability/contract_test.go, run by predeploy-gate.sh beside permaudit and the env audit) fails the build when an entry is

  • GET /admin/platform-health/summary — one row per component with state (from open signals), open counts, last activity from its ledger, last sweep where a detector records one, and a live node-agent probe for infrastructure. Platform Health shows it as a state strip above the tabs; PROPOSAL-097's loop reads th

  • Retention is a policy, not an accident — Call recordings are kept per plan (plan_billing_quotas.recording_retention_days, default 90, 0 = forever; a workspace override in tenant_billing_overrides wins), exports and imports 30 days, diagram outputs 7 days, backups 90 days. The sweep runs with the storage rec

  • Plan editor — Call recordings kept (days). Tenant billing tile: the retention in force. Storage tab: per-bucket retention column, a Retention card with the last sweep, and enforcement readiness ("reconciler clean N/14 days", D4) next to the mode.

  • S3 lifecycle backstops — (scripts/prod-s3-lifecycle.sh, dev twin scripts/dev-minio-lifecycle.sh): exports/imports 30 d, diagram outputs 7 d, recordings 400 d — the net under the app's sweep. Dry-run by default; not Terraform because that module is DO-NOT-APPLY.

  • An extension has at most one live web-phone call, across every browser page — console tabs and embedded widgets alike. A second dial or answer while the extension's web leg is connected elsewhere is refused (409 already_on_call, with the busy room) and the page offers Take the call over here (the rejoin path)

  • Desk phone + web phone is allowed and reported — a registered SIP device on one call while the web phone starts another is permitted and recorded as call event dual_device on the desk-phone call (extension, surface, room), with a warning in the log.

  • A blind primary model borrows eyes — (runtime/vision_bridge.go, AgentCapabilityService.VisionReaderFor): when the agent's model cannot see and the user attaches an image, a vision-capable llm sub-agent — or, failing that, a vision-capable fallback model — transcribes and describes the image (all text verbatim

  • The composer and the runtime read one source — image.analyze on GET /agents/:id/capabilities now also lists a vision-capable fallback model, and the same resolver picks the runtime's reader.

  • Document types follow the agent, not the model row — a PDF/DOCX/XLSX/TXT attachment is accepted whenever the platform extracts documents (always), instead of only when the model's own format list mentions it.

  • A stripped image never carries its payload — the text a non-vision fallback model gets for an image it cannot receive names the type and size; until now it embedded the whole data URL, i.e. the entire base64 image, in the prompt.

  • Trash → Extensions — (app/trash/page.tsx): removed phone extensions are listed with the rest of the recoverable items, with restore (asking for a new number when the old one is in use again) and permanent delete (only when there is no call history). The Removed extensions list on Phone System → Extensions stays

  • Menus, levels and keys pin a voice and a language — (phone_ivr_handler.go tree fields voice_id/language on the menu, each node and each option; ivr-menu-dialog.tsx pickers): "1 para español / 2 for English" now continues the call with a native voice for each branch, and pins speech recognition and the agent

  • fail2ban watches the registrar — (deploy-env/prod/firewall/fail2ban/, install-fail2ban-sip.sh): the prod nodes had fail2ban for SSH only, and every SIP ban lived inside Kamailio for one hour while the flood (up to 279 INVITE/min on Sep 30) still reached the container. A log follower writes the sip-registrar log

  • Per-source rate cap on 5062 — (app-node.sh): more than 20 packets per second from one address is dropped before Kamailio parses it; softphones send one packet every 30–600 s.

  • The flood alert rates what got through — (kamailio.cfg statistic invites_ok, Health tab sip_invite_flood on invites_processed, new warning sip_invite_noise for rejected floods): a flood Kamailio was already dropping no longer holds a critical alert open for hours. Takes effect with the next sip-registrar

  • Automatic Away — (PUT /phone/my-status/auto-away, migration 000482 auto_away): the console and the embedded phone report idleness after NEXT_PUBLIC_AUTO_AWAY_MINUTES (10) without input and clear it on the first input; an idle Available reads as Away everywhere, a manual Busy / Do not disturb is untouched, no

  • Temporary statuses — (duration_min / until on PUT /phone/my-status, manual_until): Busy, Do not disturb and Away can resume on their own; the header offers 30 min / 1 h / 2 h / rest of the day and shows "until 14:00"; an expiry sweeper flips the status at the deadline on every screen. Status responses carry

  • Short first prompt — (tree.intro, menu dialog Short first prompt): played on pickup instead of the full option list; the full root prompt remains the repeat / silence / wrong-key prompt.

  • Transfer announcements — before dialling a person's fallback number the assistant says why ("no está en línea" / "no contesta" → "le comunico a su teléfono móvil"), with display names spoken up to the first dash or bracket.

  • One message offer, then no more transfers — first failed transfer offers a message or more help; the second switches to message-taking and refuses further ROUTEs for the call.

  • Turn gate and serialised transfers — (worker): transcripts that are only audio-event tags ([interferencias], [ruido], [risas]) are dropped before the echo guard; a ROUTE to a person mutes the model immediately and a second ROUTE while one is in progress is ignored — the Sep 27 "línea ruidosa" double-ring call

  • Cluster-wide registrar bans — (admin_phone_response.go): every minute each node applies the union of all nodes' bans and operator bans to its own Kamailio through htable.seti; lifted bans carry a 15-minute marker every node honours. POST /admin/phone/health/ban {ip} / DELETE /admin/phone/health/ban/:ip (pub

  • Ingress alert flag — (phone:health:ingress_alert, 10 min): ≥ 10 unrouted calls in 15 min, ≥ 60 INVITE/min at the local registrar, or ≥ 5 rooms without a call record. The call supervisor shortens the orphan-room grace to VOICE_ORPHAN_ROOM_GRACE_ALERT_S (120 s) while it is set.

  • Paging on critical signals — bell notification to every active super_admin plus the System tenant's email/Slack/Teams channels, once per alert code per PHONE_ALERT_COOLDOWN_MIN (60) cluster-wide (SET NX); PHONE_HEALTH_NOTIFY, PHONE_ALERT_EMAIL. Carrier data comes from the 5-minute cache — the minute loop ne

  • Dispatch rule bound to the provisioned trunks — (dispatch_rule_reconciler.go): at boot, every five minutes and after every trunk create/release, agent-manager binds arcanflows-s1-dispatch to every inbound trunk LiveKit holds, so a call that matches no trunk is rejected by livekit-sip before a room exists. Reg

  • Super Admin → PBX → Health tab — (GET /admin/phone/health, POST /admin/phone/health/reconcile-dispatch): threshold signals; rooms without a call record and the orphan sweep's last pass; per-node registrar snapshots — Kamailio now serves JSON-RPC (xhttp + jsonrpcs) on a container-internal listener `:8060

  • A2A client — (internal/a2aclient): fetch an Agent Card (base URL or well-known), message/send with blocking configuration, follow a non-blocking task with tasks/get until completed / input-required / failed, text from artifacts or the status message; bearer or header auth from the Vault; runs on the tenant eg

  • Registry a2a_remote_agents — (migration 000480): card URL, fetched card, endpoint from the card (https and public only), auth, timeout, health, last error; API /a2a/remote-agents (list/create/get/update/delete/connect/call) under the tools permission family; daily card re-check (advisory lock 1025).

  • One tool per remote agent — of the new type a2a (a2a-<slug>-ask, inputs message and optional context_id, skills in the description), registered on connect and attachable like any tool; A2AExecutor returns the remote answer, reports input-required and still-working tasks honestly, and marks failed/

  • Agent editor → Connections tab — the workspace's MCP servers and A2A agents with health and a one-click Attach all / detach per connection, replacing the old per-agent MCP list.

  • Register from the agent editor — the Connections tab has Register MCP server / Register A2A agent buttons that create and connect in one step; the legacy Retrieval endpoints tab only appears when an agent already has endpoints configured.

  • MCP presets — a catalog of well-known remote MCP servers (GitHub, Stripe, Hugging Face, Zapier, Context7, DeepWiki, Cloudflare docs, Microsoft Learn; OAuth-only vendors listed for reference) pre-fills the add form; Connect verifies each.

  • MCP client — (internal/mcpclient): JSON-RPC 2.0 over streamable HTTP — initialize with protocol negotiation (2025-06-18 / 03-26 / 2024-11-05), Mcp-Session-Id, notifications/initialized, paginated tools/list, tools/call with text/image/resource content rendering, ping; JSON and SSE responses; 5 MB body

  • Tenant registry — mcp_servers (migration 000479): name, https URL, auth none/bearer/header with a Vault credential (secrets never stored on the row), static headers (Authorization refused), timeout, negotiated protocol, server info, capabilities, tools cache, health, last error. API GET/POST /mcp/servers, `

  • Tools materialised on connect — each remote tool becomes a tools row of the new type mcp (mcp-<server>-<tool>, remote input schema verbatim, config {server_id, tool_name}); tools that vanish are disabled; deleting the server deletes its tools. Because they are ordinary tool rows, everything already appl

  • MCPExecutor — registered in the executor manager: loads the server, resolves the vault credential, initialize → tools/call through the tenant client, returns the rendered text (and structured content); isError results are reported as tool failures.

  • Per-tenant egress policy — (migration 000478): modes public (default) and allowlist, allow/deny domains (exact or suffix), allow/deny CIDRs — a tenant allow CIDR can open one private range for a VPN-reachable system, metadata and link-local ranges can never be opened, deny lists win. safehttp.NewTenantClient

  • Enforced everywhere a tenant steers a URL — REST tools (main request and OAuth token URL), Odoo, retrieval endpoints, outgoing webhooks and event webhooks, workflow HTTP and webhook nodes, caller lookups. Vendor-fixed clients (Graph, Twilio, OpenStreetMap) are unchanged.

  • Destination ledger — per tenant (host, via, requests, blocked, first/last seen) and Super Admin → Tenants → Egress Policy dialog to edit the policy and read the ledger. Endpoints GET/PUT /admin/tenants/{tenant_id}/egress, audited as tenant updates.

  • Prompt composition is logged before every follow-up call inside a tool loop — (both loops): message count, chars, approximate tokens — the number the Sep 24 incident had no way to show.

  • Agent Card — at GET /api/v1/public/agents/{id}/.well-known/agent.json (public, cached 5 min): protocol 0.3.0, name, description, endpoint URL, streaming capability, bearer security scheme, skills = the agent itself plus one per attached enabled tool.

  • A2A JSON-RPC endpoint — POST /api/v1/public/agents/{id}/a2a (alias /a2a/agents/{id}), bearer = embed API key: message/send (blocking, or configuration.blocking=false for a working task you poll), message/stream (SSE: task snapshot, working status updates every 10 s, artifact-update, final `status-update

  • POST /api/v1/public/agents/{id}/mcp — (alias /mcp/agents/{id}/mcp): JSON-RPC 2.0 over streamable HTTP, bearer = the agent's embed API key. initialize (protocol 2025-06-18 / 03-26 / 2024-11-05 negotiated, Mcp-Session-Id issued), ping, tools/list (one tool, ask_<agent>, with message and optional `conv

  • Embed page → Connect from MCP clients — endpoint, tool name and copy-paste configs for Claude Desktop / Claude Code, Cursor, VS Code and curl.

  • Stored endpoint credentials are masked (** — *) on every API response and export; an update that sends the mask back keeps the stored value (MergeMaskedMCPCredentials). Storage is unaffected (MCPServersStorageJSON).

  • PROPOSAL-099 — MCP servers and the A2A protocol on agents — (docs/technical-proposals/PROPOSAL-099-MCP-AND-A2A-ON-AGENTS.md): audit finds the "MCP Servers" tab is a bespoke /query retrieval client (no JSON-RPC, no transports, no tools, no vault, no SSRF guard, a catalog of REST URLs that cannot work) and no A2A

  • Delete Tenant — in Super Admin → Tenants (type the exact name, optional reason). Sets status='deleted' and deleted_at with who/why (migration 000476); the tenant leaves every admin list and summary, its users can no longer sign in (login answers deleted, memberships and the status middleware exclude it, the s

  • Deleted tab — deleted tenants with deleted-by, reason, purge date and days left, contents (users, agents, numbers, files), blockers, last purge state; Restore (back to the status it had) and Purge now (type the exact name).

  • Daily purge — (TENANT_PURGE_AFTER_DAYS, default 120; TENANT_PURGE_SWEEP=off disables it loudly), one replica at a time. Order: Stripe subscriptions cancelled → vectors per agent (rag-service) → storage objects (ledger rows and the <tenant_id>/ prefix of every bucket) → the tables whose tenant_id has no fore

  • Blockers instead of surprises — a tenant that still rents phone numbers is reported blocked and retried daily — releasing a number is a billing decision taken on the phone page, never by a sweeper. The System tenant can never be deleted or purged.

  • Mark Email Verified & Restore Access — POST /users/{id}/verify-email (tenant owner/admin, users:update) and POST /admin/tenants/{tenant_id}/users/{id}/verify-email (System-tenant super_admin acting on that tenant from outside it, same pattern as reactivate). Marks the address verified on every workspace, clea

  • Delivery health in the share dialog — the tenant email status carries last_error and last_used_at for the own and shared rows; Super Admin → Tenants → Share email shows the last failure and last successful send.

  • PROPOSAL-098 — Context-window integrity — (docs/technical-proposals/PROPOSAL-098-CONTEXT-WINDOW-INTEGRITY.md): audit of prompt budgeting and the Sep 24 input_too_large incidents (a generated document's 2.35 MB base64 re-injected as a "hidden" system message the model actually read), with a same-day hotfix stage

  • .env.example documents every variable agent-manager reads — (195 names). Two sections were added: settings that only lived in a private .env (Stripe, SendGrid, Turnstile, Sentry, SerpAPI, the legacy S3 names, platform fallback LLM keys, USE_UNIFIED_LLM_BACKENDS) with placeholders, and the runtime tunables tha

  • scripts/env-example-audit.py — compares the names the Go code reads with .env.example and fails when one is undocumented; scripts/predeploy-gate.sh runs it, so the gap cannot grow again. Deliberate exceptions go in scripts/env-example-audit.allow.

  • One tool-turn guard for both loops — (tool_turn_guard.go). Identical-action redirect and ban, banned-tool refusals, time budget, per-tool call cap, consecutive-failure disable, terminal locks, produced media and tool outputs live in one object; the loops keep only their transport. Thresholds are now the same on b

  • One prompt spine for the three builders — (prompt_spine.go): head (base prompt, overlay, translation, date, long-term memory, capability limits, brand guard, structured output) and tail (prompt style, understand-then-act preamble, chain-of-thought) shared by the main, web-search and diagram builders. 660 lines of

  • Model-switch preflight in the agent editor — Picking a model shows at once whether the agent can run on it. Block (Save disabled): no provider recognises the id, the provider has no implementation, the workspace has no API key and the platform no fallback, the catalog marks the model retired (deprecated and disab

  • Sweep of every active agent — from /commercial-models → Agents on a broken or degraded model: the same check over all active agents (all workspaces from the System workspace), listing the ones that are not ok with the reason and a link to the editor. GET /api/v1/commercial-models/preflight-sweep. This is how

  • Provider profiles and model facts — (internal/modelfacts): what each provider does on the wire (native tools, tool-result dialect, JSON mode, system prompt placement, tools with JSON) and what each model family can do (context, output, tools, vision, reasoning). Runtime decisions — native tools per provider *and

  • Gemini speaks its own dialect — The Google provider sends systemInstruction, native functionDeclarations, parses functionCall parts back, replays them and answers with functionResponse parts, sends data-URI images as inlineData, and supports JSON mode with a schema. Before: no tools, the system prompt pas

  • Gemini 3 thought signatures — ride with each tool call and are echoed on the replay, which Gemini 3.x requires ("Function call is missing a thought_signature"). Note: Google has retired the gemini-2.5 models for new users; the current ids are gemini-3.6-flash / gemini-3.6-pro — run the Google Sync on `/commercial-m

  • Groq gets native tools — The provider is now the OpenAI client pointed at Groq, so tools, the role:tool round-trip and JSON mode come with it.

  • Tools and structured output together — on providers that allow it (OpenAI, xAI). Elsewhere a JSON schema still wins over tools, as before.

  • Local backends that refuse tools fall back on their own — "model does not support tools" (Ollama's wording) triggers one retry without tools, and that model is kept on the text protocol for the rest of the process. The unified local gateway (USE_UNIFIED_LLM_BACKENDS) now carries tools and the response format inst

  • Catalog and picker corrected — The commercial-models Sync, the list endpoint and the agent editor's model list apply the facts: Grok 4 rows stop saying 8 K context and no tools, Gemini rows say what the provider can now do, and reported limits are never shrunk. /commercial-models gains a Capabilities column (

  • xAI/Grok receives tools natively — The provider always spoke the OpenAI tools contract; the executor now lets it (providerSupportsNativeTools). NATIVE_TOOLS_XAI=false rolls a single environment back to the text protocol without a rebuild. The 50 Grok agents on prod carrying 73 tool attachments gain native cal

  • role: tool results for the OpenAI wire family — OpenAI, xAI, DeepSeek, Alibaba and the OpenAI-compatible local servers now get the assistant's tool_calls replayed and one role: tool message per call keyed by tool_call_id — the contract those models were trained on. Until now every provider but Anthropic rec

  • Tool executions record the model and provider that asked — (tool_executions.provider, .model, migration 000472), so tool reliability can be read per model instead of grepping logs.

  • The in-call view has tabs — While a call is connecting or live the widget shows Call · Messages · Team; the Call tab is the full call view (levels, keypad, hold, transfer, conference), the other two show a compact call bar (caller, timer, mute, hang up) above the texts or the team chat. Click-to-text and click-to-c

  • Fit and finish (S4) — A desktop mention notification now opens the phone widget on that conversation when clicked (console and embed); the in-app bell's team-chat notifications deep-link to /team-chat?conversation=…; the team-chat chime stays silent while the seat is on do-not-disturb, as it already did during a

  • Host page contract for team chat (S3) — The embedded phone's host can open or start a conversation with phone.openChat({ conversation_id | user_id | external_user_id }) — click-to-chat beside click-to-call — and receives chat_received for every inbound colleague message and chat_unread whenever the seat's cou

  • Team chat inside the embedded phone (S2) — Each integration key (pbx_) has a Team chat switch — on for new keys, off for keys that existed before (D1) — editable on the Phone System Integrations tab. When on, the embedded widget shows the Team tab and its session may call /api/v1/public/phone/team-chat/* (c

  • Team tab in the phone widget — Beside Dialpad and Messages, the console widget now carries the team chat — the same workspace component and module store as the Team Chat page and header popup, so one load and one socket serve every surface and read state is shared. Unread and mention badges on the tab; `arcanflows:

  • Country selector on the dialpad and the in-call Add / Transfer boxes — People type numbers the way they see them locally, without a country code; the phone used to prepend "+" and the carrier read "7135551234" as +7 (Russia), so the call never left. A selector (United States, Mexico, Canada pinned, then every count

Improved
  • A directive glued to the next keyword — (USE_TOOL: odoo-search-recordsUSE_TOOL, no line break) named a tool that does not exist; three such calls struck the phantom tool out for the turn (Annie's HR agent, Sep 29). The slug sanitiser now cuts a glued USE_TOOL / INPUT, and a slug that still matches nothing res

  • Conversation learning skips the whole conversation once any turn used a tool — , not only the turn that called it. A summary of Odoo data two turns after the query used no tool itself and was learned as durable fact; the agent then answered from that stale snapshot instead of the tool. Tool output is transactional

  • The retention purge deleted messages by their own age — , so a conversation started in June and still in use in September lost its June turns at the first run after September 1 — on prod a 41-message conversation kept 26. It also hard-deleted whole conversations by COALESCE(last_message_at, created_at) while `las

  • A seat is an active member — (migration 000486, check_resource_quota('users')): deactivated members no longer occupy a seat. MultiGla sat at 50 of 50 with 49 active members and one deactivated one, so the 51st invite — and the extension that needs a member — was refused with no way to free a seat short of deletin

  • Member seats on the Capacity dialog — (Super Admin → Tenants → Capacity): the plan's seats, the override, active vs deactivated members and human extensions in use, next to simultaneous calls and maximum call time. PUT /admin/tenants/:id/call-capacity takes set_seats + max_users (null clears, -1 unlimited).

  • Removing an extension keeps its history — An extension with calls, events or messages is soft-deleted: the row stays for statistics, the number is released for reuse, its device credentials, group memberships, embed sessions and messaging suspensions are gone at once. One with no history is deleted outright. Delete

  • Drafts are visible to the platform team — A workspace that created a listing and never pressed Submit for review left it in draft, where Super Admin → Marketplace showed nothing to approve or reject (MultiGla's receptionist agent, Sep 28). The Pending tab now lists drafts under "not yet submitted by their workspa

  • Create submits by default — the workspace's create dialog has Submit for review now checked, so the draft step is no longer a place to get lost.

  • Reviewers are told — a submission raises a bell for every super admin (through the alert record, bell only, no external channels) linking to the review page.

  • Objects keyed by the zero UUID belong to the System tenant — (the platform's own workspace: shared assets, system agents, platform docs) and are attributed to it; the reconciler had read the zero UUID as "no tenant" and listed every one of them as an orphan. The Storage tab marks that row System tenant.

  • An orphan that the walk can attribute is forgotten — the orphan list only kept keys that vanished, so a key attributed later stayed listed until an operator acted.

  • Group rings go out together — Device legs were created one after another, before the console rings were even asked for, at ~1 s each: a 16-member group took 17 s from "group resolved" to the first console ring, the 15 s window started only then (35 s for the caller, 36 of 42 group rings unanswered on Sep 28), and o

  • A transfer to a person answered on their desk phone is recognised from the server — , not only the SDK cache whose sip.callStatus lags. Missing it meant the babysitter removed the answered leg at the deadline, announced "no contesta", and dialled the mobile — the attendant "staying active" after a redirect. One l

  • Resume and consult-cancel restore the held party to everything current — (restoreAudio), not to the tracks recorded when the hold began: a caller held while a colleague was added came back hearing only the operator's original track — and not even that when the operator's track had been re-published. Hold also rec

  • The operator who placed an outbound web call can hang up on it — Since Sep 21 the "callee who never joined cannot end the caller's call" guard also caught the caller: hanging up first while the far end was still connected was refused, the far end sat in silence until it hung up, the row stayed "Live 0:00" until t

  • The web phone reports "joined" on the ordinary dial path — the joined proof the Sep 21 guard relies on was only sent after a rejoin or reload.

  • Odoo tools ask the instance what fields a model has — (fields_get, cached 10 min per model) before every search, create and update. A requested name that Odoo renamed between versions is corrected when the target is unambiguous (user_id → user_ids on project.task, tag → tag_ids); a field nobody has is d

  • Raw fetches carry the tenant pin — (lib/api-client.ts exports tenantPinHeaders() / authHeaders()): the chat stream, the knowledge and OCR uploads, the Builder attachments, the jobs page, the scheduled-tasks page, the forms wizards, the app editor, the theme selector, the scheduler component and the web-call c

  • A missing agent is a 404, not a 500 — (runtime_handler.go, three sites): the service wraps the repository's not-found as failed to get agent: agent not found, and the handlers compared the bare string. repository.ErrAgentNotFound is now a sentinel tested with errors.Is; the 404 says "Agent not found in the

  • A recovered panic is logged — (middleware/sentry.go): with SENTRY_DSN unset a panic used to leave nothing but a 500 in the access log. It now logs the request, the value and the stack.

  • The recognizer is pinned to the line — (voice_gateway_handler.go resolve + turn, voice-agent-worker/worker.py _build_stt): every prod line ran ElevenLabs Scribe in per-utterance auto-detect — the extension default is auto and the agent's language was never consulted — so short Spanish turns came back as Jap

  • Foreign-script turns are dropped — (ivr_menu.py script_mismatch, worker turn gate): a transcript written in a script the line's language never uses is a recognizer hallucination on noise, not a caller turn.

  • The reply language is sticky — (voiceOverlay): the prompt said "always answer in the language of the caller's LAST message", so one mis-transcribed turn flipped the agent into English. It now stays in the line's language unless the caller asks or two consecutive turns are clearly in another language.

  • The language is a hint, not an order — (voice_client.go, llm/voice_adapter.go, voice-service stt/gates.py): the console sent the agent's configured language as a forced decode language, so a Spanish speaker on an en agent got English-shaped text, while embedded widgets sent nothing and every clip was auto-d

  • Silence and noise are not decoded — clips under 0.4 s return empty; Whisper decodes with condition_on_previous_text=False, a no-speech threshold and a temperature ladder; segments Whisper itself marks as no-speech, and known hallucinations ("Subtítulos realizados por la comunidad de Amara.org", "Thank you for wat

  • Chat voice input goes to ElevenLabs Scribe first — (services/cloud_stt.go, wired in main.go when ELEVENLABS_API_KEY is set; CHAT_STT_PROVIDER=local restores local-only): the same recognizer the phone agents use, about a second per clip, with the hint/allowed-set language policy applied in Go and audio-event

  • Call turns record language and engine — (migration 000488 call_turns.language, stt_engine): the next "it switched language" report can be checked against what the line listened in.

  • Knowledge upload runs server OCR for image-only PDFs — (components/rag/DocumentUpload.tsx, lib/ocr-extract-client.ts): client-side extraction finding no text used to throw "Scanned/image-only PDF — no extractable text"; it now sends the file through /api/ocr-extract (tesseract eng/spa/por in rag-service) and

  • Team Chat renders the user's effective status — , not a socket flag: GET /team-chat/conversations returns statuses and GET /team-chat/members a status per member (available / busy / do_not_disturb / away / in_call / wrap_up / offline), computed cluster-wide; the store follows the phone.status broadcast li

  • Handoff operators carry status and available — ; the picker shows the status and sorts takeable operators first — a teammate on Do Not Disturb is no longer a green "online".

  • Header switcher — renders for every user (extension or not), follows the socket instead of a 30 s poll, and is labelled as the status for phone, team chat, handoffs and integrations.

  • Widget seats emit status events again — migration 000481 lets user_status_log accept embed_socket and api sources; the failing insert used to swallow the hub broadcast and the phone.status.changed webhook.

  • Voice worker falls back to OpenAI when ElevenLabs fails — (VOICE_PROVIDER_FALLBACK, default on): text-to-speech and Scribe transcription are wrapped in livekit's FallbackAdapter with OpenAI voices / transcription as the second provider, so an exhausted quota, an outage or a bad key degrades the voice instead of

  • Phone Health shows the platform ElevenLabs credit pool — (tier, used / limit, reset date; cached 5 min) with a warning at 80 % and a critical page at 95 % or when exhausted — the signal that was missing on Sep 27 while the credits went from full to zero.

  • Kamailio public-source gate — (services/sip-registrar/kamailio.cfg): an INVITE from any address outside the container network / VPC must name a From-user that exists in sip_credentials (otherwise 403) and pass the 407 digest challenge against that credential before the proxy relays it — to a registered phon

  • Source bans in the registrar — htable counters badsrc / ipban — ten rejected requests from one IP in five minutes (403, wrong password or unknown user on REGISTER / INVITE, pike hits, scanner user agents) drop that IP silently for an hour. Pike threshold lowered from 30 to 20 requests per 2 s. (The first cut

  • Voice worker: no fallback agent for unrouted calls — When the dialled number resolves to nothing the worker hangs up and deletes the room; VOICE_S1_AGENT_ID is ignored (warning if set). Prod and dev had the S1-era id set, so every probe was answered with the default greeting through ElevenLabs.

  • Call supervisor orphan-room sweep — call-* rooms that no open calls row names, older than VOICE_ORPHAN_ROOM_GRACE_S (default 600 s) and holding at most one party are deleted (the calls table is re-checked before each delete; two parties are never ended blind; 150 per sweep). LiveKit records that only exist

  • Operations (Sep 27) — scanner IPs dropped at the top of ARCAN-SIP-REG on both prod nodes (runtime only — the registrar ban is the durable defence); new registrar config installed on both nodes and dev; VOICE_S1_AGENT_ID blanked; workers recreated. PROPOSAL-100 S1 (dispatch rule bound to trunk ids), S2 (super-ad

  • Generated-file base64 no longer reaches the model — Since Nov 2025 the streaming loop appended a document's base64 as a "hidden" system message that nothing filtered; every streamed document turn sent it on the follow-up call (≈90 k tokens for a median document; 2.35 MB → 1.6 M tokens on Sep 24 with the new letterh

  • A context overflow no longer cascades through the fallback chain — Provider errors that mean "prompt larger than the context window" (xAI input_too_large, OpenAI-dialect maximum context length, Anthropic prompt is too long, Google, Ollama) are classified; the turn ends with an honest bilingual note, a `contex

  • Script tool logs are capped — (head 3 000 + tail 1 000 chars): a script's stdout mirrors its result, so file tools were storing their base64 twice per tool_executions row (4.7 MB).

  • Signup sends the verification link — Register created the account unverified and sent nothing; the only sender was the resend button. Registration now sends the link best-effort in the background; the day 3 and day 7 reminders mint a fresh 24 h token and carry the link instead of saying "use the link we sent you"

  • Reactivating a sweeper-disabled user sticks — Reactivate and Change status → active also mark the address verified (every tenant row) and clear disabled_reason/disabled_at, so the sweeper cannot undo the administrator.

  • Account emails fall back to the platform mailbox — Verification, reminder, invitation, password-reset and generic account emails try the tenant's mailbox, then the System tenant's mailbox, then SendGrid. A brand-new tenant receives its shared mailbox from the onboarding workflow a moment after signup, so the veri

  • Login answers every non-active status — (inactive, pending, suspended) with a 403 and the status, instead of a generic 500 for suspended accounts.

  • A usable mailbox row wins — The tenant email lookup preferred the tenant's own row even when it was disconnected (is_active=false, no credential), which starved the working shared platform mailbox; an active row with a credential is chosen first.

  • One share implementation — The super-admin Share email button now calls the same code as the onboarding workflow's tenant-admin tool (executor.ShareEmailConfigForTenant): it clones the credential into the tenant and self-heals an existing share instead of inserting a row that pointed at the System tenant's cred

  • send-office-365-email sends from the connected credential's mailbox, never from a model-chosen address — (migration 000475). The endpoint is now /users/{{credential.email_address}}/sendMail; the sender_email path parameter is gone from the parameters and from the model-visible schema. The credential resolver

  • Parallel tool calls over an OpenAI-dialect stream are no longer merged — (OpenAI, DeepSeek, Alibaba providers). Every stream delta carries one tool-call entry at slice position 0 with its own index; buffering by slice position concatenated two calls' arguments into one invalid JSON blob, the dispatcher validated

  • Malformed tool-call arguments are never replayed as a native tool_calls turn — openAIToolCallsToBlocks wraps non-JSON arguments as {"_raw": "…"} so the provider accepts the round-trip and the model sees what it sent.

  • A fallback model's stream is served by the main streaming loop — instead of a nested copy that only knew about web search. After a primary failure the loop swaps channels and continues: tool detection, the tool-turn guard, usage accounting, nudges and honest endings apply to the fallback exactly as to the primary;

  • The web-search builder dropped the tool block — It rebuilds the whole prompt mid-turn after a search; a text-protocol model lost its tools from that point and a native one lost the rules. The tool block is rendered there now.

  • Non-stream ban, budget and cap branches burned iterations — They appended a SYSTEM line and continued on the stale response, so the same tool call was detected again on the next iteration, up to the 50-iteration cap. Every guard verdict now asks the model again.

  • Reasoning models are no longer cut while they think — Grok 4, the o-series, Gemini 2.5+ and DeepSeek's reasoner emit nothing while reasoning; a costed proposal on Grok 4.6 thought for more than 90 s and the stream watchdog aborted the turn (prod, Sep 24 05:36Z). Internally reasoning models now get a 300 s idle and

  • A streaming fallback now speaks the fallback provider's dialect — Tool turns written for the failed provider are flattened to text, images are dropped for non-vision models and native tools attach only if the fallback takes them. DeepSeek rejected the replayed Grok tool calls ("reasoning_content in the thinking mod

  • A turn whose fallback also fails ends honestly — When a fallback had started and then failed, the loop fell through and saved the primary model's last narration as the answer ("I'll generate the Word now") with no word to the user. The turn now ends with the partial text plus a clear note that nothing was generated

  • A turn can no longer end on "Genero la propuesta en Word." — Both tool loops nudged a plan-without-a-call only on the first iteration; once any tool had run, a closing announcement was accepted as the answer (prod, Sep 24 06:20Z: eight scraper steps, a code run, then "Genero la propuesta comercial en Word" and noth

  • The detector understands present-tense Spanish — "Genero", "Armo", "Redacto", "Preparo", "Procedo", "Paso a", "lo genero como Word" join "voy a" and "procederé"; Word, docx, propuesta, correo and presentación join the action words.

  • A customer Word template without "List Bullet" / "List Number" no longer fails the document — python-docx raised KeyError on the first bullet and the whole file died after a five-minute composition (prod, Sep 24 13:02Z, the Windconsul proposal template). The generator now checks the template and falls back to a tex

  • …and a template without heading, title, subtitle or table styles renders too — (migration 000474): in template mode the generator adds the heading styles it needs, falls back to bold paragraphs otherwise, and draws borders when "Table Grid" is missing. Root cause of both: windconsul-format-template, uploaded Sep

  • A retry after a failed tool call is no longer treated as a loop — The identical-action guard redirected the model's retry of the failed Word call, and the next attempt met the tool budget. A failed call now resets the repeat counter so one honest retry proceeds; the consecutive-failure cap still bounds a tool that

  • A Grok turn that writes a whole document into a tool argument no longer dies as "idle" — The xAI stream swallowed tool-call argument fragments without emitting anything, so the stream watchdog saw 90 s of silence while Grok streamed a Word document into generate-word-document and aborted the turn (prod, Sep 23 09

  • Fallback models now apply inside the tool loop — on non-streaming and background turns. Until now they covered only the first call of a turn; a provider stalling mid-loop (DashScope, three 5-minute stalls in one turn the same morning) dead-lettered the job although a fallback was configured. The rest of the turn co

  • Non-streaming Grok never saw a native tool call — The xAI provider read tool_calls from the choice instead of the message; the sync /chat path therefore treated every Grok tool call as prose. Message-level first, choice-level as fallback.

  • Unknown model names no longer default to Ollama — A typo or a brand-new model id used to fail as "provider ollama not found or not configured" on a cluster that never had one; the gateway now says no provider recognises model "<name>". Installs with an Ollama provider registered keep the legacy local-first defaul

  • The streaming path never carried structured tool calls to the round-trip — Tool detection and dispatch run when the stream closes, where the loop's chunk is empty, so chunk.ToolCalls was always nil — the Anthropic structured round-trip only ever worked on the non-streaming path. The calls are now captured as they

  • Blind transfers are now events — Every carrier REFER the voice worker performs — an extension's forward, the attendant's route fallback, the assistant's transfer action, a keypad *ext# transfer — records a transfer event with mode: blind, the destination and who initiated it. Only consult transfers from the c

  • Conference members who leave on their own are stamped — The call supervisor compares the room's participant list against the members with a conference_joined and no conference_left, and records conference_left (reason: left, time in conference, remaining parties) for anyone gone; a member joined less than 2

  • Callers heard dead air while the platform rang a person or a team — After "Un momento, le comunico…" the only sound in a ring window came from LiveKit's dial tone on SIP legs — a web-only seat, a team with no desk phones, an unregistered device or the gap between hops produced nothing for 20–60 seconds, and callers

  • Add-on editor showed one bucket at a time — The Benefits tab rendered only the fields of the selected category, so an add-on could never mix benefits and several sellable quotas were unreachable from the editor. The tab now lists every metered bucket the platform enforces, grouped (Capacity · AI usage · Media · Pho

  • Product editor could not sell minutes, audio, searches or messages — The Value & Pricing tab exposed tokens and four media counters only, and the Stripe fulfilment path never read voice_minutes_amount / audio_seconds_amount — a paid pack of minutes was recorded as a purchase of nothing. Products now carry every

  • Builder tokens were not sellable — Plans metered them since 000437 but no add-on or product could grant them. extra_builder_tokens / builder_tokens_amount added and folded into the period limit.

  • Plan editor had no Builder tokens field — monthly_builder_tokens_limit and builder_overage_rate_per_1k were SQL-only since 000437; the plan editor (Quotas and Overage sections) now carries both, and a plan edit refreshes the tenants' periods as it does for every other quota.

  • First-of-month snapshot used a second, older formula — get_or_create_billing_period computed the new month's limits without add-on audio seconds, add-on storage or any product grant, so tenants lost those until the next purchase or plan edit re-ran the refresh. It now delegates to refresh_billing_period_limits

  • Outbound calls ended by the far end now record the reason — The outbound room's "other side left" path never named its reason, so a two-hour IRS hold that the IRS terminated read as unknown/lk:client_initiated (Sep 22, ext 122); it now reads peer-left-empty-room like the answer path.

  • Incoming-call card said "Unknown" for internal callers — The ring payload carried whatever the ringing path had — an extension with no name, a LiveKit identity, or nothing (the attendant's ROUTE path rang seats with an empty caller) — and the card printed the callee's extension underneath, which read as the calle

  • Typed extensions bypassed the status rule on consult and conference — The picker greys out busy/in-call/DND colleagues since Sep 15, but the "Extension or +number" box rang them anyway. Both the console (instant reason, no request) and the server (dialIntoRoom) now refuse busy, away, do-not-disturb and in-call se

  • Every server-side click-to-call in the embedded phone dialled twice — The embed transport and the phone component both turned one phone.originate event into a dial, so the CRM's click placed two calls in the same second: two carrier legs to the customer and a twin room the UI lost track of. At MultiGla one such t

  • Server folds twin dials — A dial from the same seat to the same number within 5 seconds returns the call already in progress (its room, a fresh token) instead of creating a second one — cross-node via a Redis claim, database check as backstop — so cached widgets cannot reintroduce the double.

  • Supervisor closes never-connected web-out rooms — One party alone in a web-out room with the far end never seen was "still dialling" forever (until the ceiling). After VOICE_NEVER_CONNECTED_GRACE_S (default 15 min) it is closed as a miss dated to the dial, billing nothing.

  • MCP Servers and A2A Agents pages render inside the app shell — (sidebar, top bar, tenant switcher); they had shipped without the dashboard layout.

  • Connections tab registers and connects in one step — (Register MCP server / Register A2A agent), and the legacy Retrieval endpoints tab appears only when an agent already has endpoints configured.

v1.1.14.2“Your Own Voice”September 21, 2026

Your workspace can now create voices — and give them to agents and menus.

Design a voice from a sentence, or clone one with consent. Settings → Voices: describe the voice you want, hear three candidates, keep one. Or upload 30 s–3 min of recordings of a person who agreed, with their consent recorded alongside the voice. Library voices appear under Your voices wherever a voice is chosen. A voice still used by an agent, extension or menu cannot be deleted.

Agents pick a real voice for spoken replies. The voice-id box becomes an engine choice and a grouped list — Spanish and English native voices first, with a preview.

Phone menus speak in the voice you choose. A menu carries its own voice, and Preview plays the prompt exactly as callers will hear it.

A caller's hangup ends the call for everyone, at once. On a call answered by a web operator, the caller hanging up used to leave the operator holding a dead line until they pressed hang up themselves; the call now ends within a second, and call durations match the carrier's.

New
  • Voice library (Settings → Voices) — design a voice from a description or clone one with recorded consent; Your voices in the agent picker and Studio; plan-bounded; delete refused while in use.

  • Real voice picker for agent spoken replies — engine + grouped voices with preview instead of a typed id.

  • Phone menus with their own voice — voice picker in the menu builder; Preview speaks the prompt in that voice.

  • Create Voice node in Studio — design a voice from a description or clone connected audio (with consent) inside a flow; downstream Voiceover / Change Voice inherit it; re-runs reuse the voice.

  • The phone speaks with your own ElevenLabs credential — a workspace with its own backend uses it for the attendant, menus and previews; its library voices appear as Your voices in the extension and menu pickers.

  • Teams & queues — a new tab on Calls — per ring group: offered, answered, missed, answer rate, time to answer and who answered; per queue: served, abandoned, overflowed and wait times with full history; conferences, holds and transfers; CSV per section. Group and conference numbers are counted from this release on.

  • Country code on the dialpad — pick the country (United States, Mexico and Canada first, then A–Z) and type the number as you see it locally; the phone qualifies it and shows what it will dial. Extensions and numbers typed with + or 00 are untouched. Also in Add to the call and Transfer to.

  • Team chat in the phone widget — a Team tab beside Dialpad and Messages, in the console and in the embedded phone: the same conversations as the Team Chat page, with unread and mention badges. Inside a CRM it appears when the integration key's Team chat switch is on (Phone System → Integrations); the host page can open a conversation (click-to-chat) and receives new-message and unread-count events.

  • Messages and Team stay reachable during a call — the in-call view has Call · Messages · Team tabs; on the chat tabs a compact bar keeps the caller, the timer, mute and hang up on top.

  • Grok agents call tools natively (PROPOSAL-095 S1) — xAI receives tool definitions the same way OpenAI, Claude, DeepSeek and Qwen do, tool results go back to those models as proper tool messages, and every tool execution records the model that asked for it.

  • Gemini and Groq call tools natively (PROPOSAL-095 S2) — every provider with an implementation now receives tool definitions in its own API and answers in its own dialect; one registry of provider and model facts drives the runtime, corrects the commercial-models catalog on every Sync and feeds the model picker.

  • Capabilities on the models page — tools, vision, reasoning, JSON and audio at a glance, plus each model's output limit; "text tools" marks a model driven by the text protocol.

  • The model check before you save (PROPOSAL-095 S3) — picking a model in the agent editor shows at once whether the agent can run on it: blocked when the workspace has no key for the provider, the model is retired or no provider recognises it; confirmed when it will run with limits (tools on the text protocol, no JSON mode, unverified model). The models page can sweep every active agent and list the ones on a broken or degraded model, with a link to each editor.

  • Tenants can be deleted, and come back for 120 days — Super Admin → Tenants → Delete Tenant (type the name); a Deleted tab shows who, why, purge date and contents with Restore and Purge now; a daily job purges permanently after the retention window (Stripe cancelled, files and vectors removed, every row deleted, purge record kept). Rented phone numbers block the purge until released.

  • Every agent is an MCP server — Model Context Protocol clients (Claude Desktop, Cursor, VS Code…) add …/public/agents/{id}/mcp with an embed API key and get the tool ask_<agent>, which runs the agent with its own prompt, tools, guardrails and quotas; long turns stream progress. Embed page → Connect from MCP clients has copy-paste configs.

  • Mark Email Verified & Restore Access — tenant owners/admins and, from the System tenant, super admins can restore a user disabled for an unverified email; Reactivate now does the same, so the hourly sweeper can no longer undo it.

  • Verification email at signup — registration sends the link (it never did); day 3 and day 7 reminders carry a fresh link; account emails fall back to the platform mailbox when a new tenant has none yet.

  • PROPOSAL-098 (context-window integrity) and PROPOSAL-099 (MCP & A2A on agents) written; the Sep 24 overflow was a generated document's base64 re-injected as a hidden message the model actually read.

  • Every agent is an A2A agent — a public Agent Card at …/public/agents/{id}/.well-known/agent.json and a JSON-RPC endpoint (message/send, message/stream over SSE, tasks/get, tasks/cancel) authenticated with the agent's embed API key; tasks persist, contextId continues the conversation, a human handoff is reported as input-required. Embed page → Connect from A2A clients.

  • Per-tenant outbound egress policy — where a workspace's REST tools, retrieval endpoints, webhooks, workflow HTTP nodes and caller lookups may connect: public-internet default, deny lists, allow-list-only mode, CIDR overrides for a VPN-reachable system (metadata ranges never), a destination ledger with blocked counts, and a Super Admin → Tenants → Egress Policy dialog.

  • MCP servers as tool sources — Integrations → MCP Servers: register any Model Context Protocol server (streamable HTTP) with a Vault credential, press Connect, and its tools become tools in your workspace that you attach to agents like any other; audited, guarded and governed by the egress policy; health probed hourly.

  • Remote A2A agents as tools — Integrations → A2A Agents: register any Agent-to-Agent protocol agent by its Agent Card, press Connect, and it becomes an Ask <agent> tool for your agents; tasks are followed to completion, human-input requests are reported honestly, calls are audited and governed by the egress policy.

  • Connections tab in the agent editor — the workspace's MCP servers and A2A agents with health and one-click attach/detach of all their tools; plus a catalog of well-known remote MCP servers (GitHub, Stripe, Hugging Face, Zapier, Context7, DeepWiki, Cloudflare and Microsoft docs) that pre-fills the add form.

  • Phone Health for platform operators — a new first tab on Super Admin → PBX shows the phone stack's vital signs across nodes: threshold signals, registrar request and rejection rates with banned sources, gateway rooms without a call record and the orphan sweep, dispatch binding with a one-click reconcile, unrouted-call counters, call outcomes, and Twilio's own alert log per workspace. The gateway now rejects calls that match no provisioned trunk before a room exists.

  • The phone stack responds on its own — a source banned by one node's registrar is banned on every node within a minute, operators can ban or lift a source from the Health tab, the orphan-room sweep tightens to two minutes while probe traffic is arriving, and critical phone signals page the platform operators by bell and by the System workspace's notification channels.

  • Phone menus got shorter and transfers got honest — a menu can greet with a short first prompt and keep the full option list for silence or a wrong key; the assistant tells the caller why ringing starts again before dialling a person's mobile; after one failed transfer it offers a message, after two it takes the message instead of transferring again; and transcriber noise tags are no longer mistaken for the caller talking.

  • Away when you walk away — after ten minutes without input you read as Away everywhere and come back to your own status the moment you return; Busy, Do not disturb and Away can now carry a duration (30 minutes to the rest of the day) and resume to Available on their own, with the header showing until when.

  • One Platform Health — Phone, Storage, Infrastructure and Builder health join Agents, Workflows, Tools, Data tables, Integrations and Studio on a single page; the PBX Health tab points there.

  • Storage that is counted — the platform reads every bucket every 6 hours: per-bucket totals, per-workspace usage against the plan with a category breakdown and 30-day trend, orphaned objects with attribute/delete, and an estimated monthly cost. Workspace usage now follows the bucket instead of a ledger that only ever grew.

  • Signals — one alert record for the whole platform: every detector (workflows, message queue, phone, handoffs, storage, billing, governance, Builder audit, marketplace) writes to it, critical signals page once per cooldown, and Platform Health opens on a Signals tab with acknowledge, resolve and a paged history.

  • One web call per seat — an extension can be on one web-phone call at a time across every browser tab and embedded widget; a second page is told where the call is and can take it over. A desk phone alongside the web phone is allowed and recorded.

  • Retention — call recordings are kept for the period set on your plan (90 days by default), exports and imports for 30 days; the Billing tab shows the period in force and an expired recording says so on the call instead of disappearing. Plans get a Call recordings kept setting.

  • A state strip on Platform Health — every component the platform observes, its state and when it was last active, in one row at the top of the page; behind it a component contract that the deploy gate enforces, so no health view can appear outside Platform Health again.

  • Logs on Platform Health — container logs from any node with level and text filters and follow, and the recent errors of every component read from its own records, side by side on one tab.

  • Workspace health on your dashboard — one line that says whether anything in your workspace needs attention: connected integrations, storage against your plan, phone and messaging if you use them, agent failures, workflow runs, tool errors and people waiting for a handoff. Green collapses to a line; amber or red opens with the reason and a link to where it is fixed.

Fixed
  • A caller's hangup ends a bridged call immediately — the operator's phone no longer shows a dead call, and durations no longer run ~20 s past the carrier's.

  • Pressing Hang up while still connecting to an incoming call no longer cuts the caller off — a callee who never joined the room ends only their own leg; the ring times out and the assistant resumes.

  • An operator's hang-up after a real conversation closes the call — the phone now reports the moment it is actually connected, so only a leg that never joined is kept from ending the call.

  • A colleague added to a call who answers in their console is no longer reported as "did not answer" — both their desk phone and console are watched; the answered one wins and the other is stopped.

  • The assistant no longer hijacks a press-number menu on a click or a cough — while a menu is active it speaks only when the caller really says something (a spoken number counts as a keypress), silence repeats the menu, and prompts play to the end unless a key is pressed.

  • Changing a plan's allowances now updates every tenant on that plan immediately — the open billing period is re-derived on save (overrides and add-ons kept).

  • Super admins can sell phone minutes — a Phone add-on category carries voice minutes and SMS/MMS segments (they were hidden under Multimodal).

  • Add-ons and one-time products sell every metered allowance — the editors list all buckets (capacity, AI usage, media, phone & messaging) whatever the category; Builder tokens, web searches, audio seconds, voice minutes and SMS/MMS can now be sold as products too, and a purchase grants all of them.

  • The plan editor carries Builder tokens — monthly allowance and overage rate, applied to tenants on save like every other quota.

  • First-of-month allowances no longer drop add-ons and purchases — the new period is computed with the same formula a purchase or plan edit uses.

  • An extension or team can no longer forward to the workspace's own number — such a forward is refused when saved and ignored at call time, so the assistant resumes instead of looping.

  • Incoming calls show who is calling — the caller's name when the workspace knows it, otherwise the number or extension; 'Unknown' only when nothing is known.

  • Typed extensions obey colleague status — adding someone to a call or transferring to them is refused while they are busy, away, on do-not-disturb or already on a call, the same rule the picker applies.

  • Click-to-call from an embedded phone no longer dials twice — one call per click; a duplicate dial within five seconds joins the call already in progress; a call whose far end never joined is closed after fifteen minutes instead of four hours.

  • Callers hear ringing while the system rings someone — a ringback tone plays for the whole ring window when a call is routed to a person, a team or a forward, instead of the silence that made callers hang up; queue music is unchanged.

  • Calls ended by the other side record it — an outbound call the far end hangs up on is no longer logged as 'unknown'.

  • Structured tool results now reach the model on streamed replies — the structured round-trip never ran while streaming (Claude included); it does now.

  • Unknown model names fail with a clear message naming the model, instead of "provider ollama not found".

  • Conference departures and blind transfers are recorded — a member who leaves a conference on their own and every carrier transfer (forward, route fallback, assistant, keypad) now produce events on the Teams & queues tab.

  • Grok 4 and Gemini catalog rows corrected — no more 8 K context / no tools for Grok 4, and Gemini rows say what the provider can actually do.

  • Local backends that refuse tools fall back on their own instead of failing every turn.

  • A Grok turn that writes a whole document into a tool no longer dies as idle — the stream watchdog saw silence while the document streamed into the Word tool's arguments and aborted the turn; every fragment now keeps the stream alive.

  • Fallback models now apply inside the tool loop — a provider stalling mid-turn hands the rest of the turn to the fallback instead of failing the job.

  • Tool loops behave the same whether you stream or not (PROPOSAL-095 S5) — one guard now bounds repeated calls, bans, time budgets, failure caps and final-action locks on both paths with the same thresholds, and the three prompt builders share one system-prompt spine.

  • An agent keeps its tools after a web search — the prompt rebuilt after an in-turn search dropped the tool block, so a model on the text protocol could not call tools from that point.

  • Blocked-tool turns end promptly — after a ban or a spent budget the non-streaming loop re-detected the same stale call instead of asking the model again.

  • Reasoning models are no longer cut off while they think — Grok 4, Gemini 2.5+, the o-series and DeepSeek's reasoner emit nothing while reasoning; a long document on Grok was aborted after 90 s of silence. They now get five minutes.

  • A fallback model picks up a turn in its own dialect — tool turns written for the failed provider are rewritten for the fallback instead of being rejected.

  • A turn whose fallback also fails says so — instead of saving the model's last "I'll generate it now" as the answer, the reply ends with a clear note that nothing was generated.

  • A turn can no longer end on "I'll generate the Word now" — after tools have run, a closing announcement with no tool call is nudged into the call instead of being accepted as the answer; the detector also understands present-tense Spanish (genero, armo, redacto, procedo).

  • A Word template without list styles no longer fails the document — bullets and numbered items fall back to text markers when the template lacks "List Bullet" / "List Number".

  • A retry after a failed tool call is no longer treated as a loop — one honest retry proceeds; a tool that keeps failing is still capped.

  • Office 365 email sends from the connected credential's mailbox — the model could set sender_email to another person's mailbox and Graph refused (403); the sender is now bound to the credential.

  • Parallel tool calls over OpenAI-dialect streams were merged into one unparseable call (qwen3.8-max 400) — calls are keyed by their wire index; malformed arguments are never replayed raw.

  • A fallback model's stream runs through the main loop — tool detection, guards and honest endings apply; a USE_TOOL directive is no longer printed to the user as the answer.

  • Login answers every non-active status (inactive, pending, suspended, deleted) instead of a generic error; a usable mailbox row wins over a disconnected one; the super-admin Share email button self-heals instead of answering 409.

  • The agent tab "MCP Servers" is now "Retrieval endpoints" (it was never MCP): fake catalog removed, private addresses refused, stored credentials masked on every response and export.

  • .env.example documents every variable agent-manager reads, enforced by the predeploy gate.

  • Generated-document base64 no longer reaches the model — since Nov 2025 every streamed document turn re-sent the file's base64 to the model as a hidden message (1.6 M tokens on Sep 24, refused by the model and by its fallback). The file stays in memory for the email attachment only, and a guard removes any such payload before every provider call.

  • A context overflow ends the turn honestly instead of cascading through the fallback chain with the same oversized prompt; recorded as context_overflow in agent health. Script tool logs are capped so file tools stop storing their base64 twice.

  • Phone ingress hardened — the public SIP registrar now relays calls only from devices it knows (403 for strangers, digest challenge for known devices) and bans an address after ten rejected requests; a dialled number nobody provisioned is hung up at once instead of being answered by a fallback agent; the call supervisor deletes rooms that no call record names. A scanner had turned random-number probes into hundreds of zombie rooms and failing calls.

  • Voices keep working when a speech provider fails — phone agents and menus fall back to OpenAI voices and transcription automatically when ElevenLabs is exhausted or down, the platform's ElevenLabs credit pool is on the Health tab with a page at 95 percent, and the System workspace's default provider key is now the platform's key of record for every workspace without its own. Operators can also read container logs from any node on System & Containers.

  • One presence — the status you set in the top bar (Available, Busy, Do not disturb, Away, plus In a call and Offline) is now the same status in Team Chat, in the handoff picker, in the embedded widget and in the API; a teammate on Do not disturb no longer shows as a green online dot, and the header follows changes live.

  • Odoo field names are checked against your instance — a field Odoo renamed (user_id → user_ids on tasks) is corrected and noted; an unknown field is dropped from a read or reported with the similar names, instead of the tool failing with Odoo's raw error.

  • Queue counters no longer show callers who already left — waiting counts and wait times on Phone system → Groups only count calls that are still live; stale entries are closed automatically.

  • Hanging up an outbound web call ends it again — the caller's own hang-up was being refused while the far end was still connected, leaving calls open and operators redialling.

  • Transfers ring everyone at once — device legs no longer queue up before the console rings; a desk-phone answer is recognised from the server; taking a caller off hold restores everyone who joined meanwhile.

  • Marketplace drafts reach reviewers — the platform team sees and can publish drafts that were never submitted; creating a listing submits it by default and notifies the reviewers.

  • The System tenant's files are no longer listed as orphans on Platform Health → Storage.

  • Conversation history is safe from retention — a conversation is kept for as long as it is active; older turns of a live conversation are never removed, and an expired conversation disappears from the list 30 days before its rows go.

  • Who sees which conversations — owner and admins see every conversation in the workspace, everyone else only their own, on the list and on the conversation itself; platform operators see only their own.

  • Seats and extensions — a seat is an active member, so deactivating someone frees it; removing an extension keeps its call statistics; a member-seat override sits beside call capacity for the platform team.

  • Tool calls and the knowledge base — a tool call the model wrote without a line break is recognised instead of failing three times, and nothing from a conversation that used a tool is ever learned as durable knowledge.

v1.1.14.1“Still Working”September 20, 2026

A dropped connection no longer costs you the answer.

The turn belongs to the conversation, not to the connection. If your phone changes networks or your laptop sleeps while an agent is still writing, the agent keeps working on the server and the whole exchange is saved as if you had stayed. On the page you see Connection lost — the agent is still working and the answer appears by itself; if you left, the notification bell brings you back to it.

Your question is always kept. Even when a turn ends without an answer — a provider error, an empty reply — the message you sent stays in the conversation.

Stop means stop. Pressing Stop ends the turn on the server as well, wherever it runs; a stopped turn saves nothing. Moving a long reply to the background stops the live turn first, so nothing is answered twice.

Fixed
  • A lost connection no longer loses the answer — the agent finishes, the exchange is saved, the bell rings; on the page the finished answer drops into place by itself.

  • The question is kept even when there is no answer — provider errors and empty replies no longer erase the turn.

Improved
  • Stop is a deliberate signal, distinct from a dropped line — it ends the turn on the server, on either production node; moving a reply to the background stops the live turn first.

v1.1.14.0“Press One for Sales”September 19, 2026

Your phone numbers can now answer with a menu — and keep the assistant listening behind it.

Press-number menus. On a principal number, open Menu and build the tree: what the caller hears, and what each key does — ring a team, put the caller in a team's queue with music, hand to an agent or an extension, forward to an outside number, open a submenu, repeat, go back, reach the assistant, or say goodbye. Preview any prompt in the workspace voice, then save and attach in one click. Detach returns the number to the assistant.

The assistant stays on the line. In menu-first mode the prompt is the greeting, and the caller can press a key or simply say what they need — either way they land on the same routing. A caller who hates menus is served by the assistant; a caller who knows the key is served in one press. Assistant-first mode keeps the normal greeting and turns the keys into shortcuts for the whole call.

Menus that always work. Saving refuses two actions on one key, key 0 doing anything except reaching a person or the assistant, a submenu that loops, or a target that is not a live extension or team. Digits that match no key are dialled as an extension. A wrong key gets "opción no válida" and the prompt again, then the fall-back you chose.

New
  • Press-number menus on principal numbers — a builder in Phone System with per-key actions, submenus, a voice preview, and one-click attach.

  • The assistant listens behind the menu — callers can press a key or just speak, and both reach the same routing.

  • Menus are validated on save so a stored menu can always be played: unique keys, key 0 reserved, live targets, no loops.

Fixed
  • Menu keys pressed during the prompt were lost. The first live calls honoured no key: the keypad was armed only after the greeting had finished — 17–19 s after pickup, after the moment every caller actually presses. It is now armed the instant the call is answered, and a keypress cuts the prompt short. The keypress measurement now runs on every call from the first second; the live re-test showed one clean event per key from the carrier.

v1.1.13.9“The Team Answers”September 19, 2026

A team line can now be answered by one of your agents from the very first second.

Pick an answering agent on a ring group and every call to that group — dialled as the extension or arriving on a number that rings the group — is answered immediately by the agent, instead of ringing while your people are tried one by one. Only agents that already have a phone extension can be chosen. Groups without an answering agent behave exactly as before.

The agent knows whose team it speaks for. When the caller asks for a person, or asks for something the agent cannot do, it rings the team; if someone answers, the agent steps out. When nobody is free it says so and offers to keep the caller in line with music. A caller who says they do not want to talk to an assistant is routed straight away, no arguing. The agent may close a call it has fully answered on its own, and it can never route the caller back to itself.

New
  • A ring group can be answered by an agent — choose an Answering agent on the group; every call is answered instantly instead of ringing member by member.

  • The agent hands over like a colleague — rings the team when the caller wants a person, offers the wait with music when nobody is free, and steps aside when the caller does not want an assistant.

v1.1.13.8“Which Account”September 17, 2026

Your phone system runs on a Twilio account. Until now the platform could not have told you which one, and that gap had teeth: deleting the credential silently stopped your text messages while calls carried on, changing accounts left calls running on the old one, and two workspaces could share one account with nothing to say so.

One credential, named. Each workspace now designates the Twilio credential its phone system uses, under Phone System → Settings → Twilio account. If you only have one, it is chosen for you. That credential cannot be deleted while the phone system depends on it — you are told what depends on it and where to change the designation first.

Every number knows its account. Numbers, trunks and your Messaging Service now record the Twilio account they live on. Running Sync tells you if any of them belong to a different account than your credential, which is exactly what happens after a credential swap. Releasing such a number is refused, because releasing it here would not stop its billing; you can detach it from the workspace instead.

Shared accounts are visible. Adding a Twilio account that another workspace already uses is allowed, with a clear warning about what you are sharing. Selecting a Messaging Service another workspace already uses is refused, because it can only deliver messages to one of you. So is adding a number another workspace routes.

Health at a glance. The Twilio account card shows three signals in green, amber or red, and administrators get a Phone tab in Platform Health with the same signals for every workspace.

New
  • A designated Twilio credential per workspace, chosen in Phone System settings and protected from deletion while the phone system depends on it.

  • Numbers, trunks and the Messaging Service record their Twilio account; Sync reports any that belong to a different account than your credential.

  • Shared accounts are detected: a warning when adding an account another workspace uses, and a refusal for a shared Messaging Service or a shared number.

  • Credential health on the Twilio account card, and a Phone tab in Platform Health for administrators.

  • Changing the Twilio account is an explicit, guarded action — a dialog shows what lives on the current account and does not move; the change is refused while any number is still on the old account, and each stranded number can be re-provisioned on the new one once it exists there.

Fixed
  • Releasing a number that lives on another Twilio account is refused instead of deleting your records while the number stays alive and billing elsewhere; detach from the workspace is offered instead.

  • Deleting the credential the phone system runs on now fails with an explanation rather than silently breaking messaging.

  • Studio image nodes with several reference images — all connected images were always sent; the prompt prefix the platform added misled compositions that are not two people. It is neutral now, and Image nodes show how many images are connected and the <IMAGE_n> tokens the prompt can use.

v1.1.13.7“Words With Timings”September 17, 2026

Subtitles now work everywhere speech does — including the engine we run ourselves, and including speech the platform generates for you.

The local speech engine can make subtitles now. It was the only one that could not, and the reason was almost funny: it was already asking Whisper to time every word, and then reading only the start and end of each sentence and dropping the rest. Nothing above it asked for the detail either. Both ends are fixed, so the cheapest engine produces SRT and VTT like the rest. Placing every word takes a little longer, so it is done for transcription and skipped on live phone calls, where nothing would read it.

Captions on the speech you generate. A Voiceover node now carries captions, and a talking avatar inherits them from the voiceover driving it. On a video the player gets a CC button and the captions start on. On audio you get the subtitle files, since there is no picture to put words over.

Only ElevenLabs reports exactly when it said each word. For every other voice the words are spread across the real length of the clip, which is close but not exact — and those captions are labelled estimated timing, so you always know which kind you have. Sound effects and music are left alone; there are no words to caption.

New
  • The local speech engine produces subtitles — it was already timing every word and throwing the detail away.

  • Voiceovers carry captions, and a talking avatar inherits them from the voiceover that drives it.

  • Video players get a CC button, with captions on by default; audio nodes offer the SRT and VTT files instead.

Fixed
  • Estimated captions are labelled as estimated. Only ElevenLabs reports real timings; every other voice is spread across the clip length and says so.

  • Generated audio gets a real duration — most speech engines never report one, which left the stored clip with no length at all.

v1.1.13.6“What It Already Knew”September 16, 2026

Both changes in this release are the platform surfacing something it already had and was quietly throwing away. Subtitles from your transcripts. Speech-to-text engines have always returned word-level timings — exactly when each word starts and ends — and every layer above the engine discarded them, so it was impossible to build subtitles from a transcript the platform had timed perfectly well. A Transcribe node in the Studio now offers its text as TXT, and as SRT and VTT subtitle files ready for a video editor or the web. Lines are grouped to be readable, breaking at pauses and sentence ends rather than flashing one word at a time, and they are kept with the transcript so they are still there when you come back to the flow. Not every engine reports timings. Deepgram, ElevenLabs and the Whisper adapter do; the local Whisper engine does not yet, so a transcript from it offers plain text and says so, instead of handing you subtitles with made-up timecodes. A stopped speech engine now says it stopped. In the Studio's engine picker, a local engine that was down was filtered out of the list — indistinguishable from one that had never been set up, with nothing on screen to explain why a node would not run. Offline engines are now listed and greyed out, marked offline. Engines you have deliberately switched off are still hidden: switched off is a choice, offline is a fault.

New
  • Transcripts download as subtitles — TXT always, plus SRT and VTT whenever the engine reported word timings, with lines grouped for reading rather than one word at a time.

  • Subtitles are kept with the transcript, so they survive coming back to the flow later.

Fixed
  • A local speech engine that is down is shown as offline instead of disappearing from the Studio's engine picker, where a fault used to look identical to an engine that was never configured.

  • An engine that reports no timings says so rather than producing subtitles with invented timecodes.

v1.1.13.5“Nobody Waits for Nothing”September 16, 2026

A customer who calls a busy team should wait with music and be connected the moment somebody frees up. Every part of that turned out to be broken, and this release fixes the lot. Waiting now works from anywhere. Reaching a team through the receptionist could not put you in the queue at all — the receptionist would say nobody was available and, if you offered to hold, had no way to let you. It now asks whether you would rather wait with music, and puts you in line when you say yes. The music plays continuously. It used to stop the instant the system began ringing the team, so callers heard about three seconds of music and then twenty of silence, over and over. It now plays right through and stops only when someone actually answers. Unreachable phones stop costing you time. A desk phone that is switched off was still rung for a full twenty seconds before anyone else was tried. That dead time is gone: the system moves on as soon as it sees there is nothing ringing. Operators stop being invisible. Hanging up used to leave you shown as 'wrapping up' for about a minute even though the real window is fifteen seconds, and a Do-not-disturb set hours earlier would silently exclude you from your teams with nothing on screen to explain it. Wrap-up now clears on time, and the web phone warns you when your own status is hiding you from team calls.

New
  • The receptionist can offer to put you on hold for a team — if the team is busy and you say you will wait, you get hold music and a place in line, and are connected as soon as someone frees up.

Fixed
  • Hold music no longer cuts out every few seconds — it used to stop as soon as the system started ringing the team, up to twenty seconds before anyone could answer. It now plays through the ring.

  • A switched-off desk phone no longer costs the caller twenty seconds — the system moves on to the next person as soon as it can see nothing is actually ringing.

  • 'Wrapping up' clears on time — the window is fifteen seconds, but its end was never announced, so colleagues kept seeing you as busy for about a minute after you hung up.

  • The web phone warns you when your own status is hiding you — Busy, Do not disturb and Away quietly remove you from every team queue; being signed in is not the same as being reachable, and now it says so.

v1.1.13.4“What It Can Actually Do”September 15, 2026

Two proposals close in this release, and they are the same idea applied twice: the platform should offer exactly what it can actually do, and admit what it could not read. What an agent offers. Last release the console chat learned to decide attachments from everything the agent has — its model, its sub-agents and its tools — instead of the model alone. Every other surface was still guessing. Now the embedded agent, the chat bubble and chat inside your apps ask the same question: an agent whose model cannot see, but which has a vision or image-editing sub-agent, accepts images on those surfaces too; and chat inside an app, which never offered an attachment at all, offers one whenever something can read the file. Nothing to configure — attach the sub-agent and the surfaces follow. What the platform read. Scanned pages inside an otherwise digital document were being skipped. One average over the whole file decided whether any page was read with OCR, so a 200-page contract with ten scanned inserts — a signed page, a stamped annex — was treated as fully digital and those ten pages contributed nothing, with no warning anywhere. Every page is now judged on its own. Very large documents are capped and the agent is told plainly when pages were left unread, poorly scanned pages are flagged so figures and names from them are treated as uncertain, and large files are processed in bounded batches instead of being loaded whole.

New
  • Embedded agents and app chats offer what the agent can really do — an agent whose model cannot see, but which has a vision or image-editing sub-agent (or an image tool), now accepts images on the embedded widget, the chat bubble and inside your apps, exactly as in the console.

  • Chat inside an app can accept files — it previously had no attachment control at all; it now shows one whenever something attached to the agent can read a document or an image.

Fixed
  • Callers are held in line when every operator in a group is busy — the call queue (hold music, your place in line, a maximum wait, and the group re-rung when it is your turn) never actually engaged: callers were dropped straight to the overflow action instead of waiting. Switch Queue on for a group and it now works.

  • Ring groups no longer ring someone who is already on a call — busy, away and do-not-disturb were always respected, but a member genuinely on a call could still be rung, wasting a full ring window per busy member before reaching a free one. The person who receives an internal call is now seen as busy too, and returns to Available properly after hanging up.

  • Agents on Claude, GPT, Gemini or Grok accept images again — a capability check added in the previous release did not know about commercial models, so the chat refused image uploads for them (documents were unaffected).

  • Scanned pages inside a digital document are no longer skipped — a mostly-digital file with a few scanned inserts had those pages silently dropped, and the agent answered as if the document were complete. Each page is now judged on its own.

  • You are told when a document was only partly read — very large documents are capped at 300 scanned pages and the agent is told which pages were not read, instead of answering from a document with holes in it.

  • Poor scans are flagged — each scanned page carries a confidence score, and the agent is told to treat figures and names from badly scanned pages as uncertain.

  • Large scanned files are processed in bounded batches rather than loaded whole, and the OCR on/off setting is finally honoured (it was ignored before).

v1.1.13.3“Finishing the Job”September 15, 2026

A research request on a production agent came back as text from memory: no web search, no document, no email. The agent had asked the scraper to open a Google results page, which is refused instantly; it retried the same call twice, and a five-month-old safety guard answered the third attempt by taking every tool away for the rest of the turn. None of that showed in the list of what the agent was doing. This release changes each link of that chain. A tool that repeats itself now loses only itself — the search, the document generator and email stay available. A scraper pointed at a search results page runs the search it meant and hands back the results. A request to investigate or research something runs the web search before the model starts writing. And the guard's interventions appear in the activity list, so a turn that changes course explains itself. Documents: the old PDF Report Generator, deprecated for months, is gone; the Word Document Generator produces PDF and Word, and when a tenant has no default template of its own it now applies the built-in ArcanFlows brand format. The chat also offers exactly what the agent can do — attach, image, video, audio, documents — computed from its model, sub-agents and tools together (PROPOSAL-086).

New
  • Research requests search first — asking an agent with web search to investigate or research something (investigar, pesquisar, recherche, deep dive) runs the web search before the model writes, even when the same request also names a document or an email to produce.

  • Built-in ArcanFlows brand format — when a document request names no template and your tenant has no default format template, the Word Document Generator applies the ArcanFlows brand format, so a brand-new tenant still gets a branded PDF or Word document.

  • The chat offers what the agent can actually do — the attach control and the image/video/audio/document options now follow what the agent's model, sub-agents and tools can really do, per action, with a reason when something is unavailable (PROPOSAL-086).

  • An agent whose model cannot see can still read an image by delegating to a vision-capable sub-agent.

Fixed
  • A looping tool no longer takes every other tool down with it — when the same tool is called three times with the same input, only that tool is blocked for the rest of the turn; the search, document and email tools stay available so the task can finish.

  • A scraper pointed at a search results page runs the search instead — Google, Bing, DuckDuckGo, Yandex, Baidu, Yahoo, Ecosia, Brave and Startpage result pages given to the Web Scraper are answered with the agent's web search results for that query, not a refusal.

  • The activity list shows the guard's interventions — Repeated call to X skipped and X blocked for the rest of this turn appear as steps, so a turn that stops using a tool says why.

  • Internal housekeeping prompts (conversation titles, call summaries) never trigger a web search.

  • The list of steps is drawn once — while a reply was streaming, the same list could appear twice, one copy flickering in and out; the standalone Working on your request bubble now hands over to the message as soon as it exists.

  • Guard notices look like notices — Repeated call skipped and blocked for the rest of this turn appear in amber with a shield instead of reading as failures.

  • A tool call written twice by the model — once without its input, once with it — now runs with the input instead of being rejected as empty.

  • Long turns are bounded — an agent gets a time budget for tool calls in one reply (7 minutes in chat, 12 in the background) and at most 8 calls to the same tool; when either is reached it answers with what it has and says what it could not finish, and the list of steps shows why.

  • A step that never reported its end is now marked as not finished when the reply ends, instead of spinning forever.

  • A failed background job is retried only when the failure was quick and transient — a run that already took more than ten minutes, or that ended on a model-provider timeout, is not run again from scratch; it is marked failed with the reason.

  • Both people on a call show In a call — the person who dialled and the person who answered, for extension-to-extension and external calls alike, from ring to hang-up; the receiver of an internal call used to stay Available, so colleagues rang them and added them to conferences.

  • The transfer / Add-to-the-call picker shows everyone's status and will not let you pick someone who is in a call, busy, on do-not-disturb or offline.

  • Presence updates live on every call event, whichever way the call arrived.

  • People added to a conference show In a call — invitees and consult targets count from the moment they are rung until they leave, are removed, or never answer.

  • Removing someone from a conference is final — they leave and stay out until you invite them again; before, their browser reconnected on its own and put them back in the call.

  • Documents that were never generated no longer come with a link. A document too long for a single generation is retried shorter, then reported honestly instead of as raw text; a download link the agent made up is removed and flagged, and the agent is pushed to really generate the file.

Improved
  • PDF Report Generator retired — deprecated months ago and disabled platform-wide, it is removed from the catalog and from the tool lists of the 35 agents that still listed it. PDF output is the Word Document Generator with output format PDF.

v1.1.13.2“Showing the Work”September 14, 2026

An agent that needs several steps no longer leaves you staring at a still window. From the moment you send a request you see the Arcanflows mark turning, "Working on your request" and a counter — and as the agent works, a short list of what it is doing: the tool it is calling, the sub-agent it is asking, the search it is running, each with a tick and how long it took. When the answer arrives the list folds into a single line you can open again, and a step that failed stays open, because that is usually why an answer disappointed. The list is kept with the conversation, so coming back tomorrow — or to something you sent to the background — still shows what happened.

On a phone call the opposite is true: a caller hears that someone is still there, and never hears any of the detail. The agent fills a long pause in its own language, stops the instant the answer is ready, and never says it more than twice. Tool names, sub-agent names and search terms stay on the screen where they belong.

Also in this release: an agent's safety rules can be edited, not only created and deleted. Correcting a single wrong keyword used to mean deleting the guardrail and building it again from memory; the pencil now opens the rule in the same form used to create it, and saving keeps the rule's on/off state.

New
  • See that the agent is working — the Arcanflows mark, Working on your request and a counter appear the moment you send, and stay while the agent is busy. It replaces a spinner that disappeared as soon as the first word arrived, leaving the rest of a long request looking dead.

  • See what it is doing — a short list of steps as they happen: the tool being called, the sub-agent being asked, the search being run, each with a tick or a cross and how long it took. It folds to one line when the answer lands, and a failed step stays visible.

  • It is kept with the conversation — reopen a chat later, or come back to something you sent to the background, and the list of what the agent did is still there.

  • Names and outcomes only — the list says Searching the web, never what was searched; Odoo search records, never which record. Anyone who can open the conversation can read it, so it carries no customer detail.

  • On a call, presence instead of silence — when a question takes a moment the agent says so, in its own language (Spanish, English, Portuguese, French), stops the instant the real answer is ready, and never says it more than twice in one turn.

Fixed
  • Callers no longer hear the internal Sub-Agent label read aloud before a delegated answer; it belongs to the screen.

  • Your own messages in Team Chat no longer appear twice — the message you sent and the copy that came back over the live connection could both be drawn while the send was still completing.

  • Safety rules can be edited — the pencil on a rule in an agent's Safety tab opens it for changes (keywords, action, scope, priority) instead of forcing you to delete it and start again. Saving keeps the rule switched on or off exactly as it was.

  • The list of what an agent is doing now includes its tools and web searches, not only its sub-agents — a document being generated no longer looks like nothing happening.

  • Agents follow the Arcanflows brand rules again: the name, the ™ and the palette reach the model instead of only the brand tools being available.

  • Reopening a conversation no longer shows each step of the agent's work twice.

v1.1.13.1“Messages in the Phone”September 13, 2026

Texting moves into the phone itself: a Messages tab beside the dialpad in the console, in the docked phone on an app page and in the widget a partner CRM embeds — your conversations, the shared inbox with Claim, a reply box and New. Pictures are real attachments now: send an image, a short video, an audio clip, a PDF or a contact card up to 5 MB, and pictures a contact sends appear inline in the conversation, stored by ArcanFlows rather than left on the carrier. Every outbound message identifies the sender — a header such as ARCANFLOWS, with the opt-out line on the first message of a conversation — configurable on the Messaging tab, and the compose box shows exactly what the contact will receive before you send. Integrators get a click-to-text command, two host events, the seat's session messaging routes, three server-key scopes that send only as a mapped seat, and six webhook events carrying the seat's own CRM id.

Team Chat is a place now, not a pop-up. Operations → Team Chat opens the full workspace: conversations on the left, the conversation in the middle, details on the right — and the header and dock buttons show the same thing in a smaller frame. A message is something you can act on: reply in a thread, react, edit or delete your own, pin it, copy a link to it. Text is formatted, the composer takes several lines, and typing @ picks a teammate who is then told, even if they have the conversation set to quiet. You choose how loud each conversation is (everything, mentions only, or nothing), mute it, pin it to the top, and optionally have unread mentions emailed to you once a day. History no longer stops at 200 messages.

The phone's directory now tells you who is reachable before you ring them: every person carries a coloured dot and a label — available, busy, in a call, wrapping up, do not disturb, away or offline — and it follows changes live. Three fixes for anyone embedding the phone in their own system: transferring a call and adding a participant work from an embedded phone, the panel collapses to one column in a narrow card instead of painting the directory over the dial pad, and a workspace with no webhook subscriptions answers with an empty list rather than nothing at all.

New
  • Messages tab in the phone — beside the dialpad in the console modal, the docked app phone and the CRM widget: own conversations, the shared inbox with Claim, reply and New, refusals inline, allowance and suspension notices, an unread badge.

  • Pictures and files (MMS) — Attach sends an image, short video, audio clip, PDF or contact card up to 5 MB; incoming pictures render inline in the conversation. Attachments are stored under your workspace (and counted in its storage), fetched by the carrier through a short-lived signed link, and removed from Twilio. Numbers outside the US and Canada receive a link inside the text instead.

  • Every message says who sent it — a brand header (ARCANFLOWS: …) on outbound messages and Reply STOP to opt out on the first message of a conversation, both configurable on the Messaging tab; the default is your workspace name, so a new workspace is compliant from the start. The compose box previews the exact text and its segment count.

  • Click-to-text — the widget accepts a text command from the host page (the twin of dial) that opens a prefilled compose; the host receives message_received and message_updated events.

  • Session API for the seat — messages/me, threads, thread detail (+ read, claim), send, preview and media upload, all scoped to the seat behind the widget.

  • Server API scopes — messages:read (tenant-wide conversations, a seat's usage), messages:send (send as a mapped seat, never as the key, through that seat's own gate), messages:manage (assign).

  • Six webhook events — phone.message.received (with the caller context your lookup returned), sent, delivered, failed with the carrier code, opted_out, and phone.user.suspended; every payload carries the seat's CRM id, and stored pictures arrive as signed links.

  • App pages — onMessageReceived / onMessageSent on the webphone component, with event.message_body, event.message_from, event.thread_id and the phone_message_* state keys.

  • Team Chat has a page — Operations → Team Chat: conversations on the left, the conversation in the middle, details on the right. The header icon and the floating button open the same thing in a smaller frame, so the two never disagree.

  • Messages you can act on — reply in a thread, react, edit your own (marked edited), delete your own, pin to the conversation, copy a link. Messages are formatted now: bold, lists, code blocks and clickable links, in a composer that takes several lines.

  • @ mentions — type @ and pick a teammate; they are notified even if the conversation is set to quiet, and @channel / @here work in groups. A conversation someone mentioned you in shows an @ instead of a count.

  • Choose how loud each conversation is — all messages, mentions only, or nothing; mute for an hour or a day; pin to the top of your list. Desktop alerts if you allow them, and an opt-in daily email of mentions you never read.

  • History you can reach — Load older messages walks back through the whole conversation (it used to stop at 200), with day dividers and a new messages line that stays where you left off.

  • See who is reachable — the web phone's directory shows each person's live status beside their extension: available, busy, in a call, wrapping up, do not disturb, away or offline, with AI agents marked separately. It updates as people change status or pick up calls. You can still dial anyone; the dot informs, it does not block.

Fixed
  • A CRM session never reports management rights through the widget; a session is a seat credential.

  • The signed media route answers HEAD and serves correct partial content, which carriers require before they will fetch an attachment.

  • The phone API conformance suite sends the working-tenant pin the console uses; a header change had let it skip most of its checks silently.

  • Team chat voice notes are fetched through the same membership-checked route as files: a copied link is useless to anyone outside the conversation, and they now count toward the workspace's storage and its retention settings.

  • Team chat no longer loads everything twice on every page, and closing the panel no longer marks messages you never saw as read.

  • You can start a team chat conversation without the handoff permission — chat has its own teammate directory.

  • A conversation preview no longer stops updating when a message is cut mid-character (any accented text could trigger it).

  • Transferring a call, and adding someone to one, now work from an embedded phone — the widget was sending the target extension in a shape the API could not read.

  • The embedded phone fits a narrow card again: below about 520 pixels the directory moves under the dial pad instead of over the digits.

  • A workspace with no webhook subscriptions answers with an empty list instead of nothing, so integrations no longer break on their first run.

v1.1.13.0“Text Messaging”September 13, 2026

SMS and MMS join the phone system. Before anything can be sent, ArcanFlows verifies your own Twilio account — Messaging Service, sender pool, A2P campaign and brand — and keeps one readiness verdict. Every number you own is registered with the capabilities the carrier reports, and one SMS-capable number becomes the workspace's messaging number. Texts arrive on a signed, per-workspace webhook and land on the right person: the owner of a dedicated number, the owner of the open conversation, or the shared inbox as unclaimed; who a message was attributed to when it arrived never changes. The new Messages page shows Mine, Inbox and All with claim, assign, transfer, release and close. Sending goes through the Messaging Service with a fixed gate that names every refusal — suspension, workspace pause, readiness, permission, the extension's switch, your allowance, number capability, opt-out, quiet hours, plan quota. Billing meters SMS and MMS segments; admins get per-user counters, allowances, suspensions, a workspace pause and a full audit trail.

New
  • Messaging readiness — the platform verifies the workspace's Twilio Messaging Service, sender pool, A2P 10DLC campaign and brand through the workspace's own credential and keeps one verdict (ready / pending / blocked / not configured); Verify now re-checks.

  • Numbers with capabilities — every number is registered with voice / SMS / MMS as Twilio reports it, synced on demand; the number search shows capabilities and can ask for SMS-capable numbers only; one number is designated as the workspace's messaging number.

  • Receiving — a signed, per-workspace webhook (Twilio's signature validated with the workspace's own token; retries store one row); messages resolve to a dedicated number's owner, the open conversation's owner, or the shared inbox; STOP / START / HELP recorded.

  • Messages page (Operations) — Mine, Inbox and All; claim, assign, transfer with a note, release, close; attribution shown under every message; live updates.

  • Sending — reply box and New message, from the workspace number or your dedicated number; refusals name their reason; quiet hours in the contact's local time (default 08:00–21:00, per-workspace window and time zone; a manager may override once, on record); delivery status returns onto the message.

  • Metering — SMS and MMS billable segments, inbound and outbound, with plan allowances, overage rates, tenant overrides and add-on grants; visible in the usage view.

  • Per-user controls — counters per user from a ledger written with every message, daily and monthly allowances, manual and automatic suspensions (opt-out complaints, carrier filtering, repeated breaches), a workspace pause, and an audit log; the Who may send, and how much card on the Messaging tab.

Fixed
  • The delivery-status webhook used by notification channels accepted unsigned requests; it now validates Twilio's signature before writing.

  • The billing period refresh had silently dropped the web-search limit since that bucket shipped; repaired.

  • A Messaging Service whose campaign had failed read as merely pending; blocked now wins.

v1.1.12.6“Hang Up Means Hang Up”September 13, 2026

The first real third-party CRM integration of the embedded phone and a conformance pass over all 53 phone API routes (286 checks, all green on this build). For integrators: call filters that mean what they say, CRM fields on call detail, stable response shapes, seat provisioning that attaches to an existing extension instead of creating a second one plus a lookup route, webhook secrets never echoed, recording links only for files that exist. For the embedded phone: the realtime socket production had refused since the widget shipped now connects (incoming calls ring, click-to-call reaches the seat), a console login in the same browser no longer mounts a second phone, and leaving the page delivers the hang-up. For every workspace: a far end left alone is hung up within 90 seconds, the attendant's "are you still there?" ends in a goodbye after 20 seconds and is asked at most three times, and dialing the workspace's own number is refused.

Improved
  • Phone API conformance suite — every one of the phone's 53 public routes, 286 checks; the gate for phone releases from now on.

  • Seat lookup — GET /server/seats/lookup?email=|external_user_id= says what provisioning will do; the directory lists each human extension's email.

  • Widget — host page guarded against reload/close during a live call; the phone renders docked inside its iframe; PROPOSAL-080 S9/D11 written up; reference CRM at github.com/windconsul/arcanflows-crm-demo.

Improved
  • external_user_id and extension call filters both mean "calls involving the seat"; call detail carries the CRM fields; documented fields are always present.

  • Provisioning a seat for someone who already has an extension attaches the id to it (adopted: true) — never a second seat; 409 when their extension carries another id.

  • Webhook secrets are never echoed to server keys; unknown subscription delete is 404; past expires_at rejected; status note over 200 chars is 400; dial abc is 400.

  • Recording links are minted only when the file exists (not_ready for two minutes after a call ends); a sweeper clears paths the egress never wrote.

  • The embedded phone's realtime socket connects from the console origin (production had refused every one); a console login in the same browser no longer mounts a second phone inside the widget; the page-leave hang-up goes out as a beacon.

  • Call supervisor hangs up a far end left alone within 90 seconds; the voice agent's idle prompt reaches its goodbye and is asked at most three times; calls to the workspace's own number are refused.

  • The served OpenAPI document reports the running version.

v1.1.12.5“The Phone Joins the Page”September 12, 2026

The workspace phone is now a component in the App builder: place it on a page and it docks there for any signed-in user who owns an extension — the same single phone the console already runs, so a live call survives moving between pages. The phone also drives the page: a call rings, the caller's number and the CRM's name land in app state, the form beside the phone fills its empty fields without touching what the agent already typed, and when the form is saved the call and the submission point at each other.

New
  • Web Phone app component: dock the workspace phone into any app page for signed-in users who own an extension. It is not a second phone — the one you already have moves into the page and floats again when you leave, so a call in progress is never interrupted. Viewers without an extension, or apps with their own accounts, see a short explanation instead.

  • The phone drives the page: every call raises events a page can act on (ringing, caller identified, answered, held, resumed, ended, missed) and publishes the live call into app state. Wire caller identified to a state update and the form beside the phone fills in the caller's number and CRM name, leaving anything the agent typed untouched.

  • Calls and form submissions linked both ways: save a form during a call and the submission carries the call id while the call carries the form reference and a form_submitted tag.

  • Click-to-call from any component: bind the phone's dial target to a table row or a button and a click places the call.

  • Phone desk template: a ready-made page with the docked phone, a customer form and a recent-calls table, already wired.

Fixed
  • Form prefill inside apps now fills only empty fields instead of replacing the whole form whenever its bindings change — a latent way to wipe a half-typed form.

v1.1.12.4“Everything In Its Place”September 12, 2026

We spent this release trying to break the embedded phone on purpose. Six drills — a key revoked mid-call, a session expiring mid-call, spoofed origins, a CRM lookup that never answers, a webhook receiver down for ten minutes, and fifty embedded seats ringing at once — found four real defects, all fixed here. Phone webhooks now survive a ten-minute outage at your end, one dead receiver no longer holds back everyone else's events, and the Phone System page is organised into five tabs instead of nine stacked cards.

Improved
  • Phone webhooks survive a ten-minute outage at your receiver: a phone.* subscription now retries for about 17.5 minutes (7 attempts) instead of 2.5 minutes, so a maintenance window at your end no longer loses call events. An explicit retry policy always wins, and existing subscriptions keep their settings.

  • One dead webhook endpoint no longer stalls everyone else: deliveries used to run inside the event loop, so a receiver that stopped answering held back every event on the platform for its whole retry cycle. They now run in parallel, bounded.

  • Large ring groups ring all at once: the web members of a ring group were called one after another, so the last seat of a big group started ringing noticeably late. Measured after the fix: fifty embedded seats all ring within about 50 ms of each other.

  • An embedded phone whose session was revoked now ends its call instead of appearing to still work: ten seconds of grace for a renewed token, then a normal hangup.

  • Steadier database access under load: the connection pool was sized by CPU count while background maintenance jobs each hold a connection for the length of their run, so enough overlap could leave the platform unable to reach its own database. The pool is now sized explicitly and a job can no longer wait forever for a connection.

Improved
  • The Phone System page is now five tabs — Numbers, Extensions, Ring groups, Integrations and Settings — instead of nine cards in one long scroll. The CRM features (embed keys, caller lookup) sit together under Integrations, and every tab can be linked to directly.

v1.1.12.3“The CRM Knows Who's Calling”September 11, 2026

The embedded phone gets its data half. A CRM or ERP backend now holds its own scoped server key: call history and statistics, write-back of its record ids, tags, notes and outcomes onto our calls, click-to-call through a seat's open phone, phone-event webhooks, and just-in-time seats for its own users. And before an inbound call is routed, the platform can ask the CRM who is calling — greeting by name, screen-pop context, and CRM-directed routing — falling back to today's routing whenever the CRM does not answer.

The phone is also a documented product for developers now: a phone-only OpenAPI specification served at a public URL, a Phone API quickstart and interactive reference on the documentation site, a Phone webhooks guide that states the delivery contract from the code that sends it, and TypeScript types generated from the specification.

New
  • Phone server keys (pbxs_): a scope-gated key for your backend under /api/v1/public/phone/server — tenant-wide call history with filters and CSV export, call detail, one-hour signed recording links, the console's statistics and per-ring-group queue figures, presence, groups and seat status. Managed on the Phone System card under Server keys; every call audited.

  • CRM write-back: stamp your own record id, tags, notes and outcome on any call, then filter history by them.

  • Click-to-call from the CRM: originate asks the seat's open web phone to dial; you get 409 seat_offline when nobody is there to place it.

  • Just-in-time seats: one idempotent call turns a CRM user ArcanFlows has never seen into a phone-only identity with a web extension from the workspace's reserved range (default from 300).

  • Phone webhooks from the server key: create and manage phone.* subscriptions with the webhooks:manage scope.

  • Caller lookup: point the workspace at a URL your CRM answers; before routing, the platform asks who is calling (signed, hard timeout, cached, fail-open), greets the caller by name in the attendant and voice agents, pops the record on the ringing agent's screen, carries caller_context on every phone event and — when you allow it — routes to the extension or ring group your CRM names. Live "Ask the CRM" test and miss/timeout counters on the Phone System card.

  • Phone API for developers: every phone route has OpenAPI coverage and a phone-only specification is served at /api/v1/public/phone/openapi.json; the documentation site gains a Phone API quickstart (/documentation/api/phone) and an interactive reference (/documentation/api/phone/reference) that renders the live specification.

  • Phone webhooks guide: headers, HMAC-SHA256 signature over the raw body, retry policy (3 retries at 5/30/120 s), timeouts and the payload of each of the seven phone events, with Node and Python verification snippets. TypeScript types for the phone API are generated from the specification.

v1.1.12.2“Every Call Tells Someone”September 11, 2026

The phone system now talks to the rest of your software, and the phone itself moves into it. Every call, every agent handoff and every seat status change is a platform event you can subscribe a webhook or a workflow to; and the web phone ships as a drop-in widget for any CRM or ERP page. Two long-standing event-router defects are fixed for everyone.

New
  • Phone events for webhooks and workflows: call ringing, answered, completed (with duration, summary and a one-hour signed recording link), missed, transferred, voice-agent handoff requested, and seat status changed are catalogued events — subscribe a webhook or use them as workflow triggers, no code.

  • Drop-in phone widget: one script and one line render the console's own web phone inside any CRM or ERP page on the ArcanFlows origin, with ring, call and status events streamed to the host page and click-to-call from it. A ready-made test page ships at /embed/phone-test.html.

  • Webhook-only event subscriptions (no workflow attached) now work.

Fixed
  • Event subscriptions no longer receive other workspaces' events.

  • New event subscriptions are matched immediately instead of after a cache that could stay stale for minutes or indefinitely.

  • Embedded phone resolves the API at runtime and reopens its dialpad after a hangup or a failed dial.

v1.1.12.1“The Phone Goes Where the Work Is”September 11, 2026

The release that lets a customer's phone system live inside whatever software their team actually works in. A CRM or ERP backend holds one embed key; its users get short-lived, single-extension sessions; the browser rings, answers, holds, transfers and sees presence through the same code the console uses, with every action audited and recordings leaving only as short-lived signed links. Also: the whole-cluster view for administrators, pending handoffs that page someone instead of aging invisibly, and a Microsoft Graph fix for semicolon-separated cc/bcc lists.

New
  • Embed the webphone in your CRM or ERP: create a phone embed key on the Phone System page; the other system's backend exchanges it for 15-minute, single-extension sessions — by extension id or by that system's own user id — and its users ring, answer, hold, transfer, set status and see presence from inside their own tools.

  • Session ledger and activity trail: every embedded session is visible (host, IP, opened, expires) with a Close button, and every action an embedded seat performs is recorded under Show recent activity.

  • Recordings only as short-lived links: an embedded seat can fetch a call's recording through a signed 10-minute URL, never a permanent one.

  • Whole-cluster view for administrators: one page shows every server with CPU, memory, disk, load and containers, and says plainly when a server cannot be reached.

  • Pending handoffs page someone: a handoff waiting longer than the configured minutes alerts the workspace's owners and admins, once, instead of aging unseen.

Fixed
  • Embed pages enforce their domain allowlist in the browser: agent, dashboard and phone embeds now send a frame policy derived from the key's allowed domains, so a restricted key cannot be framed from another site.

  • Microsoft Graph cc/bcc lists with semicolons no longer fail with HTTP 400; both comma and semicolon separators are accepted for to, cc and bcc.

  • Infrastructure page sections below the cluster cards are labelled with the server that answered instead of flipping silently between servers.

v1.1.12.0“Built to Lose a Node”September 10, 2026

The release where the platform stopped depending on any single machine. The web edge is now active-active behind a network load balancer that removes a failed server from rotation in under thirty seconds with no human involved. Inbound phone calls fail over automatically through a second carrier route. The data layer is addressed by stable internal names, with the standby database one command away from taking over. And none of it is theory: the edge failover and the phone failover were both drilled the same day — the latter with a real phone call answered normally while the primary telephony node was deliberately offline.

New
  • Automatic edge failover: all public hostnames now route through a health-checked load balancer across both application servers — a server failure removes it from rotation in under 30 seconds, automatically.

  • Automatic phone failover: incoming calls reach a second, independently verified telephony stack if the primary does not answer — proven with a live call during a controlled drill.

  • Database failover in one command: the standby database (already replicating within milliseconds) can be promoted and traffic repointed in minutes, with the procedure documented and the dangerous edges spelled out.

  • Deploy safety: the pre-deploy gate now refuses to deploy while any phone call is live, on development and production alike.

Improved
  • Both application servers now serve traffic simultaneously — capacity as well as safety.

  • Failover procedures are executed drills with recorded timelines, not untested documents.

  • Architecture documentation updated to reflect the new topology end to end.

v1.1.11.2“Booked Where It Belongs”September 9, 2026

The release where things land where they belong: calls in the right tenant, browser tabs in the right workspace, models chosen on the node that uses them, and support calls given the hours they actually run. A report that one tenant's extension was being counted in another's workspace unraveled to a resolver that threw away the caller's tenant on shared trunks — fixed, proven against the live collision, and the mis-booked calls moved home with an audit trail. The 4-hour call ceiling (enforced, it turned out, in five different places) became a 4h default with per-tenant grants up to 8 hours, each tab now pins the tenant it works in, and the Studio gained the accountability it was promised: a run log that turns "several nodes fail" into queryable facts, honest translated errors, real downloads, resizable nodes, capability-driven controls, and a per-node model picker.

New
  • Per-tab workspace pin: each browser tab remembers which organization it is working in — switching tenants in one tab no longer switches every other tab mid-task.

  • Studio run log & honest errors (PROPOSAL-082 S1b): every node run — success or failure — is recorded with engine, parameters, latency and the full error; failures open a detail modal, recurring provider errors (content filter, quota, rate limit, bad API key) are translated into plain language, and Platform Health gained a Studio tab.

  • Studio capability-driven controls (P082 S1): duration selectors show what the selected engine can actually render — fixed-duration engines say so instead of silently ignoring the setting; downloads save the file with a real name; image and video nodes are resizable with a full-size lightbox.

  • Model picker on Studio nodes (P082 S2): pick the model within the engine (e.g. wan2.2-i2v vs wan3.0-video-prime on the same account) right on the node — the list comes from the backend''s own supported-models configuration.

  • Call duration limits by demand: the platform default is 4 hours, and individual tenants can be granted 5, 6, 7 or 8 hours — or tightened below — from the capacity dialog. Real support calls run past four hours; they no longer get cut off mid-conversation.

  • Builder guided goal cards: visual what-do-you-want-to-build cards replaced the example lists, and the Builder''s plan quality went under regression guard with app-level golden cases.

Fixed
  • Calls book to the right tenant: on shared trunks, extensions that exist in more than one workspace resolved to whichever created them first — one tenant''s calls were counted (and billed) in another''s. Resolution is now scoped by the caller''s own workspace, and the mis-booked calls were re-assigned with a full audit trail.

  • Hold music is for the caller: operators and transfer targets no longer hear the hold-music bed during consultations; a declined or unanswered transfer now auto-cancels and notifies the operator instead of leaving the caller parked in silence; a mid-call page refresh recovers the call.

  • Backend edits apply immediately: changing a video/image/voice backend''s model, URL or key now takes effect on the next generation instead of after the next platform deploy.

  • Longer videos by chaining: connecting one video node into another continues the clip from its last frame instead of failing — and image-seeded generation works on models that support it regardless of naming.

v1.1.11.1“Signed, Sealed, Delivered”September 5, 2026

The release where "sent" stopped being taken on faith. A week of silently dead email traced to one Microsoft-blocked mailbox taught the platform that acceptance is not delivery — so mail is now DKIM-signed, dev is structurally unable to spam, and outbound email governance has a proposal and its first stage live. The same honesty landed on the phone system: every call is classified by whether it actually cost money, historical prices were repriced to the carrier's own numbers with a full audit log, hold music finally dies with the hold, and the two mysterious 20-second delays QA and the billing data measured from opposite ends turned out to be the same bug — teardown listening to media timeouts instead of signaling. PROPOSAL-074 COMPLETE (all stages + all four decisions), PROPOSAL-076 COMPLETE (the QA acceptance sheet answered), PROPOSAL-077 COMPLETE (the Builder learns what it spends, shows it, and can be limited and sold), PROPOSAL-075 S0, plus P059 D5–D7 resilience work — on dev and production.

New
  • Call billability classification (P074 S0, migration 000432): every call

  • Outbound calls reconcile at last (P074 S1): the endpoint match was

  • Call legs become first-class (P074 S2, migration 000435): one row per

  • The call ceiling is a tenant setting, and it pages (P074 S4, migration

  • Tenants see where their minutes go (P074 S5): five scenario tiles on

  • Billability-from-legs, in shadow (P074 D4): a new gate under which a

  • Presence in the upper bar and meters in the call widget (P076 S4+S5):

  • Recording integrity watch (P076 S3): every five minutes, calls whose

  • The Builder starts measuring itself (P077, migrations 000436/000437):

  • Outbound email governance, stage 0 (P075): the two email tool contracts

  • Ringback for internal calls (P076 S2): an extension-to-extension caller

  • WAL archiving with proven point-in-time recovery (P059 D7): production

  • Qdrant RAG replication (P059 D5): every shard of both vector collections

  • Per-node companion guard (P059 D6): a post-deploy check that proves the

  • Workflow execution settings are editable — a workflow's timeout,

Fixed
  • The email outage — Microsoft had placed the platform's single shared

  • 57 calls claimed both "never touched a carrier" and a carrier charge

  • Hold music finally dies with the hold (P076 S1): stops are room-keyed

  • The two 20-second constants (P076 S2): a declined internal call took

  • Hold-music lifecycle, complete (P076 S1): room-keyed stop flags (a stop

  • Call waiting closed without building (P076 S6, owner decision): the

  • The web phone says how each recent call ended — Answered / Missed /

  • Every table on the super-admin phone page paginates — extensions,

Improved
  • The production edge configuration (Caddyfile) is under version control —

  • [email protected] email tasks on dev are paused and dev sends sink to

v1.1.11.0“Nothing Ships Stale”September 3, 2026

The public site stops needing a deployment to tell the truth. Privacy, terms, FAQ and a new About page are edited and published from the console; /release replaces a hard-coded changelog whose newest entry was nine months and 33 releases out of date, and imports the real one; and the footer finally points at the pages it had been advertising with dead links. PROPOSAL-073 S1, S2, S3, S3b and S5a — on dev and production.

New
  • Content-managed public pages (migration 000430): site_pages +

  • /release — the release history (migration 000431): public page with

  • /about, reusing the existing showcase page type rather than adding a

  • Super-admin navigation in five feature groups (Platform, Tenants & People,

  • Talk to an agent on the contact page: pick an agent, authenticate with an

Fixed
  • Unpublishing a page now takes it down. Both public loaders cached their

  • The contact page rendered neither its form nor its assistant — both were

  • Selecting a channel kind now changes the row. Choosing "Phone" on a

  • The contact form is chosen from a list, not a UUID typed from memory, and

  • PUT /site-pages/:slug validates its slug. It required one in the body

  • The CHANGELOG importer stopped inventing facts. An unreadable date

  • Footer links that were never wired: "About" and "Careers" were href="#"

Improved
  • Dev drops the dev6 hostnames, which resolve to the production cluster.

v1.1.10.9“Nothing Fails in Silence”September 3, 2026

Rolls up one theme found five ways in 24 hours of live onboarding: the platform failing QUIETLY. Now it pages, persists, explains, and shows the truth instead. P067 S1 (self-monitoring, verified live on prod), the background-chat loss fixes, the RAG pipeline integrity package, the phone/dock fixes, and the Outbound calling card.

I sent it to background and it evaporated
Loaded must mean retrievable

The MultiGla receptionist showed two "loaded" documents and held ZERO vectors. Chain: invisible ingestion → user re-uploads → catalog dedupe skips re-ingestion but the new row still claims vector_stored → phantom rows share ONE set of vectors carrying the FIRST row's id → user deletes the "duplicates" → purge destroys the document's only knowledge → the catalog still says loaded, so re-uploads are skipped-as-unchanged forever. Platform audit: 160 of 253 catalog rows point at vanished vectors.

It never rang, and I was right there

Live prod findings while onboarding MultiGla Services and testing extensions (all deployed to dev AND prod the same evening):

The platform notices its own failures
Fixed
  • Stuck-pending chat jobs are reaped (CHAT_JOB_PENDING_STALE_SECONDS,

  • Dead-lettering tells the user (bulk move and per-job): notification +

  • Failed background chats keep the user's words: the message and an

  • Conversation rows stop lying: the background persist path updates

  • One row per (agent, filename): re-uploads REINDEX onto the existing row

  • Share-aware delete: vectors survive while sibling rows reference the

  • pip in the rag-service image survives a flaky PyPI (120s timeout, 10

  • An open dialer swallowed incoming rings: the web dock treated

  • The attendant denied ring groups existed: S6's extension_groups

New
  • GET /api/v1/documents/status (rag-service) + `GET /agents/:id/

  • Knowledge tab renders the truth, polled every 20s: "Ready · N chunks",

  • The edit page's Save→train flow — the path that actually minted the

  • Found while verifying live: the default min_relevance: 0.5 silently

  • Outbound calling card on the Phone System page: shows whether the

  • Failure-rate sweep (workflow_health_alerter.go, 5-min cadence, one

  • Kafka canary probe (60s, on EVERY app node deliberately — the Sep 1

  • Delivery: bell notification to every active super admin + the System

  • Config (all optional, defaults sane): WORKFLOW_HEALTH_ALERTS=off,

v1.1.10.8“Please Hold — Someone Will Be Right With You”September 2, 2026

P063 COMPLETE. Rolls up: S7 call queue (FIFO with hold music in the caller's own room, depth/max-wait caps, ring-lease turn-taking), S4 announcements over the music, per-answer round-robin, overflow-attendant with the routing menu, and the server-truth answer-detection fix.

The hold line speaks
Please hold — someone will be right with you
New
  • Announcements over hold music (P063 S4 — the final P063 stage): every

  • Call queue (P063 S7) — migration 000429 group_queue_entries. When

  • v1 edges closed: round-robin now advances PER ANSWER (the claim moves

Fixed
  • Callers heard ringing long after the member answered: group-ring

v1.1.10.7“Compliant, Announced, and Ringing the Team”September 2, 2026

Rolls up: P063 S8 (group DIDs), unavailability announcements, the Twilio A2P compliance bundle (signup opt-in + settings consent + terms §5.4 — already live on prod ahead of this tag), the web-phone modal fix, the dev LiveKit URL fix, and the Kafka self-hairpin hardening (incident Sep 2).

The Sales number rings Sales
The opt-in Twilio was promised
Telephony terms of use
Not available means you hear it
New
  • Group DIDs (P063 S8) — migration 000428: a purchased number can ring

  • SMS opt-in at signup (Twilio A2P campaign requirement): the register

  • Reconsider any time — Settings → Profile → SMS Notifications: each

  • Terms §5.4 — Voice, SMS/MMS & WhatsApp Communications: telephony

  • Unavailability announcements (owner request): calling a person whose

Fixed
  • The S9 status picker blew the web-phone dock out of its modal (§5b

v1.1.10.6“The Team's Number Rings the Team”September 1, 2026

Rolls up every entry from here down to v1.1.10.5: P063 S5+S9+S10+S6 (ring groups, user status & presence, outbound caller-ID policy, live group ringing with claim/overflow), the group-call lifecycle fixes, the web-phone hooks crash fix, and the dev LiveKit URL fix (dev web calls had silently pointed at prod's LiveKit since the Aug 29 DNS cutover).

The team's number rings the team
Who's free, and what number shows
Teams get a number
The caveats catch up with reality
The contract layer closes
New
  • Group ringing (P063 S6) — dialing a ring-group extension now rings the

  • The attendant now routes to teams: groups appear in its directory and

  • The web phone can dial a group (webint room carries the group payload;

  • User status & presence (P063 S9) — migration 000425: user_phone_status

  • Outbound caller ID policy (P063 S10) — migration 000424. One tiered

  • Ring groups (P063 S5) — migration 000423 creates extension_groups +

  • Dial-space integrity — group numbers live in the same global dialplan

  • Axis B (key shape): a per-component contract registry of canonical

  • Axis D (wiring): a CI invariant that every cross-component ref

  • G-H: migration 000422 teaches auth_mode and allow_registration

Improved
  • The owner verified S6 in the UI (re-invite after delete + custom app-role

v1.1.10.5“Proven Builds, Honest Answers”August 31, 2026

Closes the last places where the Builder failed quietly: drafts that vanished mid-pipeline, and three separate causes behind a single hallucinated conversation. Builds now prove what they produced, and data-table shares get a branded public page with per-share overrides.

Nothing vanishes anymore
The retired provider that kept hiring itself
Nineteen thousand relics get a shelf life
The marathon that never happened
The exam build's three truths
A dropped connection no longer eats the turn
Built is a claim; verified is a fact
The share page learns about night
Anonymous access that actually opens the door
The share page joins the brand
New
  • P070 S4 — the Builder proves what it built: post-build checks EXECUTE components (probe rows through live validators, probe submissions through published forms with the table row asserted, one real agent turn, app-reference resolution); every delivery card reports verified / unverified / failed with the reason.

  • P070 S5 — nothing vanishes anymore: all five silent-drop sites report through user-visible channels (failure cards, proposal notes, build-summary notes); unknown proposal types fail loudly; app component types validated on write against the full renderer union; action_data_share taught to the Builder with a full node contract.

  • P071 kind-backfill EXECUTED on prod: 16,120 pre-S1 learned points classified at their own learned_at; the sweep retired 2,096 expired relics (learned share 20.8% → 16.1%).

  • POST /admin/learned/backfill (rag-service): classifies the ~19k pre-S1

  • Light/dark theme on the public share page: follows the visitor's system

Fixed
  • Agent hallucination triad (the CDMX-marathon autopsy): Spanish queries now search in Spanish; a temporal-integrity rule stops a previous edition's results being presented as today's; reasoning-only turns get one plain-text nudge before the generic fallback.

  • Builder exam findings: agents finally have an Enable path (draft → active); an exam plan without its wizard form is a wrong plan (hard planner rule); a dropped stream no longer loses the turn (server-side persistence + UI keeps drafted cards).

  • P066 convergence: the retired searxng provider stopped hiring itself — migration 000421 converged all agents/templates on serpapi; create/update normalize; the form fallback fixed.

  • New agents created from templates regressed onto searxng — the

  • Search in the wrong language: the agent had no language configured,

  • No temporal integrity rule: the model presented a *previous

  • Reasoning-only turns surrendered instantly: qwen3.8 burned 1,882

  • Agents can finally be enabled. Builder-created agents are drafts, the

  • An exam plan without a form is a wrong plan. The planner swapped the

  • Not changed, by design: question banks ship EMPTY unless the user's own

  • A network blip mid-Builder-stream (mobile connections, proxies) canceled

  • With Require Registration disabled, share login returned an empty

v1.1.10.4“Share Links & Branded Mail”August 31, 2026

Document sharing grows up. Share links carry row filters, workflows can share a table as a step, and the brand frame becomes the default for every system email rather than a handful of them.

The switch that lied about the default
Every email wears the mark
The node controls what the dialog controls
The secret that escaped, and the email that never left
Share the rows, not the table
The share procedure becomes a node
New
  • action_data_share workflow node: the manual sharing procedure as one step — create a share + read-only password token, output share_url/password for a follow-up email/notification node. Full dialog parity: visible fields, row filters (customer = {{input.name}}; status != closed), require-registration/search/export/page-size. Migrations 000417–000419.

  • Row filters on data-table shares: share one customer's rows from a mixed table — enforced on listing, reads, writes, deletes and file downloads (fail closed). Filter editor in the share dialog's Settings tab.

  • The brand frame as the default for all system emails: brand.EmailFrameAuto at every send boundary (tenant chain, system SendGrid, legacy notifications, email channels); complete documents pass through, fragments framed, plain text escaped tag-aware. Router's reset/invitation/verification emails re-skinned onto the frame.

  • action_data_share now exposes the share dialog's settings: **Require

Fixed
  • Run-wide secret scrubbing: sensitive values (share passwords) redacted from every persisted node output — including downstream nodes that interpolate them.

  • The legacy email channel marked notifications "sent" while sending nothing when SendGrid was unconfigured; it now rides the tenant chain and fails honestly.

  • Workflow node boolean switches rendered unset keys as OFF while the backend default was ON.

  • Deleted workflow node types cleanup (migration 000415) and dead app_component_type enum.

  • Workflow node boolean config switches rendered unset keys as OFF even

  • Secrets scrubbed run-wide. Redaction stopped at the producing node:

  • The legacy email channel stopped lying. With SENDGRID_API_KEY

  • The Data Share Link node rendered as an unstyled white box: it was

v1.1.10.3“Knowledge Hygiene & the Portal Door”August 30, 2026

Published apps become usable products: a signed-in user menu, emails sent through the tenant's own mail configuration, and the four portal blockers fixed in one shape. Learned knowledge is labelled as learned where the model reads it, acts on whole documents, and gets a lifecycle sweep that is dry-run by default.

A door on the portal
The email path apps never got
Checks that disagreed with reality
Told before Build, not after
Measured against the renderer, not the palette
Builder can finally use the tools you already have
Prove it
Review that people will use
Say what it is
Retention that retires things
Knowledge with a shelf life
A transaction is not knowledge
Every call to a tenant number is a call
Each call is its own conversation
The same nil, one floor down
New
  • P071 RAG knowledge hygiene, S0–S5 complete: execution-origin learning gate (fail-closed — scheduled/workflow/background runs never learn), answer-content veto, per-agent conversation_learning modes (off/interactive/all), unlearn-on-delete for conversations, kind + valid_until classification (transactional/news vs durable knowledge, capped LLM judge), lifecycle sweep with real deletion — 19,530 stale points removed on day one (38.6k → 19.1k) and a nightly autonomous sweep, doc-level review + promote-to-document, negative eval probes (probe_type=negative_learned, migration 000414) and the Knowledge hygiene card.

  • P070 Builder, S3(C+E)/S6/S7 + G18/G19: Builder binds existing workspace tools by name instead of drafting duplicates; renderability coverage tests incl. the first apps parity check (axis E); capability caveats surfaced on the plan card before Build plus GET /builder/capabilities; and the four portal blockers fixed — app-defined roles assignable (create + update), a deleted email can be re-invited (migration 000416: live-rows-only uniqueness + SQLSTATE 23505 detection), invite responses carry a shareable invite_link, route permission is the single authority.

  • Apps get a door: signed-in user menu in every authenticated app (avatar, profile dialog with editable name + change-password, honest sign-out labeling per auth mode; PUT /auth/me, POST /auth/change-password).

  • App email delivery joins the tenant chain: portal invites/resets/forgot-password route tenant office365/OAuth → fallback channel → system SendGrid, same as platform emails; email_sent is honest.

  • Phone: each call is its own conversation (tel-<caller>-<room>); every call to any tenant number is logged and billed, unassigned numbers answered by the attendant; read-back rule for captured phone/email data.

  • App Users mode: profile is editable (first/last/display name) and

  • Platform mode: identity shown read-only; sign-out is labeled

  • Public mode (or the flag off): no menu, nothing changes.

  • an app_users app: the pages and auth screens build, but app-role

  • a platform (staff-only) app: existing staff sign in fine, inviting NEW

  • Axis C (renderer_coverage_test.go): every field type the Builder may

  • Axis E (app_coverage_test.go): the console's AppComponentType

  • Migration 000415 drops the dead app_component_type DB enum (a third,

  • Negative probes in the RAG golden set (migration 000414): a question

  • Platform metrics. rag-service POST /admin/learned/stats (indexed

  • Agent Health → Knowledge hygiene card: learned share vs the ≤ 10%

  • rag-service POST /admin/learned/sweep (admin key) evaluates every

  • POST /admin/learned/snapshot creates a Qdrant snapshot of both

  • agent-manager KnowledgeLifecycleSweeper: nightly

  • Super-admin routes POST /api/v1/admin/rag/lifecycle/sweep and

  • explicit dates in the question or answer → valid through the latest date

  • "hoy / today / esta semana / this week / este mes / this month", and the

  • prices, exchange rates, availability, "current version", "actualmente"

  • no signal → a small LLM judge on the agent's own model (owner decision

Fixed
  • Post-P054 workflow node rows left running forever after a done-context write; fresh close-out context.

  • The stale "email delivery is not configured" message on tenants with working email configuration.

  • FRONTEND_URL unset now fails loudly (response warning + ERROR log) instead of silently mailing localhost links.

  • G9: apps define their own roles, but role assignment accepted only

  • G10: the uniqueness constraint counted soft-deleted rows while the

  • G11: the invite token lived only inside an email that might never

  • G12: a role gate duplicated inside InviteUser/ResendInvitation

  • It could not bind existing tools. A tenant asked Builder — twice,

  • Enable telemetry counted facts as failures. *"data_table X: type has

  • The inbound resolve now carries inbound=1, caller and room; when there is

  • The worker hangs up immediately (deletes the room) instead of leaving the

  • Order. InitDataTableServices now runs immediately after the workflow

  • Constructor. NewDataTableAdapter panics at boot on a nil record

  • Engine. executeNodeWithRetrySafe wraps every node executor call: a

Improved
  • One row per learned document; every action — approve, delete, and the new

  • Each row shows kind (durable / time-bound with its validity, or expired),

  • Filters: kind, never served, expired only, older than N days — the same

  • A composition strip: document chunks, attachment chunks, learned durable /

  • API: GET /agents/:id/learned-knowledge?kind=&never_served=1&expired_only=1&origin=&older_than_days=,

  • Retrieval hits are routed by their payload source: conversation-learned

  • SemanticMemoryKnowledgeSource removed and unwired.

  • rag-service: chat_attachment gets its own rank tier (+0.04, between

  • Execution origin. ExecutionRequest.Origin (interactive, channel,

  • Turn trace. Any tool call (recorded at the executeCustomTool choke

  • Content vetoes on the answer: the model's own question back to the

  • Per-agent mode configuration.conversation_learning = off |

  • Unlearn on delete. Deleting a conversation now deletes its training

  • Learned items now carry origin in their metadata for S1/S2.

v1.1.10.2“Carrier Truth & Honest Failures”August 30, 2026

Carrier truth and honest failures. Every agent data-table write had been crashing agent-manager since August 20; a workflow node that hung forever was recorded as nothing in particular; and a failed write left no trace anywhere. Phone agents now read numbers and email addresses back before recording them, and stop speaking formatting meant for a screen.

The agent said *ahora llamo a la herramienta* and the server died
Three failures that left no trace
The word *factura* disarmed a CRM agent
A background job that cannot finish, and the reaper that made sure of it
A gated app stops answering strangers
The drafter's answer, kept

Four small Builder defects from the P070 audit, each costing something on every single build, each with a test that fails without its fix.

A repeater the platform can actually run

The previous entry repaired the stored sub_fields on MultiGla Services' carga-de-documentos-1787888034. It never checked that the platform can RENDER those sub-fields. The owner found the rest by using the form. Three gaps, all closed here.

A repeater that repeats

MultiGla Services' form carga-de-documentos-1787888034 shipped a repeater ("Archivos a Subir") that rendered the placeholder "Configure repeater sub-fields in the properties panel" — to end users. Owner: "at least Builder should deliver a first functional version."

Empty schemas are deletable

Owner: "if schemas don't have tables, we should be able to delete them, and avoid having empty schemas there."

One column never costs the build

Production regression fix (P054 S8f). MultiGla Services asked the Builder to extend their client-portal app; the Builder drafted the change and then delivered nothing, twice, with: Partial: could not update data table "Documentos Recibidos": field 9: reference field must have a reference table ID

Carrier Truth

PROPOSAL-068 S5, voice half. SMS/MMS do not exist yet, so this is scoped to voice — which is the larger exposure anyway, because it has been live and billing customers from a guess.

New
  • P068 S5 (voice): carrier-truth reconciliation — carrier_usage_records / carrier_usage_daily / carrier_reconcile_log (migrations 000409–000410), calls.cost_basis, a 6-hourly Twilio reconciler in diff mode, and the PBX→Carrier variance view. Measured drift on day one: platform said $77.91, Twilio $33.28.

  • P054 S7+S8: full visual schema canvas; per-app schema namespacing (data_schemas, (tenant, schema, name) uniqueness after duplicate cleanup), Builder awareness of schemas, empty-schema deletion.

  • P070 S0/S1/S2/G8: Builder component contracts — form→table mapping through repeaters, managed_by: builder, unified refScope for cross-component references, delivery notes for unresolved refs, and gated apps no longer disclose their definition to strangers.

  • Repeaters that actually run: canonical sub_fields, file/radio/select sub-fields rendered in rows, full sub-field editor, one table row per entry (_form_submission_id, _repeater_index).

  • Failure accounting extended: data_table_error, workflow_node_stuck, job_timeout, job_orphaned, tool_panic.

  • Background jobs: 3600 s in-worker deadline, heartbeats (last_heartbeat_at, migration 000413), heartbeat-based reaper.

  • Voice overlay: greeting in context, USE_TOOL exempt from voice rules, no copyable example sentences, ASR-tolerant guardrail, DATA CAPTURE read-back before recording phone numbers and emails.

  • DELETE /api/v1/data-schemas/:id (data_tables.delete) deletes an EMPTY

  • UI: a trash action on each Schemas-tab card and a "Delete schema" button

  • Migration 000409 — carrier_usage_records (per-resource carrier truth,

  • calls.cost_basis — estimated | reconciled | off_carrier |

  • Carrier reconciler (internal/services/carrier_reconciler.go), modelled

  • Handles the price lag: Twilio's price is NULL on the create response

  • calls has no Twilio SID column — nothing in the voice path ever

  • On a deployment that has never reconciled, the first run backfills 30 days.

  • Super Admin → PBX / Phone → Carrier variance tab: what we counted · what

Fixed
  • Every agent data-table insert/update since Aug 20 crashed agent-manager (writer wired before the service existed — typed-nil). Boot-checked, setter guarded, and a tool panic can no longer take the node down.

  • The post-tool spoken confirmation was swallowed on phone calls when the model fenced its INPUT JSON (phantom fence in the worker filter).

  • The stale-job reaper killed healthy jobs older than 20 min by age — the "3 or 4 tasks" ceiling.

  • "factura" disarmed a CRM agent (document-intake hard stop); fenced blocks and tool directives spoken aloud; guardrail refusal loop on noisy lines; greeting repeated.

  • Select columns created with no options rejected every row (top-level fields too); Builder preview had no upload handler.

  • Workflow node that hangs was closed with a fixed sentence naming nothing; a form's failed table write left no trace.

  • Call lifecycle: registrar-outbound calls invisible to /calls and billing; phantom ring-time billing; Kamailio in-dialog ACK/BYE (handle_ruri_alias returns 2 = TRUE).

  • dev.arcanflows.com had no Caddy site block.

  • Order. The writer is wired immediately after InitDataTableServices,

  • Setter. SetDataRecordWriter refuses a typed nil (reflect) and leaves

  • Guard. executeCustomTool — the single choke point both tool loops

  • The leak. stripDocumentArtifacts only removed the document tools'

  • A picker for a capability the agent did not have. Every document tool was

  • Contaminated call summaries. summarizeCall runs phone transcripts

  • Whole-job deadline — CHAT_JOB_TIMEOUT_SECONDS (default 3600).

  • Heartbeat — last_heartbeat_at (migration 000413) + a 30s ticker and

  • Reaper — replaces the age-only loop; judges heartbeat staleness.

  • Accounting — new job_timeout / job_orphaned classes. This class was

  • Gated app, unidentified caller → a shell: name, icon, theme,

  • none and an unset mode: byte-for-byte unchanged. The client's own

  • Still gets the whole app: a platform session in the app's own tenant

  • Client: the runner re-fetches with the app JWT after sign-in, and a

  • the schedule contract named the cron key cron; the validator has always read

  • the loop contract taught bare {{item}}; the engine nests the iteration under

  • action_agent's output was described as the reply text; response is an

  • transform_aggregate was said to require source/operation/group_by for

  • A repeater file cell now uses the same public upload endpoint, storage

  • UploadPublicFormFile resolves repeater sub-field paths

  • Also added to the row renderer: radio, multi_select, checkbox_group,

  • Required sub-fields are validated per row before submit ("Row 2: Archivo is

  • materializeInlineDataURLs now walks repeater rows too — the Aug 24 base64

  • Repeater file cells are canonicalized server-side into the standard file

  • Prompt teaches sub_fields + min_rows/max_rows/default_rows,

  • Canonicalize on save (FormService.Create/Update — the one chokepoint

  • Publish refuses a repeater with genuinely no sub-fields, naming the field

  • Migration 000411 repairs stored forms in place (guarded, idempotent —

  • Renderer + TS types read the legacy aliases as a fallback, so a

  • New internal/service/builder_table_refs.go — one tableRefScope used by

  • Two passes. A relation whose target is created later in the same plan is

  • Isolated components. A failing proposal is logged, skipped and reported;

  • Nothing targetless escapes. A reference column with no resolvable target

  • Directly drafted reference_table_ref columns now create dependency edges,

  • calls.duration_s is the PLATFORM's wall clock (NOW() - answered_at), and

  • calls.cost_usd was that wall clock times a hardcoded $0.05/min whose env

  • Twilio's own price field was declared once in the codebase and never read.

  • That operator estimate was rendered to TENANTS as "Voice cost".

  • Nothing anywhere compared our numbers to the carrier's.

  • Off-carrier calls were charged carrier rates. Extension-to-extension

Improved
  • formTableColumns (new, shared by the creator and the reconciler) gives the

  • formRecordRows (pure, testable) fans out: each row carries that entry's

  • Backfill stays idempotent: every fanned-out row shares one

  • Mapping entries for sub-fields use a composite <repeaterID>::<subFieldID>

  • A second repeater keeps its entries in one JSON column. Fanning out two

  • Non-repeater forms write exactly the single row they always did.

  • Reconciliation now also runs when an already-published form is saved:

  • Trashed tables still carry schema_id, so a schema can look empty while

  • App bindings (apps.settings.default_schema_id) are CLEARED and counted.

  • The edit path never resolved table references. applyUpdate's

  • Refs could only name tables from the same run. The resolver looked at

  • Schema placement stopped at the first build. The app schema was only

  • One bad column aborted everything. Execute returned on the first error,

  • Tenant billing basis is now the CARRIER's duration where the carrier

  • The tenant-facing "Voice cost" KPI is gone (G11). /calls → Stats now

  • VOICE_COST_ESTIMATE_PER_MINUTE is now a fallback, used only in the

  • Operator cost was massively over-stated. The $0.05/min constant is

  • Tenant minutes were under-counted. A call we forward onward bills Twilio

v1.1.10.1“Billing Integrity & Hold Music”August 26, 2026

Calls that stayed open after the caller hung up — and kept billing — now close. The streaming watchdog stopped killing self-hosted models before their first token, research reads pages that exist rather than pages the model remembered, and forms create and follow their own data tables.

New
  • P065 S1–S4: Stripe webhook retry sweeper + operator replay surface; honest usage percentages (unclamped); usage threshold notifications (tenant 80/100/overage + operator alerts); missed-webhook Stripe reconciler.

  • Promotions: tenant validation + Stripe pre-application of codes; duration semantics ("3 months = months 1–3"); catalog-aligned targeting (real plan list, per-item add-on/product/service pinning, Services category, billing-cycle rules with the yearly-coupon guard); store promo-code box.

  • P024 T4+T2: agent failure accounting (agent_failure_events + super-admin Agent Health page) and the 90-second streaming idle watchdog with model-fallback handoff.

  • P063 S1–S3: hold music (synthesized default + per-tenant uploaded track, PyAV-decoded), explicit Hold/Resume on the web phone.

  • P064 S1–S4: forms auto data-tables (auto-create, reconcile, backfill, opt-out).

Fixed
  • notifyTenantAdmins role filter matched a role that never existed — every tenant billing notice had been delivered to nobody.

  • Attended transfer rebuilt subscription-based: MoveParticipant is LiveKit Cloud-only and had never worked self-hosted; recorded calls could never transfer (EG_ egress counted as a party).

  • Voice: symmetric RTP for port-rewriting NATs (one-way audio); Kamailio dual Record-Route (BYE delivery both directions); hangup tears down the surviving leg; webphone Decline is terminal (no forward chase); PyAV padding distortion in hold music.

  • Webphone: louder dual-tone ring, full-screen incoming-call modal, tab-title flash.

  • Overage cap lowered to 1.25×; closed billing periods backfilled from usage_logs (no under-billing found).

v1.1.9.0“AWS Production Cluster & Multi-Party Voice”August 24, 2026

The production AWS cluster, and voice that survives more than two people. A conference no longer dies when one participant leaves, rosters show real names, recordings actually reach S3, and web phones ring across replicas instead of only the one holding your presence. You can also bring a Twilio number you already own, including regulated ones.

v1.1.8.1“Call Intelligence & Fleet RAG v2”August 23, 2026

Every agent on the fleet moved to v2 embeddings — 181 of 181. Phones can ring the browser and the desk phone together, call statistics gain time ranges, outbound and live concurrency, and each agent gets an Answer Quality panel with hallucination metrics that were recalibrated to mean something.

v1.1.8.0“Identity, RAG Quality & Relational Data”August 22, 2026

Retrieval quality becomes measurable and multilingual: an eval harness, corrected retrieval, per-agent cutover to new embeddings, a knowledge catalog, and conversation learning that is governed rather than automatic. Identity catches up too — the tenant switcher works, admins are per-tenant, and a drift gate keeps new routes from shipping without permissions.

v1.1.7.0“Workspace PBX & Data Integrity”August 21, 2026

The workspace gets a real PBX: numbers and extensions you manage yourself, softphone extensions that ring, outbound calling through the platform, and transfers from a physical keypad. Data tables gain real database semantics, and the MultiGla CRM connector arrives read-only.

v1.1.6.4“Team Files & Transfer Control”August 19, 2026

Team chat carries files and photos, with a control plane deciding what may be sent and kept.

v1.1.6.3“Dynamics 365 & Embedded Handoff”August 19, 2026

Adds the Microsoft Dynamics 365 connector, and fixes handoff replies that never reached the bubble widget or API clients — a human answered and the visitor never saw it.

v1.1.6.2“Field Capture & Scheduled Reliability”August 19, 2026

Forms learn to capture the physical world: a camera field for photos and video, geolocation, and a Location column so what a form collects maps cleanly into a data table. Also fixes embedded dropdowns that were invisible, and hardens scheduled-task operations.

v1.1.6.1“Reliable Delivery & Builder Memory”August 18, 2026

Web search becomes a good citizen — query hygiene, PII scrubbing, pacing, and a super-admin console showing what was searched. The Builder renders diagrams inline and can produce architecture documents on request, and team chat gains group conversations alongside the AI launcher.

v1.1.6.0“Service Operations & Scale-Ready”August 18, 2026

The service-delivery lifecycle becomes a complete, honest operation — purchase-gated requests, real partner assignment, calendar-agreed scheduling, timed sessions, reminders, and instant notifications — while the platform itself becomes safe to scale horizontally (cross-replica realtime, single-runner sweeps) and forms trade the old math captcha for Cloudflare Turnstile. Plus honest per-model conversation memory, the Odoo/streaming chat fixes, and a mobile-responsiveness sweep.

v1.1.5.2“Self-Review & Long Memory”August 17, 2026

The Builder's evolution loop closes (PROPOSAL-046 complete): failure-gap clustering, eval-verified skill saves, and a confirm-gated self-review where the Builder proposes its own skill edits. And agents get honest conversation memory (PROPOSAL-047 S1): history budgets derived from each model's real context window — verified live going from 8,000 to 83,790 tokens — which also exposed and fixed a platform-wide pgx bug that had silently broken every model-capability lookup.

v1.1.5.1“Roles & Signatures”August 17, 2026

Apps gain their own role system (both auth modes), forms and tables gain draw-to-sign signature fields, the Builder eval corpus grows to 22 curated golden cases, and a platform governance rule that broke generated-media links is fixed — plus the sequenced-drafting fix that closes the parallel-draft correlation gap for good.

v1.1.5.0“The Evolution Loop”August 16, 2026

Builder quality becomes a number. An eval harness scores builds, the first turn of the evolution loop took a suite from 11/16 to 16/16, unparseable drafts retry themselves, and the drafter's compiled judgment becomes editable data rather than code. Apps join the types you can edit by conversation.

v1.1.4.0“The Builder Operates”August 15, 2026

Builds are verified before they are handed over, and a failure arrives with a fix button rather than a shrug. Credentials gain health, an honest Test, and Reconnect. Also fixes a re-index that destroyed knowledge bases while status flags reported success.

v1.1.3.0“Governance in Depth”August 14, 2026

Governance reaches the places data actually flows: documents are scanned before they are embedded, the safety log stops being a PII honeypot, and a PII floor applies platform-wide. Mobile gets usable cards and composers, and the store becomes findable.

v1.1.2.0“Service Fulfillment Operations”August 14, 2026

Service delivery becomes an operating system rather than a spreadsheet: the hour ledger credits on purchase and logs on delivery, requests have an intake queue, partners have configurable levels and a fulfillment queue. Also fixes service purchases that the Stripe webhook never recorded.

v1.1.1.3“Integration-Aware Builder”August 13, 2026

The Integration Hub takes shape — a Shopify connector, ServiceNow folded in as a connector rather than a standalone backend, and a Builder that knows connectors exist and can attach them. Dashboards gain share links, print and PDF, API-key embeds, and caching that survives concurrent loads.

v1.1.1.2“Web Search Overhaul”August 11, 2026

Web search now tells the truth about itself. The SerpAPI tool had zero lifetime executions (three independent causes, all fixed via a new per-tenant api_key_provider auth mode); the Web Search tab's engine routing was saved and read by nothing (now: six engines, keyword-routed per query, localized, recency-filtered); Google Flights and Hotels join as structured-parameter catalog tools with response distillers; search accounting covers workflows and APIs; quotas gate paid tools where they execute. Plus: the tools and apps audits closed — every PROPOSAL-027 component type is now done — and the two-cloud production architecture (AWS mx-central-1 + Vultr MEX in-country DR) is designed in deploy-env/production/. Details: RELEASES.md.

v1.1.1.1“Builder Component Quality”August 10, 2026

The Builder can now build the whole component, not a fraction of it. Nobody had asked how much of each product the Builder could actually express — only whether what it emitted got wired correctly. Measured against the product's own type definitions: form fields 16→41, table columns 15→23, workflow nodes 23→31, dashboard widgets 6→14, plus filters, ordering, currency formatting, agent capabilities and model choice, app pages that surface dashboards, and threshold alerts. Along the way: five bugs where a value was taught, drafted, saved and silently discarded; three separate defects that made dashboard alerts notify nobody while recording that they had; four charts that were in the palette but drew grey placeholders; and app pages that vanished without a word. Details: RELEASES.md.

v1.1.1.0“Governance & Reliability”August 8, 2026

The platform's guardrails became real, and a long list of quiet failures got fixed. Content safety was enforced on only one of two execution paths — streamed conversations (console chat, embed widget, voice) ran with no checks at all; that's closed, and above it sits a new platform-wide guardrail layer that updates without a deploy, plus tool-call SSRF governance in shadow mode. Human handoff went from half-built to a working support channel (deterministic escalation keywords, operators actually notified, live operator replies). Voice cleared its bench: speakable-only streaming, SIP toll-fraud lockdown, billing enforcement, graceful drain, and a VAD retune so callers don't have to shout. Studio gained the Alibaba model family with HappyHorse as the default avatar engine. Details: RELEASES.md.

v1.1.0.1“Softphone Registrar”August 6, 2026

Any softphone now works, and Twilio numbers are proven end-to-end. A Kamailio SIP registrar in front of the LiveKit trunk lets Zoiper/Linphone register and hold a full two-way call with the agent; the worker's echo guard stops the agent from hearing its own speakerphone echo and talking to itself; and a real US number purchased in-console took a live PSTN call through to the agent. Details: RELEASES.md.

v1.1.0.0“Phone Agents Update”August 4, 2026

The platform's first minor release since GA: agents answer real phone calls. PROPOSAL-033 delivered S1–S5 in two days, live-verified by real calls: self-hosted LiveKit voice stack, Phone tab (extension/number, greeting, language, voice picker, recording policy), Calls page with transcripts/recordings/summaries, super-admin PBX panel, per-tenant trunks + extension namespace (D8), Twilio number purchase in-console (D7), voice_minutes billing in shadow with per-plan concurrent caps enforced. Plus the Builder/forms hardening round, sidebar icon rail, diagram viewer repairs, and the platform-wide tool-noise cleanup. Details: RELEASES.md.

v1.0.0.3“Avatars Update”August 3, 2026

Studio Avatars: 12 curated presets or your own photo as the on-screen character, Presenter/Action flows, true lip-sync via Google Veo 3.1 Fast (DashScope wan2.2-s2v adapter shipped and armed for CN-region keys), Veo self-healing (model-id churn, completed-response handling); live Alibaba/DashScope model sync + provider-sync tenant fix; agent Web Search tab is now the single source of truth, with SearXNG fallback, explicit no-result/misconfiguration notices, and streaming anti-narration; Builder trash safety (live component status in history, bundle restore, double-confirm + per-component audit); themes reach embeds, editor previews, and the app editor. Details: RELEASES.md.

v1.0.0.2“Design System Update”August 3, 2026

Professional design system (full-token rendering, 12 new themes incl. 2 premium, apps + Builder theme awareness, tenant brand kits with local logo uploads, premium gating — migrations 000315/000316); chat image normalization (HEIC/TIFF/BMP + oversized → JPEG); sub-agent rule routing bounded to ≤280-char requests; batched tool calls re-issued instead of dropped (daily-news email restored); system tools never attachable to agents. Details: RELEASES.md.

v1.0.0.1“Reliability Update”August 3, 2026

Image analyze-vs-edit routing; vision/OCR capability self-awareness; scheduled-task reliability (concurrent worker pool, stuck-run watchdog + 48h window, empty tool-call guard, per-tool failure cap); large attachments via DB row (70-page scanned PDFs work in background chat, ~4 min); extraction memoization; Builder seeding on-demand only (migration 000314); Teams bridge 60s. Details: RELEASES.md.

v1.0.0.0“First General Release”August 2, 2026

Everything below this line up to the project's beginning ships as ArcanFlows v1.0.0.0, the platform's first tagged release. Release notes: RELEASES.md. Platform versions are four-segment (major.minor.patch.hotfix); the version is surfaced in the console sidebar, on Settings → Licenses, and at the API /health endpoint.