Tale v0.5.34
0.5.34 carries 2 merged pull requests. One gives the operator of a deployment a way to name who may create an organization, in place of the two extremes that existed: any signed-in user on a deployment you run yourself, and nobody at all — not even the owner — on a managed deployment, whose proxy refused organization creation for everyone. The other lets a person whose administrator set their password actually leave the forced-change wall on their first sign-in, instead of being bounced back onto it with the password already changed. No migration, no API contract change, no image in the stop-gated tier: the upgrade is tale update followed by a plain tale deploy.
Highlights
Who may create an organization is now the operator's to name (#3413)
Better Auth's organization plugin lets every signed-in user create an organization, and a managed deployment answered that with the opposite extreme: the CLI's proxy policy refused POST /api/auth/organization/create for everyone and answered the capability probe {"canCreate":false} without looking at who asked, so neither the owner nor the operator could open a second workspace, and nothing the deployment declared could change it.
TALE_ORGANIZATION_CREATORS names the sign-in addresses that may create an organization — commas, semicolons or spaces, matched case-insensitively, the same grammar TALE_DEPLOYMENT_CONFIG_ADMINS uses, through one shared parser. The backend judges every caller against it, in Better Auth's before-hook for the create route: the edge cannot know who is asking, and backend-api is reachable from the sandbox network the edge never sees — the same argument 0.5.33 made for accounts.
- Unset keeps the previous behaviour: any signed-in user may create. A workspace deployment or an own Compose file that never heard of the variable is unchanged.
- Set, a listed address passes without a database read; anyone else is refused with 403
ORGANIZATION_CREATION_FORBIDDENonce the deployment holds an organization, and the refusal is logged. - The first organization is always allowed — the setup flow's, or the managed bootstrap's — so setup is unaffected by any list.
- A set but empty value closes creation to everyone after the first organization.
GET /api/app/organizations/capabilities answers the same predicate per caller, so the app shows Create organization exactly when the door would open; the create page's forbidden copy already existed in English, German and French, and the app needed no change.
A managed deployment declares the list instead of inheriting the blanket refusal. The deployment specification takes organizations.creators: 1–64 distinct addresses, literal or environment references that preparation resolves; two spellings of one address are refused as a duplicate. Declared, the CLI writes TALE_ORGANIZATION_CREATORS into the runtime environment as a managed variable (an environment entry cannot set it), leaves the two organization rules out of the proxy policy — the sign-up refusal stays — records the declaration in the runtime bundle so the bundle reader checks the policy against it, and includes the list in the receipt's input hash only when declared, so every earlier receipt keeps its hash. Undeclared, nothing changes: the edge refuses everyone as before, and the variable is removed if an earlier declaration wrote it.
The rule is documented on the Install the tale CLI page (Name who may create organizations, under Managed deployments), on the first-administrator page and in the environment reference, in English, German and French; the manual layer gains AUTH-B9.
The forced-password wall releases on the write's own answer (#3412)
A member whose administrator set their password meets the forced-change wall on first sign-in. Setting the new password left them on it: the page navigates to the dashboard the moment the change resolves, the dashboard gate reads the shared password-expiry cache, and that cache still said expired: true — so it redirected straight back onto the wall with the form emptied and the password already changed. Only a manual reload got the person through. Reproduced end to end against a real stack.
0.5.31 had closed the cache staleness by invalidating the status after the write, which works when the follow-up read lands — but it made the landing depend on a second round-trip, and with that read failing the flow bounced back onto the wall all the same.
The write now answers the question itself: updateUserPassword recomputes the credential's expiry status and POST /api/app/users/update-password returns it as passwordExpiry, and the app publishes what the server just decided into the shared cache instead of asking again — no extra round-trip on the critical path, nothing left to fail between the write and the landing. Against a backend that answers no status — a mid-roll deployment still serving the previous image — the app falls back to re-reading, so the roll itself is safe. Proved in real Chromium with the real query cache, account bootstrap, expiry gate and router (the published status with no re-read; still landing when every re-read fails; the mid-roll fallback), in the adapter test, against real Postgres in the backend integration check, and in the browser end to end including with the status read forced to 503 throughout. Manual box AUTH-F20 covers the administrator-set-password path.
Behaviour changes
POST /api/auth/organization/createis judged in the backend againstTALE_ORGANIZATION_CREATORSwhen the variable is set: a listed caller passes, any other signed-in caller is refused with403 ORGANIZATION_CREATION_FORBIDDENonce the deployment holds an organization, and the first organization always passes. Unset, the route behaves as before.GET /api/app/organizations/capabilitiesanswerscanCreateper caller by the same rule instead oftruefor everyone.- A managed deployment that declares
organizations.creatorsno longer refuses organization creation at its proxy and no longer answers the capability probe there; one that declares nothing is unchanged. - The CLI refuses a deployment specification whose creator list is empty, longer than 64, repeats an address in another spelling, or names something that is not an address; an
environmententry that tries to setTALE_ORGANIZATION_CREATORSis refused as a managed key. POST /api/app/users/update-passwordanswers{ ok, passwordExpiry }— the credential's recomputed expiry status — where it answered{ ok }; the app leaves the forced-change wall on that value and re-reads only when a backend answers none.
API contract changes
- None. The OpenAPI document stays at 1.15.0 with 80 paths, 127 operations and 58 schemas, and the
Error.codeenum keeps its 150 values.ORGANIZATION_CREATION_FORBIDDEN(403) is a code of the Better Auth door, likeSIGN_UP_CLOSED;/api/v1mounts no organization-creation route, and the REST registry records the code as app-only. ThepasswordExpiryfield on the password write is an addition to an/api/appdoor — the app's own session API, not the machine contract.
Security
- Organization creation is now a named-list decision made in the backend (#3413). Before, a managed deployment's only protection was the proxy, which the sandbox network bypasses, and a self-managed deployment had no control at all. The default for a deployment that sets nothing is unchanged in both cases — open where it was open, refused at the edge where it was refused — so the release itself widens nothing; an operator who sets the variable narrows creation to the people named.
- What the list does not cover. A managed deployment that declares no creators keeps today's edge-only refusal, so a signed-in session on the sandbox network can still reach the backend's open create door there, as before this release. Declaring a list closes that door in the backend too. A session is required in every case; the route never answers an unauthenticated caller with anything but 401.
- No dependency changes in this range, and no advisory is fixed. The
@better-auth/oauth-provideradvisory noted in 0.5.33 (CVE-2026-67332 / GHSA-p2fr-6hmx-4528, medium) remains open with its workaround in place; the 1.7.0 upgrade is still a separate dependency pull request.
Known issues
- A managed deployment gets the new behaviour only once its specification declares
organizations.creatorsand a new bundle is applied. Until then its proxy refuses organization creation for everyone, exactly as on 0.5.33 — the release alone changes nothing on such a deployment. - The browser round for
AUTH-B9is manual: the picker entry disappearing for an unlisted member, the forbidden page, and the entry returning for a listed one. The backend gate, its wiring, the capability route and the CLI declaration are automated, and the signed-in refusal is proved against real Postgres in the backend integration check.AUTH-F20(an administrator-set password's first sign-in leaving the wall) is likewise a manual box beside its browser and integration specs. - The list is matched against sign-in addresses. A person who signs in through enterprise SSO is matched by the address the directory reports; a renamed address must be renamed on the list.
- Unchanged from v0.5.33, where each is described in full: the sign-up gate's first-boot race; the boot catch-up that marks provisioned accounts verified asks nobody; the break-glass administrator's password-rotation, single-sign-on-link and memory-adapter limits; the cross-scope webhook guard governs deliveries from that release on; a site's robots policy upgrades at its next scan; a scan waiting on render capacity takes longer by design; the governance pickers list only providers with an active credential; one dependency advisory is open.
- Unchanged from v0.5.32, where each is described in full: the embedding pacing is proved against a controlled server, its bound is per Tale process, and
minTokensPerSecondis a statement nothing verifies; the Kubernetes page's verified scope is one kind cluster,config-dataneeds RWX or a single node, and Tale ships no Helm chart. - Unchanged from v0.5.31, where each is described in full: a managed deployment picks up that release's proxy policy only when a newly prepared bundle is applied; the transcription setting is only as good as the organization's credentials; the six agent-turn fixes are bounded by the pinned Claude Code build they were read from; the 0.5.29 proxy change has been exercised live in
TLS_MODE=letsencryptonly; the web tier's backend-URL default lives in the image, not in the generated compose; the scheduled-pack fix does not reach an automation an organization already has; a budget hold covers a turn's first round only; a run still carries no usage or cost; nothing backfills a task timeline. - Unchanged from v0.5.20, where each is described in full: the
es/co-ccColombian cédula detector still ships switched off and a locale-agnostic PII toggle still widens national-ID matching to every locale; thinking-block replay on the native Anthropic connector is not done and the live Max-plus-tool-call check is still owed;rag_searchembedding calls inside a harness turn are unmetered; the product edit dialog cannot clear a field; the app's skill editor still carries the retiredprivatevisibility. - Cloud sync, left for later: there is still no Sync now action — the cadence is the fifteen-minute scan, so a reconnected account waits for the next run. A config whose owner leaves the organization is still deactivated silently by a different door, and a source-deleted item is still a status stamp with no bell.
- Documents indexed before 0.5.27 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. - The rail's navigation memory has had part of its manual round: the R5 round drove six EN/DE/FR desktop and phone cases covering parts of
NAV-F16–NAV-F19; the remaining section, the second-account cases andNAV-B6–NAV-B9are still unrun. - 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
visionmodel reads an image over REST only on a thread the app continued with an image attachment; the design of anattachmentsfield on the send is recorded as contract debt. - No REST door authors or deploys an automation —
POST /automationsanswers 405 by design. Build and deploy in the app, or over the MCP endpoint'ssave_automationanddeploy_automation; the REST key lists, reads, runs and wires triggers. - The
x-tale-paginationextension is a declaration on the OpenAPI document; generated clients that do not read vendor extensions still branch on the two cursor names untilcursoris retired. - The app's zip upload of a skill bundle rewrites the bundle and moves
updatedAteven when the zip is byte-identical, wherePUT /skills/{slug}writes nothing. - A tool call the reply cap cut keeps
input: {}on the storedtool-callpart; 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.
- Two bounded document readers still filter after their cut; both report an honest
truncated, so a caller can tell the answer was cut. - 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
ip6tablesand the reverse proxy's network is IPv6-enabled — an operator item, documented on the Own Compose page. - Recorded as contract debt, each with its design in the ledger: a queued send is invisible on the message list until a worker opens it; a webhook delivery the deployed
inputsschema refuses moves no trigger stamp; the MCPrun_deployedtool keys its idempotency apart fromstart_runand REST; a page is fetched three to four times per scan; a cancelled run answerstrace: nullandeffects: nullwhere a failed run answers both; approvals and asks have no REST twins; a task cannot be archived or deleted over REST; a webhook bind does not say whether the deployedinputsschema admits a delivery; an exhaustedrepeatUntilis only a trace note;Websitecarries noscanStartedAtand 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 stampsscore: 0; noIdempotency-Keyon the task start; no queue position on a queued send; a corrupt Office document still fails asindexer_errorand is retried five times where a PDF landsmalformed; no/.well-known/security.txt; no changelog feed on tale.dev; no SDK, collection or per-code table beyond theError.codeenum;GET /notificationsrows carrytypeas a free string and nothing pushes them to a machine caller; a skill keeps no version history on the machine door; the per-task circuit breaker is not built; the messages a conversation snapshot applied are readable only in the app.
Migration notes
- No migration. The application database stays at 0107 and the knowledge database is unchanged; the boot-time account catch-up from 0.5.33 keeps running and matches nothing once every provisioned account is verified.
- One new environment variable:
TALE_ORGANIZATION_CREATORS, documented in.env.exampleand in the environment reference in English, German and French. Unset means unchanged behaviour, so no deployment has to act on this release. - One optional addition to the managed deployment specification,
organizations.creators. A specification that declares nothing behaves as before; a managed deployment whose runtime bundle was prepared by an older CLI is unaffected until a bundle prepared with this release's CLI declares the list. - One new error code,
ORGANIZATION_CREATION_FORBIDDEN(403), on the Better Auth door only. - No image in the stop-gated tier changes. The
proxyanddbimages carry no source change. The managed proxy policy the CLI renders changes only for a deployment that declares creators. A plaintale deployis the whole upgrade: no--stop, no downtime window. - The platform image (the gate, the capability route, the shared allowlist parser, the forced-change wall's answer) and the docs image (three pages in each of English, German and French: the CLI install page, the first administrator and the environment reference) carry source changes. web and ui-docs rebuild with no change of their own. The
db,proxy,sandbox,sandbox-runtime,sandbox-buildkitd,sandbox-egressandsandbox-llm-gatewayimages carry no source change. - The CLI has source changes in this range — the
organizations.creatorsdeclaration, its runtime variable, the policy rendering and the bundle reader — so a managed deployment must move its pinned CLI reference as well as its platform reference to declare the list. The release executables report 0.5.34. @tale/uiand@tale/marketing-uiare pinned by this release as theui-v0.5.34andmarketing-ui-v0.5.34tags on their snapshot branches; a consumer outside the monorepo installs"@tale/ui": "github:tale-project/tale#ui-v0.5.34". Neither package has a source change in this range, so both tags are content-identical to their 0.5.33 predecessors.
Upgrading
-
On the 0.5 line (0.5.0 – 0.5.33):
tale update tale deploy
Nothing in this release needs
--stop. A deployment crossing from a version older than 0.5.29 should read that release's notes, which do: itsproxyimage change is only applied by a--stopdeploy. A deployment crossing 0.5.33 runs that release's migration 0107 at boot. -
Want to limit who may open a new organization? Set
TALE_ORGANIZATION_CREATORSto their sign-in addresses in the deployment environment and redeploy; the first organization stays allowed, everyone else loses the Create organization entry and is refused at the API. Leave it unset to keep the open behaviour. -
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. To open organization creation to named people, add
organizations.creatorsto the specification before preparing that bundle; without it the proxy keeps refusing creation for everyone. The bundle's backend-local phases run under the interpreted CLI (cli/tale.mjs) that thesetup-cliaction andbun run --filter @tale/cli buildproduce beside the executable; the executable from the release page has no interpreted bundle beside it and cannot prepare a managed bundle. On a Linux x64 host whose CPU lacks AVX2, passlinux-baseline: 'true'to thesetup-cliaction 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 withbun run build:linux-baselineintools/cli.
What's Changed
- feat(platform): let the operator name who may create an organization by @larryro in #3413
- fix(platform): release the forced-password wall on the write's answer by @yannickmonney in #3412
Full Changelog: v0.5.33...v0.5.34