You assign a task in one sentence. An agent reads your repo, writes a plan, makes the changes, runs the tests, fixes what broke, reviews its own diff, and opens a pull request. You review the PR like you would a junior’s. That is the promise of Devin, and of Cursor’s background agents, and it is not hype — it works.

Here is what bothered me. My source code gets cloned onto their machines. The work is metered per task, so the tool gets expensive exactly when it is useful. And the agent is a black box I configure but do not control — it does not know my conventions, my review checklist, my definition of done.

So over a few evenings I built the same thing on my own hardware, on the Claude Max subscription I was already paying for. I call it Origin, and it runs inside the self-hosted agent workspace I use with my team. This post is the architecture — the whole thing — because once you see it, you realize an autonomous engineer is not a moonshot. It is an orchestration layer over parts you probably already have.

The uncomfortable truth: it is mostly plumbing

I drew the entire system before writing a line of new code. Here it is:

flowchart LR
  U["me / a teammate"] -->|"assign · or label an issue"| O["Origin surface"]
  O --> ORC["orchestrator"]
  ORC --> BR["Claude Agent SDK"]
  BR --> WS["isolated repo clone"]
  WS -->|"push branch + PR"| GH["GitHub"]
  ORC -->|"run the tests"| TST["test runner"]
  ORC -->|"verify the diff"| RV["auto-review"]
  BR -.->|"plan · tool · diff · test · pr events"| O
  GH -.->|"issue label / PR comment"| ORC

Now look at what each box really is:

  • The executor is a library. The Claude Agent SDK gives you the autonomous loop with real tools — a persistent shell, a file editor, git, web search, MCP servers. You point it at a directory and it reads, edits, and runs commands until the task is done. This is the genuinely hard part, and someone else wrote it.
  • The git lifecycle is a shell script. Clone, branch, commit, push, open a PR. There is no AI in that, and you want none — deterministic git means a hallucination can never push to main.
  • GitHub is already an API. gh opens the PR. Tests run with the repo’s own command. Review runs with whatever reviewer you already trust.

Roughly 70% of an autonomous engineer is infrastructure that already exists. When I mapped mine:

CapabilityStatusWhat it actually is
Autonomous executor (shell · edit · git · web)Had itClaude Agent SDK
Clone → branch → commit → push → PRHad ita shell wrapper
GitHub identity per userHad itgh + a token
Run the repo’s testsHad itthe repo’s own command
Claim-verifying diff reviewHad ita reviewer agent
Live streaming of the workHad itthe SDK event stream
Kill switch & approval gateHad ita stop flag
Run state machine + event logNewtwo small tables
Isolated workspace + limitsNewa worker + worktrees
Plan → build → test → review → PR loopNewthe orchestrator
The UI (board · session · diff)Newone tab

The new work was small: a run record, an orchestration loop, and a UI to watch it. The agent brings the judgment. Everything around it is ordinary software I fully control. That framing is the whole unlock.

The loop that turns a demo into a colleague

A single “do the thing” agent call is a party trick. The thing you would actually let near a real repo is a state machine with checkpoints:

flowchart LR
  Q([task]) --> P[Plan]
  P -->|"⚑ approve plan"| B[Build]
  B --> T[Test]
  T -->|fail| B
  T -->|pass| R[Review]
  R --> S[Ship]
  S -->|"⚑ approve push"| PR([Pull request])
  1. Plan — read the codebase, break the goal into a checklist with explicit acceptance criteria.
  2. Build — implement in an isolated clone, streaming every command so I can watch it think.
  3. Test — run the suite. On failure, feed the output back and fix. Bounded to a few rounds so it cannot loop forever.
  4. Review — run a claim-verifying reviewer over its own diff before it dares ask me.
  5. Ship — push a work branch, open a PR with a written summary. It never merges to main.

Two stages carry an optional human gate: approve the plan before a single line is written, and approve before anything is pushed. The default posture is the most important design decision I made:

Origin is a colleague who opens pull requests. It is not a bot with commit access to main.

That sentence is the difference between autonomy I trust and autonomy I fear. I get the leverage of an agent that works while I am in meetings, and I keep the one thing that matters — the merge button.

Two tables and a handful of endpoints

The whole state lives in two tables. A run is a durable record; its events are an append-only log, so the session view rebuilds perfectly on reload and every action is auditable.

runs        id · title · goal · repo · base_branch · work_branch
            status (queued→planning→building→testing→reviewing→awaiting_push→done / blocked / failed)
            plan · pr_url · budget · cost · approval_mode · member

run_events  id · run_id · seq · kind (status·plan·tool·text·diff·test·pr·error) · payload
            // append-only · redacted · drives the live UI and the audit trail

Everything the UI shows and everything the auditor needs is a projection of that event log.

The build, in six phases

I shipped it in dependency order. P0–P1 was a working MVP in about a week — assign a task, get a PR. Through P4 is the bar before anyone else touches it.

PhaseDeliversEffort
P0 Data model & surfaceRun record, event log, an empty board on real endpoints~1–2 days
P1 Repo executionClone → agent edits in the repo → push → PR~2–3 days
P2 The loop & gatesPlan → test-fix → review, plan/push gates, steering~3–4 days
P3 Live session UIBoard + plan, streaming activity, diff, tests, PR~3–5 days
P4 HardeningIsolation, secrets, guardrails, budget, audit~1–2 weeks
P5 Team integrationIssue-label & PR-comment triggers, per-project config~3–5 days

The 90% nobody demos: making it safe

Every flashy autonomous-agent video stops at “look, it opened a PR.” The gap between that video and a tool your team uses every day is entirely in the unglamorous safety work. This is where I spent most of the time:

ControlWhat it does
IsolationEach run gets its own worktree under an unprivileged sandbox user, in CPU/memory/time limits
Scoped secretsThe GitHub token is injected into one run’s env, never persisted or logged; logs redacted
GuardrailsWork-branch only, no --force, a destructive-command denylist, a path allowlist
Secret-leak scanThe diff is scanned for keys before any push; a .gitignore assertion keeps .env out
Hard budgetA per-run dollar cap that stops at the ceiling, cost streaming live
AuditEvery shell command, tool call, and git op logged immutably — who, which repo, what

An agent with a shell and your token is powerful and dangerous. You treat the token like plutonium. None of this shows well in a demo, and all of it is the reason I would point this at a codebase that pays salaries.

Why owning it wins

Self-hosting buys three things the hosted products structurally cannot:

  1. My code never leaves my machines. No third party holds the repo.
  2. The cost is a subscription, not a meter. Origin runs through my Claude Max plan. There is no per-task counter ticking up precisely when the tool proves useful.
  3. It works to my standards. My conventions, my PR checklist, my definition of done — because I wrote the harness. It reuses the same skills, budgets, and knowledge base my agents already share.

And because it lives in my own workspace, it composes: label an issue and a run spawns itself; comment on a PR and it fixes the thing. The autonomous engineer becomes part of the workflow instead of a separate portal I have to visit.

The takeaway for other tech leads

An autonomous engineer is not a product you are forced to rent. It is an orchestration pattern:

A capable agent SDK, running inside an isolated clone of your repo, wrapped in a deterministic git lifecycle and a plan-build-test-review-ship loop, with human gates and hard guardrails.

Buy the hosted version if the trade-offs suit you — it is a real product and it is good. But if you have private code, a fixed budget, and opinions about how your software gets written, know that the same capability is a weekend of orchestration on top of tools you already run. The leverage is enormous. The keys stay in your pocket.

That is the whole point.

Export for reading

Comments