/ AGX Team

We Stopped Pretending Linear Was the Product

This week AGX replaced a lot of Linear-shaped assumptions with a tracker contract, and that changed more than a route name.

agx-cliagx-simtrackinglineararchitecture

The feature request that made this obvious was small.

Someone asked for pinned tickets in “the Linear view.”

That was a perfectly reasonable request. It was also the clue that our product language had fallen behind the system we were actually building.

Over the last few days, AGX shipped a dense run of task-tracking work: a multi-tracker abstraction layer, grouped status moves, native labels and estimates, folder rendering, optimistic status changes, session restore, and objective views that can pull work from tracker adapters instead of one hardcoded path. By the time that landed, keeping the surface named and shaped as “Linear” was starting to create the wrong kind of gravity.

The problem was not that Linear support was bad.

The problem was that Linear had become the name for too many unrelated things at once.

”Linear” had turned into a hidden architecture decision

For a while, “Linear” was doing too much work inside AGX.

It was a route name. It was a page owner. It was a board owner. It was an API shape. It was a worker mode. It was the default answer to the question, “Where do tasks live?”

That works for exactly as long as your product is honestly just a Linear frontend.

But once you start adding tracker-specific status semantics, shared board filters, pinned items, tracker-aware scripted runs, and the possibility of more than one backend, the name stops being harmless. Every new feature becomes a vendor-shaped exception.

Pinning looks like a Linear tweak. Task grouping looks like a Linear tweak. Session restore looks like a Linear tweak. Future Jira support looks like a giant special case.

That is how you end up with a product that keeps getting broader while its core noun keeps telling a narrower story.

The important change was not Jira

The big local cut started earlier with the multi-tracker abstraction layer. That one commit added /api/trackers/[tracker]/**, tracker connections, /projects/[slug]/tracking, TrackerBoard, tracker stores, and a new task_worker execution mode. The stat line alone told the story: 52 files, more than 5,600 inserted lines, and a very explicit decision to stop putting new work behind Linear-only seams.

Recent follow-up work made the direction even clearer.

The board surface kept moving toward tracker-owned behavior instead of Linear-owned behavior. The sidebar now has a Task Tracking section. The board route is /tracking. The scheduler can talk about task_worker and trackerType instead of assuming one source forever. The objective workspace can fan out across active tracker connections and ask each one for matching items.

The mental model changed from this:

// old shape
/projects/[slug]/linear
executionMode: "linear_worker"

to this:

// new shape
/projects/[slug]/tracking/[tracker]
executionMode: "task_worker"
trackerType?: string

That may look like a rename. It is not a rename.

It is a boundary change.

And that boundary change matters even if the only truthful backend today is still Linear.

That is the part I like most about this week: AGX did not need to ship a dozen integrations to justify the move. It only needed to stop lying about what layer owned the work.

Linear is now an adapter. Tracking is the product surface.

That is a much healthier sentence.

The cloud repo asked the right question

What made this story worth writing was not just the local implementation sprint. It was the parallel work happening in the cloud repo.

One of the most useful vault notes from this week is a blocked investigation literally named around tracking-parity. The note does not ask, “Which old Linear ticket should absorb one more parity fix?” It asks a much sharper question:

What is the smallest truthful hosted owner for /tracking, /api/trackers/**, and tracker-aware board, run, and session state?

That is the real question.

Not whether one existing ticket can quietly stretch. Not whether the nav can point to a new route before the backend exists. Not whether hosted should pretend Jira support is already real.

Just: where is the ownership boundary, and what is the first irreversible cut that lets later work stop rebuilding the old Linear-only surface?

The answer in the vault is refreshingly disciplined.

Hosted should converge on the tracker-shaped contract. Hosted should keep linear as the only enabled adapter until more is truthful. Hosted should preserve compatibility for old /linear links during transition. Hosted should not fake multi-backend support just because local already has broader shapes.

That is not flashy work. It is much better than flashy work.

Once you make that call, local and cloud can finally split cleanly:

  • local can keep deepening the board UX
  • cloud can own the route, API, and state parity cut
  • future tracker backends stay explicitly out of scope until they are real

This is the kind of engineering move that removes weeks of future ambiguity.

What this changes in practice

If you only look at screenshots, the surface change can seem cosmetic. Maybe the sidebar says Task Tracking instead of Linear. Maybe a route moved. Maybe a board component got renamed.

But if you use the product, the difference is more important than that.

When the task surface is tracker-shaped instead of vendor-shaped, a bunch of everyday requests stop feeling like weird one-offs:

  • “Pin a few tickets at the top”
  • “Group tasks by status”
  • “Use native labels and estimates”
  • “Reconnect this tracker”
  • “Run work against the right tracker from the scheduler”
  • “Let objectives pull the matching work no matter where the tickets live”

Those are not integration edge cases anymore. They are just board features.

That changes how we build.

It also changes how we debug. If the product still thinks in Linear-shaped seams, every bug report has to be mentally translated back into the broader system. If the product thinks in tracker-shaped seams, the report arrives much closer to the right ownership layer.

That is why the request for pinned tickets mattered so much. The user was asking for a normal workflow improvement. Our old naming made it sound more specific than it really was.

The request was never “please make one vendor screen better.”

It was “please make task tracking behave like task tracking.”

The real win is that the noun now tells the truth

A lot of platform work fails in a subtle way: the implementation starts widening, but the public contract never catches up. The code knows more than the product language does. The route names, worker types, and ownership boundaries keep carrying assumptions that everyone already outgrew.

That is where drift comes from.

This week, AGX corrected that drift.

Not all at once. Not perfectly. Cloud parity is still work. Compatibility still matters. There are still sibling tickets that need to land around the new contract.

But the important decision is made now.

We are no longer deepening a Linear-shaped product and hoping it somehow grows into something broader later.

We are building a tracking surface, keeping Linear as the first real adapter, and forcing ourselves to be honest about where the rest of the parity work belongs.

That is the kind of change that looks smaller than it is when you read the commit titles, and bigger than it is once you feel the next few weeks of work get simpler.

Sometimes progress is a new feature.

Sometimes progress is realizing that your old noun has become a lie, and fixing it before the lie hardens into architecture.