Skip to content

Tale v0.5.27

Choose a tag to compare

@larryro larryro released this 15 Sep 01:49
eed7745

0.5.27 is a patch tag on the 0.5 line that carries more than its fixes — read it as a minor. It ships three forward-only schema migrations (one on the application database, two on the knowledge corpus), an API contract that moves from 1.9.0 to 1.11.0 in two additive steps, a new edge rule and a recovery selector for managed deployments; nothing in it is breaking, no configuration file changes shape, no environment variable is added, and the upgrade is still tale update followed by tale deploy --stop (the proxy image changes — see Upgrading). Four changes since 0.5.26: the eighth external API evaluation's findings closed at their root, the documentation rewritten as complete tasks in three languages together with the platform defects its walkthroughs found, the Documents hub listing one folder at a time, and a way out for a managed deployment whose native configuration plan has to be replaced.

Highlights

The eighth API evaluation pass (#3359)

The eighth external black-box evaluation of the REST and MCP API ran against 0.5.26 and reported 3 S2, 20 S3 and 35 S4 findings. Every finding was re-verified against the source before anything changed: the three S2 are real defects, and so is the dense-retrieval finding the report itself had marked unconfirmed — all four fixed at the root with regression tests and integration lanes; the rest split three ways: code defects fixed, contract-precision items closed in the OpenAPI document and the en/de/fr reference, and four product gaps recorded in the contract debt ledger with their pay-down (listed under Known issues).

  • robots.txt governs every path into the crawler. The Disallow rules were applied at sitemap and link-walk discovery only; the links a rendered page yielded were admitted without them, so a site whose robots.txt disallowed its legal pages had them fetched, indexed and served the moment a rendered page linked to them. The rules now govern every admission path and every non-listed fetch, and are kept per site (robots_disallow, knowledge migration public_web 11): a robots.txt that answers 5xx or 429 keeps the last known rules, a 4xx clears them; a stored page a new rule covers is retired on the next scan; a URL you listed stays your instruction, and a listed page the site answers 404 for keeps an honest http_error row; <meta name="robots" content="noindex"> is honoured like the header; http:// is refused as WEBSITE_DOMAIN_INVALID and a trailing dot stripped; websites?scanInterval= refuses a value outside its seven; idle leaves Website.status (a registered site starts scanning); a fetch error carries no OpenSSL handle or runtime path.
  • The dense retrieval leg no longer starves. A scoped knowledge query over a large corpus ran an HNSW scan whose post-filter could empty the vector leg silently, and a duplicate-heavy export — one line repeated 4,500 times — became 4,500 identical vectors crowding out nearer passages. Under 5,000 candidate chunks the dense leg runs an exact scan, above it an iterative HNSW scan (pgvector 0.8 and later; an older pgvector keeps the plain approximate scan and says so in the log); a passage repeated inside a document is embedded once (passage_repeat, knowledge migration private_knowledge 12 — such rows carry no vector and sit outside both legs); diagnostics.dense says whether the vector leg ran; RRF ties break keyword-first, then by id; control characters are stripped from served passages; the query cap of 2000 characters is named.
  • One live run per task, whichever automation asks. The rule 0.5.26 put in the schema was keyed per (task, automation) while the docs, the OpenAPI operation and the product say per task, so two engines could mutate one card at once. Migration 0104 collapses cross-automation live duplicates onto the earliest run and replaces the index with automation_runs_one_live_per_task_subject; the per-task lock and probe move with it, and a second start naming another automation answers already_running with the live run's id.
  • The generation poll cannot cut a surrogate pair. ?since= and ?reasoningSince= sliced the text in UTF-16 code units with no pair snapping, so a slice could begin with a lone low surrogate the write side refuses; both are snapped down to a pair's start and textOffset / reasoningOffset report where the slice began, so held.slice(0, textOffset) + text always reassembles. A prompt with no visible text (format controls, zero-width spaces) answers 400; archiving a thread mid-turn answers 409 CHAT_TURN_IN_PROGRESS; a thread or project archived after a send was accepted settles the reply cancelled with the prompt kept; the execute lane is charged only after body and header pass; GET /api/v1/models answers harnesses and PROJECT_AGENT_HARNESS_INVALID names the eligible set.
  • The CRM mirror can be thawed and listed. POST /api/v1/contacts/{id}/restore is the remedy a frozen mirror's 409 names (the create's own 409s apply when a live contact has since taken the key); GET /api/v1/conversations?source= lists every mirror under a source newest first, contactStatus narrows, and the keyset cursor is signed under the source; a re-keyed contact's binding follows its current externalId (the old id answers 409 CONVERSATION_CONTACT_CONFLICT); the receipt carries contactId; every 201 that creates one addressable resource carries Location (thirteen operations); the document PATCH answers its ETag; the skill file read is validated (ETag, Last-Modified, 304); null on a create reads as "left out" and the document says so.
  • MCP tools say what they did. start_run takes idempotencyKey through the REST ledger; set_trigger answers a webhook token once and says whether the trigger is deployed; get_automation reads version: "deployed"; list_versions marks the deployed row; every capability refusal carries a code (CAPABILITY_NOT_FOUND, CAPABILITY_INPUT_INVALID, the knowledge door's own); the registry holds deployed automations only; an enum argument outside its set is refused with the set named.
  • The edge, the session doors and the rendered reference. The proxy strips Expect: it answers 100 Continue itself, and forwarding the header let the origin write a second one — two interim responses on one request, a desync for a strict HTTP/1.1 client. A missing session answers the coded UNAUTHORIZED envelope on /events and the app routes instead of a bare {"error":"unauthorized"}. The rendered API reference keeps a pasted key out of localStorage, and swagger-ui-react moves to 5.32.15 on immutable 5.1.9 — the pair built for each other — so its Logout works again (0.5.26 ran 5.32.2, declared for Immutable 3, on the 4.3.9 override).

The documentation, rewritten as tasks (#3342)

All 381 non-video product guides were rewritten in English, German and French to lead a reader through a complete task — prerequisites, choices, examples, the observable result and the recovery — with three new pages (Ask about files and images, Manage tasks on a project board, Set automation approval rules), the READMEs and the contributor guide, the documentation and translation authoring skills, and every screenshot retaken on the current platform (the README gallery's six sources link to their full-resolution captures). The nineteen component guides on the design-system site explain setup, composition, state ownership, accessibility and working examples; both docs shells keep the initial skip-link focus and the reduced-motion preference; the shared Markdown renderer keeps authored Frame figures and captions.

The walkthroughs drove the real product and fixed what they found (manual rounds R3–R6 in services/platform/tests/manual/runs/):

  • An approval policy fails closed. A new decision read the organization's approval policy through a path that could substitute an unrestricted default when the policy file was invalid or its configuration mount unavailable, so a platform-internal connector write could run unapproved. New decisions read the strict, uncached configuration path; invalid YAML, an invalid schema or a missing mount refuse instead of allowing; existing pending decisions keep their authority.
  • A run asks for its input. An automation whose version declares an inputs schema had no way to supply it from Test run or Run live; the confirmation dialog now collects the JSON against the saved test version or the deployed live version, shows the schema, validates without runtime code generation (the production CSP forbids it) and sends the original JSON. Native waiting runs render: the pending-approval card recognises UUID approval ids (both decision controls were hidden), and a run with no finish date no longer shows 1 January 1970.
  • Product images upload through the platform. The product editor takes an image (PNG, JPEG, WebP, GIF or SVG, inspected, up to 5 MiB) into an organization-protected app URL that only an authorised member's session can read; a file bound to a product refuses deletion (409 FILE_BOUND_TO_PRODUCT) until the image is removed; the REST door answers that URL absolute and accepts it back on a create or patch — even on a private deployment — while every pasted external URL keeps the public-host rule.
  • Conditional document writes hold under contention. If-Match on the document PATCH was checked before the write lock, so a concurrent edit could still be overwritten; the fresh representation is compared inside the write transaction and a mismatch answers 412 with the other writer's change kept.
  • A self-hosted provider behind private DNS reaches the gateway. The private-network admission for a custom provider URL decided by hostname spelling and missed a name that resolved to a private address; every resolved address is inspected, a cloud-metadata address is refused whatever the name, the check is repeated before a cached provisioning is reused, and a public/private transition invalidates the provisioned fingerprint.
  • Indexing says why it stopped. The document dialog and the project files tab name the terminal cause — unsupported_type, image_no_vision, empty, not_text, malformed — instead of "Format not supported", and offer no retry for unchanged terminal content; knowledge entries show their real indexing status (they read Not indexed after a completed index), and a document hint refreshes the entry list without a reload.
  • Smaller fixes. The project-agent model picker finds a model by its API id as well as its display name; a website's detail dialog shows its creation date; contact and product rows show their dates instead of a dash; an active WebDAV app password stays revocable (a native revokedAt: null read as revoked) and a long device label no longer clips its badge; the rail's navigation memory survives a browser whose storage getters throw; the Vite dev server passes WebDAV discovery to the backend; tale init --no-env no longer claims it generated secrets.
  • The settings copy says what the build does. Personalisation instructions and memories are stored but not yet used by chat replies; a skill's "hidden from the model" switch is advisory metadata; the SSO description names the organization picker; Microsoft 365 file import has its own consent flow (do not add Files.Read or Sites.Read.All to the SSO scopes); the audit verifier's truncation and scrub notes read as the bounded PostgreSQL verifier behaves, and the environment reference says TALE_AUDIT_SIGNING_KEY is retained for compatibility and not read by it.

The Documents hub lists one folder at a time (#3356)

Since the 0.5.0 Postgres port, the hub's root page listed every document in the organization: a file synced from a OneDrive or Google Drive folder appeared at the root and inside its folder, and deleting the folder took both rows with it. The root page now lists only the documents that sit in no folder, a folder page lists that folder, and no request shape lists the whole hub; a cloud import refreshes the folder list too, so the sync-root folder shows without a reload. Two defects went with it: a parent crumb in the breadcrumb navigated to the root (the folder rows were keyed id, the crumb read _id), and the manual-suite guide checker could not see the design-system catalog's keys. On REST, folderId=root on GET /api/v1/documents and GET /api/v1/projects/{id}/files lists the unfiled documents — the root no folder id could name; omitting the parameter still lists everything (contract 1.10.0).

A managed deployment recovers a replaced configuration plan (4f7b426)

A deployment that fails while verifying a provider catalog retains a native configuration plan; when a reviewed replacement bundle repaired the provider's endpoint, the native phase still selected the old plan, refused the changed declaration, and bundle recovery could not finish. supersedesPendingConfigurationPlan in a managed deployment declaration — config apply --supersedes-pending-plan <sha256> on a standalone workspace — selects the exact retained plan by the SHA-256 of its canonical JSON (keys sorted recursively, arrays kept, no whitespace). The engine keeps the prior journal and verified writes, requires the same organization, origin and resource identities, refuses native state outside the old operation's recorded preimages and results, keeps the native compare-and-set checks, and replays an interrupted replacement without duplicating completed writes; supersedesPendingBundle alone never replaces native configuration intent. The receipt keeps the superseded plan and its verified subset under superseded; drop the selector once the replacement reaches ready. The CLI README and the CLI install page carry the recipe.

Behaviour changes

  • The Documents page lists one folder at a time: the root shows folders and unfiled documents only, and a synced cloud folder's files stand inside their folder. A cloud import shows its sync-root folder without a reload; a parent crumb opens that folder.
  • Test run and Run live on a version that declares inputs open the confirmation dialog with a Run input (JSON) field and the schema beside it; malformed or non-conforming input is refused before anything is scheduled.
  • An invalid or unavailable approval policy refuses a new platform-internal write instead of allowing it.
  • The pending-approval card renders for UUID approval ids; a waiting run shows no finish date.
  • The product editor uploads an image; a file bound to a product cannot be deleted until the image is removed from the product; Product.imageUrl over REST is absolute, and the deployment's own image URL is accepted back.
  • A document that cannot be indexed names its cause (Document cannot be indexed, with the reason) and offers no retry; a project file in that state shows the same label; knowledge entries show their indexing status.
  • Websites: a registered site starts Scanning (the Idle status is gone); the page counts move while a scan runs; pages robots.txt has come to disallow leave the index on the next scan, and a page carrying <meta name="robots" content="noindex"> is not indexed; an http:// address is refused when adding a site; the detail dialog shows the creation date.
  • Knowledge search: a passage repeated inside a document is returned once; a scoped search over a large corpus keeps the dense hits it used to drop; control characters are stripped from passages.
  • Task automation: a task holds one live run whichever automation started it; a second start naming another automation returns the existing run as already_running. The guide's "per-task safeguard" pause never existed; the guide now says the one-engine rule is the stop.
  • REST chat: a prompt with no visible text answers 400; archiving a thread mid-turn answers 409; a thread or project archived after acceptance settles the reply cancelled with the prompt kept; since and reasoningSince never split a surrogate pair.
  • REST: every 201 that creates one resource carries Location; null on a create or bulk import reads as the field left out; the document PATCH answers its ETag; the skill file read answers 304 on If-None-Match / If-Modified-Since; GET /api/v1/models answers harnesses; websites?scanInterval= and an unknown harness are refused by name.
  • The session doors answer coded envelopes: a missing session UNAUTHORIZED with Cache-Control: no-store on /events and the app routes, a missing orgId INVALID_QUERY, a non-member ORG_FORBIDDEN.
  • The rendered API reference at /docs keeps a pasted key in page memory only (a reload asks again); its Logout works.
  • The edge strips Expect once the proxy is recreated (see Upgrading); the proxy's self-signed mode log names the root certificate to copy instead of caddy trust.
  • The project-agent model picker matches the API model id; contact, product and website rows show their dates; an active WebDAV credential stays revocable and its badge readable.
  • The settings copy for personalisation, memories, skill invocation, SSO and Microsoft 365 import describes the current build (see Highlights).
  • tale deploy on a managed deployment honours supersedesPendingConfigurationPlan; tale config apply takes --supersedes-pending-plan; tale init ends with a backup reminder instead of the "production-ready by default" line, and --no-env says the environment setup was skipped.
  • docs.tale.dev: three new pages; the attachments page is a page again (its redirect to the chat basics page is gone); the initial skip-link focus and the reduced-motion preference are kept.

API contract changes

The OpenAPI document moves from 1.9.0 to 1.11.0 in two additive steps (1.10.0 dated 2026-09-14, 1.11.0 dated 2026-09-15); the Error.code enum keeps its 149 values. One enum value leaves — Website.status loses idle, which no running instance ever answered (a registered site starts scanning) — and every nullable enum now lists null.

Added

  • 1.10.0 — folderId=root on GET /documents and GET /projects/{id}/files: the documents (files) in no folder; a folder id answers that folder, an unknown id on the project door the opaque 404 FOLDER_NOT_FOUND, a blank value 400; omitting the parameter still lists everything.
  • 1.11.0 — POST /contacts/{id}/restore (200 with the contact; a live contact is a no-op; 409 CONTACT_DUPLICATE_EMAIL / CONTACT_DUPLICATE_EXTERNAL_ID when a live contact has since taken the key; a body other than {} 400); GET /conversations (source required; contactStatus, cursor, limit) — ConversationMirror rows newest first under a source-signed cursor; contactId on the conversation-sync receipt; Location on the thirteen 201 creates (documents, websites, products, contacts, projects, project agents, folders, files, tasks, threads, project threads, knowledge entries, PUT /skills/{slug}); harnesses on GET /models; ETag on the document PATCH response; ETag, Last-Modified and 304 on GET /skills/{slug}/files/{path}; KnowledgeDiagnostics.dense; on the MCP endpoint start_run.idempotencyKey, deployed on set_trigger, version: "deployed" on get_automation, the deployed marker and deployedVersion on list_versions, and a code on every capability refusal.

Changed

  • PATCH /threads/{threadId} with archived: true while the turn is queued or streaming answers 409 CHAT_TURN_IN_PROGRESS; a thread or project archived after a send was accepted settles that reply cancelled.
  • POST /conversations/sync — a re-keyed contact's binding follows its current externalId; a snapshot naming the old id answers 409 CONVERSATION_CONTACT_CONFLICT.
  • POST /websites — a domain carrying a scheme answers 400 WEBSITE_DOMAIN_INVALID; a trailing dot is stripped.
  • GET /websites?scanInterval= — a value outside 60m, 6h, 12h, 1d, 5d, 7d, 30d answers 400 INVALID_QUERY; Website.status is scanning, active, error, deleting.
  • POST /projects/{id}/agents and its PUT — a harness outside the eligible set answers 400 PROJECT_AGENT_HARNESS_INVALID with the set in data.harnesses.
  • The generation poll — since and reasoningSince are snapped down to a surrogate pair's start; textOffset and reasoningOffset say where the slice begins.
  • Thread sends — a content with no visible text answers 400; the execute-lane budget is charged only after the body and the Idempotency-Key header pass.
  • POST …/tasks/{taskId}/start — already_running may name a run another automation started (its name says which).
  • ContactInput and ProductInput declare their nullable fields; a null or blank on a create or bulk import reads as the field left out; the enum query filters are declared.
  • Product.imageUrl — the deployment's own product-image URL is accepted back on a create or patch, even on a private deployment; a missing or inaccessible image answers 404 FILE_NOT_FOUND.
  • The session doors (/events, /api/app/…, the control routes) — UNAUTHORIZED, INVALID_QUERY and ORG_FORBIDDEN beside the sentence.
  • The MCP endpoint — set_trigger takes one shape per kind (a key of another kind is refused by name); an enum argument outside its set is refused with the set named; start_run refuses a reused idempotencyKey with different arguments as IDEMPOTENCY_KEY_REUSED.

Documented, unchanged on the wire (en, de, fr): the edge's bare 431 and 400 carry no X-Request-Id; Idempotency-Key is read only by the operations that declare it, and curl -H 'Idempotency-Key:' sends no header at all; the redirect ceiling (redirect_limit_exceeded past five redirects); the knowledge query cap of 2000 characters and the similarity-threshold recipe; a skill keeps no version history on the machine door; the per-task circuit breaker is not built; Product.imageUrl and WebsitePage.lastErrorKind say what they carry.

Security

  • An approval policy fails closed (#3342): an invalid or unavailable approval-policy file no longer lets a platform-internal connector write run without the approval the organization configured. If a deployment carried a malformed policy file, review the automation runs of that period.
  • robots.txt is honoured on every crawl path (#3359): pages a site asked crawlers to leave alone are no longer fetched, indexed or served through rendered-page links, and pages a rule covers leave the index on the next scan.
  • The rendered API reference no longer persists a pasted key in the browser's localStorage; swagger-ui-react 5.32.15 runs on immutable 5.1.9, clear of the two advisories the dependency gate tracks (GHSA-v56q-mh7h-f735, GHSA-xvcm-6775-5m9r).
  • The edge strips Expect, closing an interim-response desync a strict HTTP/1.1 client could be confused by.
  • The product-image intake inspects the bytes (the declared type is not trusted; an SVG with active content is refused), serves them only to an authorised app session — an API key does not authorise the route — and refuses a caller claiming the intake's reserved source on the generic file registration.
  • A custom provider host is resolved and every address checked before the gateway is provisioned; a cloud-metadata address is refused whatever the name.
  • Fetch errors from the crawler carry no OpenSSL handles or runtime paths; a missing session answers Cache-Control: no-store.

Known issues

  • Unchanged from v0.5.20, where each is described in full: the es/co-cc Colombian cédula detector still ships switched off and a locale-agnostic PII toggle still widens national-ID matching to every locale (the PII library is untouched in this range); thinking-block replay on the native Anthropic connector is not done and the live Max-plus-tool-call check is still owed; rag_search embedding calls inside a harness turn are unmetered; the product edit dialog cannot clear a field; the app's skill editor still carries the retired private visibility.
  • The x-tale-pagination extension is a declaration on the OpenAPI document; generated clients that do not read vendor extensions still branch on the two cursor names until cursor is retired.
  • The Expect rule was not exercised on a running deployment. It went into a tale-proxy image no deployment has run yet, and services/proxy has no test of its own. The 0.5.26 gap is closed: the hosted platform's edge has answered 400 BODY_CHUNK_MALFORMED to a malformed chunked body since 2026-09-14, and the analytics header rides the same recreated proxy.
  • Documents indexed before this release keep one vector per repeated passage until they are re-indexed; the content hash is unchanged, so only an explicit retry-indexing (or a content change) re-embeds them. A site's robots rules are empty until its first scan on this release; that scan reads robots.txt afresh and retires the pages it covers.
  • The rail's navigation memory has had part of its manual round: R5 drove six EN/DE/FR desktop and phone cases (restore, reset, a fresh chat, two-tab isolation) covering parts of NAV-F16–NAV-F19; the remaining section, the second-account cases and NAV-B6–NAV-B9 are still unrun.
  • ui.tale.dev is not live at this tag. tale-ui-docs:0.5.27 exists from this release, but the site goes live with the operator's deployment of it; until then the link on the contributor-setup page does not resolve. The site still has its nineteen seed pages, and the docs chrome is duplicated between the docs site and the design-system site rather than shared.
  • A reply-language directive is a directive: a model may still answer in the prompt's language and nothing on the wire marks a slip.
  • No image input on the REST chat send. A vision model reads an image over REST only on a thread the app continued with an image attachment; the design of an attachments field on the send is recorded as contract debt.
  • No REST door authors or deploys an automation — POST /automations answers 405 by design. Build and deploy in the app, or over the MCP endpoint's save_automation and deploy_automation; the REST key lists, reads, runs and wires triggers.
  • The app's zip upload of a skill bundle rewrites the bundle and moves updatedAt even when the zip is byte-identical, where PUT /skills/{slug} writes nothing.
  • A tool call the reply cap cut keeps input: {} on the stored tool-call part; the part says its arguments were cut, but the raw text the model emitted is still not on the transcript.
  • Folder names written before 0.5.24 keep their bytes; a sync engine's hub-path lookup can create an NFC twin beside a legacy NFD folder. No backfill ships.
  • Behind a Docker-published port, every IPv6 client arrives as the bridge gateway's address and shares one per-address rate-limit bucket and one audit address until the daemon runs with ip6tables and the proxy's network is IPv6-enabled — an operator item, documented on the Own Compose page.
  • Recorded as contract debt by the eighth evaluation, each with its design in the ledger: GET /notifications rows carry type as a free string and nothing pushes them to a machine caller (poll only); a skill keeps no version history on the machine door (PUT /skills/{slug} replaces, and the app's history is not readable over /api/v1); the per-task circuit breaker is not built — no counter pauses automation on a task after N runs in an hour, the one-engine rule and cancel are the only stops; GET /conversations lists the mirrors, but the messages a snapshot applied are readable only in the app.
  • Still open from the seventh evaluation: a run carries no usage or cost; approvals and asks have no REST twins (a run parked on waitingFor: approval or ask is decided in the app); a task cannot be archived or deleted over REST; a webhook bind does not say whether the deployed inputs schema admits a delivery; an exhausted repeatUntil is only a trace note; Website carries no scanStartedAt and the crawler has no page cap, path filter or stop verb of the caller's; website search has no dense leg and its substring fallback (a knowledge database without ParadeDB) stamps score: 0 silently; no Idempotency-Key on the task start, so a retry after the run finished starts another; no queue position on a queued send; a corrupt Office document (docx, pptx, xlsx, odt) still fails as indexer_error and is retried five times where a PDF lands malformed; no /.well-known/security.txt; no changelog feed on tale.dev; no SDK, collection or per-code table beyond the Error.code enum.

Migration notes

  • Three migrations, all forward-only and rolling-safe.
    • 0104 automation_runs_one_live_per_task_subject on the application database, applied by the backend at boot inside the advisory lock while the previous image keeps serving: it first collapses any live runs (queued, running, waiting) that share an organization, a project and a task subject across automations onto the earliest-started run, marking the rest cancelled, then adds the partial unique index over that key and drops 0102's per-(task, automation) index, which the new one implies. Inside the roll window a cross-automation start on the previous image answers a unique violation as a 500 for that one request — never a second run.
    • public_web 11 website_robots_rules and private_knowledge 12 chunks_passage_repeat on the knowledge corpus — ADD COLUMN IF NOT EXISTS (robots_disallow, robots_fetched_at; passage_repeat defaulting to false), metadata-only and idempotent; the previous image neither reads nor writes the columns. The backend applies them to the deployment-default corpus at boot from the files the platform image ships (the same files, version-aware); the database image applies them in its knowledge role when its container starts on the new image; a bring-your-own corpus gets them from the same converge path on first use. Neither has a down migration by design.
    • No backfill runs: rows indexed earlier read passage_repeat = false and heal on re-index; a site's rules are NULL until its next scan. The task_labels_project_id_name_key constraint 0.5.22 kept for its rolling deploy is still in place; dropping it is a follow-up migration.
  • No new environment variable. The root .env.example only rewrites the comment on TALE_AUDIT_SIGNING_KEY: the key is generated and retained by the CLI for compatibility, and the current PostgreSQL audit verifier does not read it. Keep the value with the deployment's secrets; nothing to change.
  • The proxy image changes — the Expect request header is stripped before the origin sees it, and the self-signed mode's startup hint names the root certificate to copy. The proxy is in the stop-gated tier: a plain tale deploy leaves a running proxy untouched and names it in a hint, so pass --stop to take the new rule (a brief downtime while db, object-store and proxy recreate); until then a client sending Expect: 100-continue still gets 0.5.26's two interim responses. An own-Compose deployment pulls the new tale-proxy tag.
  • The platform (the backend, the app, the message catalogs), proxy, db (the two knowledge migration files), docs (the rewritten pages in en, de and fr and their screenshots) and ui-docs (the component guides and the docs chrome) images carry source changes; the web image rebuilds with the updated @tale/ui package and has no change of its own; the sandbox, sandbox-runtime, sandbox-buildkitd, sandbox-egress and sandbox-llm-gateway images have none. The CLI has source changes — the pending-plan recovery selector and the tale init completion text — and the release executables report 0.5.27.
  • @tale/ui and @tale/marketing-ui are pinned by this release as the ui-v0.5.27 and marketing-ui-v0.5.27 tags on their snapshot branches; a consumer outside the monorepo installs "@tale/ui": "github:tale-project/tale#ui-v0.5.27".
  • Documentation redirects: platform/chat/attachments is a page again (its redirect to the chat basics page is removed); every other redirect stays.

Upgrading

  • On the 0.5 line (0.5.0 – 0.5.26):

    tale update
    tale deploy --stop

    The three migrations run at boot. --stop recreates db, object-store and proxy so the edge carries the new rule (a brief downtime); a plain tale deploy applies everything else — the knowledge columns included — and leaves the running proxy on 0.5.26's rules.

  • Managed deployments move by pinning the CLI and the runtime to this release's commit, preparing a new bundle and applying it with the pinned CLI — see Managed deployments on the CLI install page. The bundle's backend-local phases run under the interpreted CLI (cli/tale.mjs) that the setup-cli action and bun run --filter @tale/cli build produce beside the executable; the executable from the release page has no interpreted bundle beside it and cannot prepare a managed bundle. A deployment stranded on a retained native configuration plan declares supersedesPendingConfigurationPlan with the plan's hash beside the corrected configuration, as above. On a Linux x64 host whose CPU lacks AVX2, pass linux-baseline: 'true' to the setup-cli action so the bundle embeds the baseline executable.

  • New install:

    curl -fsSL https://raw.githubusercontent.com/tale-project/tale/main/scripts/install-cli.sh | bash
    mkdir tale-05 && cd tale-05
    tale init
    tale deploy

    On a CPU without AVX2 the downloaded executable aborts with Illegal instruction; build it from source with bun run build:linux-baseline in tools/cli instead.

What's Changed

  • fix(platform): list only unfiled documents at the hub root by @larryro in #3356
  • fix(cli): recover explicitly replaced native configuration plans by @yannickmonney in 4f7b426
  • docs(docs): overhaul guides, translations and authoring skills by @yannickmonney in #3342
  • fix(platform): close the 2026-09-14 API evaluation's round-h findings by @larryro in #3359

Full Changelog: v0.5.26...v0.5.27