AI dev tools · GitHub App2026Live
Landpatch
GitHub App that migrates code off the shut-down OpenAI Assistants API. It finds the call sites, has a model patch them onto the Responses API, verifies the patch in a sandbox and opens a pull request only when verification passes.

At a glance
5 of 6
- Call sites migrated in a real PR (PrabalParihar/chatbot#1, +83 −64); the 6th held for a maintainer
- PR opens only after a 10-minute sandbox passes: install, typecheck, lint, tests, contract test
- $2 LLM budget per run, enforced before a model call starts
What it is
Turn a breaking API shutdown into a reviewed pull request that has been verified in a sandbox, without giving a bot unchecked write access to the repository.
Why it exists
OpenAI shut down the Assistants API on 26 August 2026, and every app still calling threads, runs and assistants broke. The migration is mechanical but easy to get subtly wrong, and nobody wants an AI bot pushing unverified code into their repository.
How it works
Installing the GitHub App sends a webhook to a Hono API, which stores the repositories and queues a run on pg-boss in Postgres. A worker shallow-clones the repository, finds Assistants call sites with ast-grep rules and confirms the receiver with ts-morph, then asks a model (OpenAI, Anthropic or OpenRouter) for a patch scoped to one function. The patch is verified in a Docker sandbox, and the pull request is opened only if that passes; otherwise the draft is stored on a Next.js dashboard with its diff and cost.
Decisions worth explaining
Guardrails refuse, they don't just report
The $2 budget, the 10-minute sandbox and the three-job concurrency limit are checked before work starts. A model call that would cross the estimate never runs, instead of being flagged after the money is spent.
Hold hard cases for a person
Moving files attached to an assistant into a vector store needs a human decision, so that call site is held and the reason is written into the pull request. An assistant id with no local config becomes a TODO that throws until OPENAI_MODEL and OPENAI_INSTRUCTIONS are set.
Least-privilege app, signed webhooks
The app asks only for contents, pull requests, checks, metadata and issues, never administration, secrets or Actions. Every webhook delivery is signature-checked and stored once per delivery id, so a retried delivery never starts a second run.
Results
- Live as a GitHub App, with three Railway services (web, API, worker) on one Dockerfile plus Postgres.
- Opened PrabalParihar/chatbot#1: 5 call sites moved to the Responses API and 1 held for a maintainer with the reason written down.
- pnpm and Turborepo monorepo: scanner, patch loop, sandbox, GitHub and migration-pack packages; self-hostable with Docker.
Stack
From the code
/*** Hard limits for a migration run. Later stages must refuse work that would* cross these, not merely report it after the fact.*/export const GUARDRAILS = {llmBudgetUsdPerRun: 2,sandboxLimitMs: 10 * 60 * 1000,maxConcurrentWorkers: 3,} as const;export function assertWithinLlmBudget(spentUsd: number,limitUsd: number = GUARDRAILS.llmBudgetUsdPerRun): void {if (spentUsd > limitUsd) throw new LlmBudgetExceededError(spentUsd, limitUsd);}