Lines carrying multi-tenant apply only to the self-hosted multi-tenant deployment; local only to the single-user local binary; enterprise marks an Enterprise Edition feature, which needs a licence and runs only in the multi-tenant deployment. Everything else is for everyone.
The big stuff
Linear is an event source. Connect a workspace with an API key, or install Triage Factory as a Linear app, which acts as its own app user and takes no seat. A multi-tenant deployment can register one Linear app for every org with TF_LINEAR_CLIENT_ID and TF_LINEAR_CLIENT_SECRET. multi-tenant Each team picks the Linear teams it tracks and which workflow states mean pickup, in progress, and done, and gets the same default rules and disabled implementation trigger that Jira has. Claiming a Linear task assigns the issue to you and moves it to in progress, through your own Linear connection, and a requeue or undo puts it back. Agents get tfac exec linear issue, with twelve actions from view to create. Setup now asks for GitHub and then one optional tracker: Jira or Linear.
Renames no longer break anything. TF now tracks repositories, pull requests, Jira projects and issues, Linear teams and issues, and Slack channels by the provider’s own id, and keeps their names for display. A Jira issue whose key changes, because it moved project or its project key was renamed, keeps its entity, tasks, and memory and emits jira:issue:key_changed. Before, it froze for an hour, gained a duplicate, and lost its tasks in the merge. A project key rename no longer silently stops its team’s handlers and completion checks, and a checkout made before a repository rename is no longer dropped from a parked run’s snapshot. A repository deleted and recreated under its old name is a new repository, which a team can now track. A Slack channel that gets a new id through Slack Connect keeps its threads. enterprise Event-handler filters pick from the team’s tracked repositories, projects, Linear teams, and channels and store their ids, so a rename can’t break a filter and a typo can’t be saved.
A command can’t end its run. multi-tenant When a native run’s jail dies mid-call, from the memory limit or a runsc crash, it is restarted in place with /work and /tmp kept, and the loop carries on. A jail that keeps dying hands the claim back, and after three hand-backs in a row the conversation parks as sandbox_lost instead of failing. The agent is told when the memory limit killed something, and how to use less. A bash command with no timeout stops after 10 minutes, background processes outlive the call, and a call still running at 30 minutes restarts the sandbox instead of parking the run. /tmp is on disk, so filling it no longer kills the jail, and a resumed run is told its sandbox is new.
Also new
- Rate-limit budgets for every source, per credential and bucket, exported as
tf_upstream_rate_limit_*and served atGET /api/orgs/{org_id}/integrations/rate-limits, with a warning the first time a budget drops below 20%. github:pr:commentedandgithub:pr:mentionedevents. Review events now fire once per submitted review, thread replies included, andmergedandclosedname who did it.label_addedandlabel_removedfor Jira and Linear issues. Theircommentedevents name the commenter and skip TF’s own comments, and Jira’sreporter_infilter, which never matched, now works.- PR Security Review and PR Correctness Review, two single-pass blueprints that each post their own review.
- A GitHub-triggered run in an org with Jira or Linear gets those verbs too, and
<run_context>says why a source isn’t usable. - Settings says when a workspace’s own GitHub App was deleted on GitHub or its key was rejected, instead of looking healthy.
- A bare clone is reclaimed a week after its repository leaves every team’s tracked set. local
- SSO settings name the identity provider and use its console’s names for each field. enterprise
Fixes
- Any website you visited could open the local websocket and read every broadcast, transcripts included, and a DNS-rebinding page could read any API response. local
- Local runs loaded your
~/.claude/settings.json, whose allow rules widened a run’s tool allowlist and whoseenvcould override the credential stored in TF. They now load project settings only, and the bubblewrap sandbox no longer binds~/.clauderead-write. local - A member removed from an org could still list its Jira projects. multi-tenant Two open redirects in
return_tohandling are closed. - Require SSO is now checked on every request, API token, and websocket, and an SSO email is trusted only on the connection’s verified domains. enterprise
- Requeueing or undoing a Jira claim never put the ticket back. It now restores the status and assignee the claim changed.
- A settings save made while a credential was being connected or removed could be silently undone.
- A PR whose first write failed could stay untracked for days.
- A cold restore couldn’t fetch checkouts that another conversation on the task had added.
- A GitHub or Jira response that broke off partway is retried instead of failing the poll cycle.
- A Slack message whose thread or queue write failed was lost for good. enterprise
- Go moves to 1.26.10, which fixes 13 standard-library vulnerabilities reachable from TF.
- Issues that changed their names hoping to leave their tasks behind have been found by their ids, and the tasks returned to them.
Upgrading
A 1.15 local install upgrades in place. local A database that ran a main build since 1.15.0 needs ./scripts/clean-slate.sh. The Postgres baseline changed, so start a multi-tenant deployment on a fresh database. multi-tenant
Local mode no longer reads the TRIAGE_FACTORY_* credential variables or TF_HEADLESS. local Keep TF_SECRET_ENCRYPTION_KEY set, connect GitHub and Jira in Settings (over an SSH tunnel on a server), and then remove the old variables. Local runs also stop loading your user Claude Code settings (permissions, hooks, plugins, MCP servers, and CLAUDE.md), and a local instance answers only to localhost, an IP address, or its --host name.
Handler filters on a Jira project, status, new_status, old_status, priority, or issue_type, or on a GitHub repo, have to be picked again in the editor. Those filters take ids now, and a handler still carrying an old field is skipped. Filters on GitHub logins are rewritten to account ids during the upgrade.
The executor needs SYS_RESOURCE in its cap_add, and the cap-broker won’t start without it or under rootless Docker or Podman. multi-tenant The state root must be on disk, not tmpfs, and on bare metal TF_ORCHESTRATOR_UID must stay outside 20000–20255 and 39999–40255.
A GitHub Enterprise Server must serve fullDatabaseId on pull request reviews and comments, or the poll’s refresh query fails. An Atlassian app used for Jira Cloud Connect needs the classic read:jira-user scope. GET /readyz no longer reports rate_limit; alert on tf_upstream_rate_limit_remaining instead.
On the API: predicates name things by id (repo_in, jira_project_id_in, linear_team_id_in, author_id_in, and the rest), and the fields they replace are a 400. PUT /api/teams/{team_id}/github-repos takes repository_ids, registered first through POST /api/repos. The Jira catalog moved under /api/orgs/{org_id}/jira/projects, and listing conversations by the completed status is a 400, because a finished conversation now stays open with its verdict.