Triage Factory
GitHub Install
← all releases
v1.16.0

Linear, and tracking that survives renames

Linear joins GitHub and Jira as an event source. Everything TF tracks is now keyed by the provider's id, so a rename no longer breaks rules, tasks, or checkouts, and in the multi-tenant deployment nothing a command does inside its sandbox ends the run.

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

Fixes

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.