DEV Community

Beni
Beni

Posted on

We Built an Autonomous Dev Agent in 16 Hours

At 6:13 AM UTC on March 17th, the first commit landed. By 10:29 PM the same day, we had a fully operational autonomous development agent — designed, built, debugged, and deployed in a single sitting.

The project is called MissionControl. It's a Telegram bot that takes coding tasks in plain English, spawns a Claude Code CLI session to do the work, creates a pull request on GitHub, and reports back — all without human intervention.

What It Does

You send a message to the bot on Telegram:

"Add rate limiting to the /api/trades endpoint using a sliding window counter in Redis"

MissionControl takes it from there. It creates a feature branch, spawns a Claude Code session with the full project context, streams progress updates back to Telegram in real time, and when the work is done, opens a PR on GitHub. You get a link, review the diff, and merge.

The Architecture

We went with a ports and adapters pattern from the start — not because we needed it on day one, but because we wanted the system to be portable. The core business logic knows nothing about Telegram, GitHub, or Claude. It talks to abstract ports:

  • MessagingPort — could be Telegram, Slack, Discord
  • VCSPort — could be GitHub, GitLab, Bitbucket
  • WorkerPort — could be Claude CLI, Codex, any LLM agent
  • StoragePort — could be SQLite, Postgres, DynamoDB

The adapters are thin wrappers. Swapping Telegram for Slack means writing one adapter file, not rewriting the system. The entire codebase is 2,597 lines of TypeScript across 24 files.

The Timeline

06:13    Initial build — full ports/adapters architecture, all core systems
07:35    Bot upgrade — streaming progress, cancel/retry/logs commands
09:22    Replaced two-phase spawn with single lead dev CLI session
10:15    Fixed CLI argument passing for tool allow/deny lists
16:09    Fixed zero-stdout hang (HOME env var bug)
19:14–20:34    Eight reliability bug fixes in rapid succession
20:50    Switched default model to Opus, bumped resource limits
22:29    Final merge — reliability fixes, feature complete
Enter fullscreen mode Exit fullscreen mode

The Hard Parts

The architecture took an hour. The bugs took all afternoon.

The nastiest was a zero-stdout hang: the CLI would spawn, do its work, but produce no output. The root cause turned out to be the HOME environment variable pointing to the wrong directory for the unprivileged user running the CLI. The process would silently fail to read its config and hang. One line fix, four hours to find.

Git permissions were another saga — the bot creates branches and commits as a sandboxed user, but the repos are owned by root. We ended up auto-chowning .git/ on project registration and running all git operations as the bot user.

The Stack

  • Runtime: Node.js + TypeScript (strict mode)
  • Telegram: Grammy framework
  • Database: SQLite via better-sqlite3
  • AI: Claude Code CLI (spawned as subprocess)
  • VCS: GitHub REST API
  • Process: PM2
  • Validation: Zod schemas everywhere

What's Next

After the initial build — multi-project support is already in the schema. The ports and adapters pattern means adding a Slack adapter or a GitLab adapter is a weekend project, not a rewrite. And because the core logic is model-agnostic, swapping in a different AI worker is just another adapter.

Sixteen hours from empty directory to working product. Not bad for a one-man team and his AI co-pilot.

15 commits. 2,597 lines. 1 day.

Top comments (0)