← Back to list

How we built a one-shot PR creator at Inkitt

Well defined, low-risk tasks go straight from idea to PR with no setup required. Here is how we did it.

Agi Letkiewicz Tanner in Inkitt Tech · 2026-08-26 22:24 · 1 claps · 4.2 min read
#ai-workflow #ai-workflow-automation
Open on Medium ↗
Wiki topics: CRY · Crypto & Web3

How we built a one-shot PR creator at Inkitt

The classic problem: small tasks take more than their fair share of resources because the context switch costs more than the change itself.

As models keep improving, taking some of those well-defined tasks from idea to completion with no human input is now genuinely possible. Developers can run these end-to-end workflows on their machines, but that still spends developer time (a constrained resource). In principle anyone in the business could run one, but local machine setup is a wall for most people.

So we set out to build a one-shot PR creator for low-risk, small-blast-radius tasks that runs on remote servers instead. You ask our agent in Slack or add a label in Linear and you get a PR ready for testing and review.

Here is how we did it.

Some ground rules

  • Don’t pay for idle resources. The expensive part should only exist while it’s working.
  • Access is the absolute minimum needed.
  • Production data and apps are guarded against unintended actions and bugs.
  • Rejecting is a feature. Risky, large or ambiguous tasks are not attempted.

Key design choices

1. A loop, not a pipeline

A single orchestrator listens for events and runs stages. Each stage is one container with a model in it, one prompt, and one job: turn the request into a spec, write the change, check the change against the spec, fix CI, resolve a conflict.

The orchestrator’s core is a pure function (run state, event) -> nextaction. No network, no database, no model call. A run is one row in a database and the loop can be picked up mid-flight.

The main guardrails live in ordinary code, not in the model’s judgement: two verify rounds, two CI fix attempts, two goes at a merge conflict. We also enforce hard rules on what a change may touch: no DB migrations or schema changes, no shared contract changes, no CI or container-build config, no auth or payment code, and no package additions or updates.

2. The agent containers have no access to the outside world

The orchestrator holds the credentials. It posts to Linear and Slack, opens PRs, applies labels, and pushes to shared branches. The containers running agents hold only a short-lived repo token and a model key. No Slack token, no Linear key, no cloud identity, and no tools for making arbitrary network calls.

So a stage can read code and write code. It cannot file a ticket, open a PR, message anyone, or fetch something off the internet. Everything that leaves the building goes through the orchestrator, which means there is one place where actions reach the outside world, and one place to audit.

It also means the guardrails don’t run on the honor system. The check for “did this change touch a file it isn’t allowed to touch?” reads the diff from git, not from the agent’s own report of what it changed.

3. The user is the bot

Linear, GitHub and Slack all see a single bot account. The big advantage is permissions: the bot can be granted far less than a typical dev. It can’t force-push, can’t bypass branch protection, can’t merge its own work, and can’t touch the paths we’ve marked off-limits.

It also keeps attribution honest. The commits are the bot’s, and every message the bot sends names the human who asked for the run.

The last checkpoint stays human. PRs open as drafts. The requester is notified when a PR has passed CI checks and the changes are live in staging, ready for testing. Marking it Ready for review is the moment a human vouches for it. The bot suggests reviewers in plain text, but the human does the requesting and the approving.

The full architecture, in summary

A trigger. A Linear label, a Slack mention, or an API call from another agent. All three come through one front door, authenticated and deduped.

A long-lived orchestrator. Small and mostly asleep. It decides the next action, performs every side effect, and owns every credential.

Short-lived stage containers. One per step, started on demand, alive for minutes, then gone.

One row per run. Anything that must happen at most once — claiming the branch, the PR number, the next retry attempt — is won in a single conditional write. Duplicate deliveries are routine, so the loser of the race stops instead of starting a second container.

A path gate, run twice. We check for paths we’ve marked off-limits once before any code is written, and again on the real diff before the PR opens.

All outputs from the orchestrator. Linear ticket and status, draft PR with labels and suggested reviewers, the staging build, the Slack message.

The run itself is one line:

intake → gate → implement → verify → gate → review → ticket → draft PR → build → CI green → done

Everything else is a detour that rejoins it. A failed verify goes back to implement. Red CI goes to a fix stage. A conflicted cherry-pick goes to a resolver. Each detour twice at most, then it stops and says why.

Two things that surprised us

The model was the easy part. Almost all of the difficulty was in the boring stuff: idempotency, locks, retry budgets, and who is allowed to say what.

Writing to a tool that webhooks can trigger is a loop waiting to happen. Filtering and de-duping is key, because Linear and GitHub webhooks are noisy. CI completion events, for example, fire on every CI job, not once per PR. So to know whether all of a PR’s jobs have actually finished, we call back to the GitHub API and ask, rather than taking action on every event that arrives.

Where it is now

This workflow ships code for us daily, sometimes moving a ticket from idea to done during the meeting that it was mentioned. There’s also a local “pro” version for tasks too big for one shot, where a human stays in the loop but the development process stays obfuscated.

With a more clear backlog and fewer interruptions, our dev team is freed up to think about the big, important problems. And that is the biggest unlock of the whole project.


메타데이터
post_id
e1b8dbc52cda
slug
how-we-built-a-one-shot-pr-creator-at-inkitt-e1b8dbc52cda
url
https://medium.com/inkitt-tech/how-we-built-a-one-shot-pr-creator-at-inkitt-e1b8dbc52cda
canonical_url
https://medium.com/inkitt-tech/how-we-built-a-one-shot-pr-creator-at-inkitt-e1b8dbc52cda
author_url
https://medium.com/@altanner
status
ok
fetched_at
2026-08-31 12:37:36