Hey tech adventurers! 👋
Confession: I'm building a tool where agents pick up Linear issues, do the work, and open PRs. It's called Paws. And testing that against a real Linear workspace is a great way to teach your coworkers what an agent sounds like at 3am. 😅
So I did the reasonable thing and built my own Linear. Locally. In a few hours. Like a normal person.
Mocks lie, and agents believe them 🤥
The usual move is to mock the API. Stub issue.update, return some JSON, call it a day.
Except agent workflows don't really live in single calls. They live in the stuff between calls. A webhook shows up twice. A delivery fails and retries an hour later. An OAuth token rotates mid-session. A human answers the agent's question in a comment thread. Mocks happily skip all of that, and then production finds it for you.
I didn't want a fake that agrees with me. I wanted one that argues back.
Meet Finear 🏠
Finear is a local, Linear-compatible server for integration tests. Bun, SQLite, done.
The part I'm weirdly proud of: it runs the unchanged @linear/sdk against real GraphQL. My code doesn't know it's being lied to. It just points apiUrl somewhere else.
What's actually in there:
- Issues, projects, sub-issues, labels, threaded comments 📋
- OAuth consent, PKCE, refresh rotation, revocation 🔐
- Signed, durable webhooks with retries 📬
- Agent delegation, sessions, activities, and the human prompts in between 🤖
- Deterministic fixtures and a reset button 🧽
I can fast-forward time now ⏰
Real webhook retries wait a minute, then an hour, then six hours. Waiting six hours to watch a test fail is not a personality I want.
So Finear has a virtual clock. Advance it, and due retries fire in order, instantly. Inspect every delivery and every attempt. Reset the whole world when you're done.
It's the closest I'll ever get to time travel, and I used it to debug webhooks. 🫠
The agent part 🐕
This is why it exists. Delegate an issue to an app and Finear creates an agent session. The agent can post thoughts, take actions, ask the human a question, and finish with a response or an error. The questions and answers show up as normal comment threads, like you'd expect.
That's exactly the loop Paws lives in. Now I can break it as many times as I want, on my laptop, without a single "hey, why is a bot commenting on my issue?" DM.
The fine print 🧾
Finear is a test harness, not a Linear replacement. It binds to 127.0.0.1 on purpose, and it isn't affiliated with Linear in any way. Please don't run your team on it. I'm begging you.
How to set it up lives in the README. This post is just me admitting I built a whole issue tracker so my agents could fail in private.
P.S. If your integration tests mostly test your mocks, I'm not judging. I was there two weeks ago. 🍕
Top comments (2)
"Mocks lie, and agents believe them" is the perfect summary. The between-calls behavior — duplicate webhooks, retry storms, mid-session token rotation — is exactly where agent integrations break in production, and it never shows up in unit tests. The virtual clock is the elegant part: time as an injectable dependency should be table stakes for any agent test harness.
虚拟时钟这招太妙了,webhook 重试原本要等几小时才能走完的路径现在可以瞬间验证。让我想起 Stripe 的 test clock,也是同一种思路——时间本来就该是可注入的依赖。