Skip to content

Tale v0.5.30

Choose a tag to compare

@larryro larryro released this 16 Sep 09:14
17a1353

0.5.30 is a two-change patch on the 0.5 line, and both changes are for a deployment an operator assembled themselves: a healthy stack no longer reports Service outage on its public status page, and the Own Compose guide finally lists the egress proxy's real capability set and the IPv6 sysctls it has needed since 0.5.18. Nothing changes shape — no migration, no contract change, no configuration file, no image in the stop-gated tier. The upgrade is tale update followed by a plain tale deploy.

Highlights

A healthy stack no longer reports "Service outage" (#3390)

The web tier reads TALE_BACKEND_URL to find the application backend: the public /status page probes its liveness route, and the web server asks it for the verdicts only a database can answer. Both fell back to http://127.0.0.1:3005 — the loopback address bun dev uses on a developer's machine. Nothing listens on loopback inside the platform container, so a deployment whose compose file left the variable unset showed Service outage on /status and backend: outage in /status.json, with the database and object-store rows following the same failed probe, while /api/health, the login page and every API door answered normally. The page that exists to tell your users the service is fine was the only thing claiming it was not.

The shipped compose.yml sets the variable and a managed deployment ships that file, which is why the hosted instances never showed it. Two paths did, and both were seen live this week: an install assembled from the Own Compose guide, whose platform example carried only env_file, and a CLI workspace, whose generated colour compose does not set it either — confirmed on a workspace freshly upgraded to 0.5.29, answering outage while its /api/health reported 0.5.29 and its REST door answered the contract.

The platform image's entrypoint now defaults TALE_BACKEND_URL to http://backend-api:3005 for the web role, exactly as it has always defaulted SANDBOX_URL. The fix therefore travels with the image and asks nothing of the operator's compose file. An explicit value still wins, so a backend service under another name is unaffected, and the api and worker roles — which exec before the entrypoint sources that script — never read it. Outside a container, bun dev and vite preview keep the loopback default.

The variable is also documented for the first time: the environment reference's deployment-topology table, the Own Compose service table and .env.example, in English, German and French. A deployment that cannot move to this release yet sets TALE_BACKEND_URL: http://backend-api:3005 on its platform service — or in the workspace .env — and recreates that container.

The Own Compose guide states the egress fence's real requirements (#3391)

"Run Compose yourself" is the page for assembling the stack by hand, and its capability table for sandbox-egress had frozen at the pre-0.5.22 set, with the IPv6 sysctls never mentioned at all. An operator building the service from that table got one of two failures, neither of which the page explained:

  • A proxy that cannot stop. Without KILL, the root supervisor cannot signal tinyproxy once it has dropped to nobody, so every docker stop waits out the grace period and ends in exit 137 instead of draining. KILL has been in the shipped capability set since 0.5.22, and those release notes told own-compose operators about it.
  • A proxy that refuses to start. The egress firewall fails closed: it needs working IPv6 netfilter, or IPv6 disabled for the default and for every interface in the container's network namespace, and it exits rather than serving traffic it cannot fence. A container cannot write those sysctls itself through a read-only /proc/sys, so on a kernel without the ip6_tables module the service never comes up. The two disable_ipv6 sysctls have been in the shipped stack since 0.5.18 and were never announced.

The capability row now carries the full set including KILL with its reason, and a new Egress IPv6 row carries both sysctls, the reason and a link to the reference's Sandbox infrastructure section, which already explains the same requirement for Kubernetes. The shipped compose.yml and the CLI's generator have carried both all along; only the guide lagged. English, German and French.

Behaviour changes

  • The platform container's entrypoint defaults TALE_BACKEND_URL to http://backend-api:3005 for the web role. An explicit value from compose or .env still wins; the api and worker roles never read it; bun dev and vite preview keep the loopback default.
  • Nothing else changes at runtime. The rest of the range is documentation, and the two code edits beside the entrypoint line are comments.

API contract changes

None. The OpenAPI document stays at 1.13.0, unchanged at 80 paths, 127 operations and 58 schemas, and the Error.code enum keeps its 150 values.

Security

  • The sandbox's network fence is unchanged; the page that tells an operator to build it is not. Nothing about the egress proxy moved in this release — the shipped stack and the CLI generator already carry the sysctls and the least-privilege capability set. But an operator whose hand-built proxy would not start had no documented cause to reach for, and the nearest guesses — a wider capability set, dropping the cap_drop: ALL line, leaving the egress service out of the stack — all weaken the only outbound boundary the sandbox runtime has. The guide now names the requirement and the reason. The fence itself behaves correctly under the failure: it refuses to start rather than passing traffic it cannot filter.

Known issues

  • The 0.5.29 proxy change is now exercised live, but only in one TLS mode. The hosted fleet moved to 0.5.29 after those notes were written, so the rendered trusted_proxies block and the removal of the X-Forwarded-Proto {scheme} pins are proved on a running deployment in TLS_MODE=letsencrypt. No deployment on TLS_MODE=external has exercised them; an operator there should still verify sign-in callbacks, secure cookies, uploads and streaming through the full path.
  • The web tier's new default lives in the image, not in the generated compose. A workspace deployed with the CLI gets the correct behaviour once its platform container runs a 0.5.30 image, but the compose file the CLI writes still names no TALE_BACKEND_URL, so the value is invisible to an operator reading that file. Any deployment still on an older platform image needs the explicit variable.
  • The scheduled-pack fix does not reach an existing install (#3381, 0.5.29). Provisioning skips an automation an organization already has, so an upgraded instance keeps the version whose input schema refuses its own scheduler. Edit that automation's inputs to admit trigger and firedAt and deploy a new version; a new organization is seeded correctly.
  • A budget hold covers a turn's first round. A turn that calls tools runs up to five model rounds, each billing its full prompt again, and only the first round's worst case is held while it runs. Concurrent sends can no longer each pass a cap with room for one, but a long multi-round turn can still settle above the cap it was admitted under.
  • Nothing backfills a task timeline (#3379, 0.5.29). Edits made before that release wrote audit rows only and do not appear; a label deleted from the catalog renders as its raw id rather than dropping the row.
  • 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; 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.
  • 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. A site that has not been scanned since 0.5.27 has no stored robots rules until its next scan.
  • 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 and NAV-B6–NAV-B9 are 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 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 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 reverse proxy's network is IPv6-enabled — an operator item, documented on the Own Compose page. This is the edge proxy, not the sandbox egress fence #3391 documents.
  • 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 inputs schema refuses moves no trigger stamp; the MCP run_deployed tool keys its idempotency apart from start_run and REST; robots.txt $ end-anchors and Allow: lines are not honoured (prefix and * rules are), and a page is fetched three to four times per scan; a cancelled run answers trace: null and effects: null where a failed run answers both; a run carries no usage or cost; approvals and asks have no REST twins; 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 stamps score: 0 silently; no Idempotency-Key on the task start; no queue position on a queued send; a corrupt Office document 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; GET /notifications rows carry type as 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 0106 and the knowledge database is unchanged, so nothing runs at boot beyond the usual convergence check.
  • No new environment variable. TALE_BACKEND_URL is not new — the shipped compose has always set it. This release gives it a default inside the image and documents it for the first time. No configuration file changes shape, and the shipped automation catalog is unchanged.
  • No image in the stop-gated tier changes. The proxy and db images carry no source change in this range and the object store runs its pinned third-party image, so a plain tale deploy is the whole upgrade — no --stop, no downtime window.
  • The platform image (the entrypoint's new default, and two code comments) and the docs image (the en, de and fr Own Compose and environment-reference pages) carry source changes. The web, ui-docs, proxy, db, sandbox, sandbox-runtime, sandbox-buildkitd, sandbox-egress and sandbox-llm-gateway images have none. The CLI has no source change in this range — the one file it gained is a guard test — so a managed deployment's pinned CLI moves only for the version stamp; the release executables report 0.5.30.
  • @tale/ui and @tale/marketing-ui are pinned by this release as the ui-v0.5.30 and marketing-ui-v0.5.30 tags on their snapshot branches; a consumer outside the monorepo installs "@tale/ui": "github:tale-project/tale#ui-v0.5.30". Neither package changed in this range, so the content is identical to the …-v0.5.29 tags.

Upgrading

  • On the 0.5 line (0.5.0 – 0.5.29):

    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: its proxy image change is only applied by a --stop deploy.

  • 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. 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): default the web tier's backend URL to the compose alias by @larryro in #3390
  • docs(docs): list the egress proxy's KILL capability and IPv6 sysctls by @larryro in #3391

Full Changelog: v0.5.29...v0.5.30