How I Set Up an Autonomous Development System with AI Agents

A
Antonio Leiva
10 min read

I’ve spent the last few days experimenting with something that’s been intriguing me: letting AI develop a software project almost completely autonomously.

I’m not talking about asking it to generate a function or a component for you—I mean a system of agents that scan the code, detect problems, create issues, prioritize them, implement them, push the changes, and close the issues. All without human intervention.

The project is Learnfolx (final name TBD 😄), a B2B training platform I’m building (Next.js + PostgreSQL + Prisma + Redis). And the AI is working tirelessly: 80 issues created and ~50 closed in 3 days. Without me touching a single line of code.

Here’s how I set it up, and I’ll share all the prompts so you can replicate it:

The Architecture: scanners + triage + executor

The system has 3 layers:

  1. Scanners — Specialized agents that analyze the code looking for a specific type of problem. Each one creates issues in GitHub with what it finds.
  2. Triage — A daily cron job that automatically prioritizes new issues (p1/p2/p3).
  3. Executor — An agent that, every hour, picks the highest-priority issue, implements it, runs the checks, and closes it.

And there’s a fourth layer that acts as a safety net:

  1. Smoke tests — Every 4 hours, it checks that the project compiles, passes tests, and has no regressions.

Everything runs as automations in Codex App + an external cron for triage (though this could also be in Codex).

Don’t let this put you off if you don’t use Codex: any process that runs cron tasks would do the same.


The scanners: 6 specialists

Here’s how we organized it. This was pretty interesting, because setting this up manually would have been tedious. Instead, I asked my Telegram chatbot (a kind of simple OpenClaw) that I wanted to do this.

Between the two of us, we defined the scanners, and automatically, by reviewing the Codex config in ~/.codex, it was able to figure out how autos are configured and do it on its own.

1. Security Scanner (daily, 9:00)

The security scanner combines deterministic tools with LLM review. It runs Semgrep and npm audit first, then does a manual review looking for what the tools might miss.

You are a security scanner. Your ONLY job is to detect problems
and create issues in GitHub. DO NOT implement anything.

## Step 1: Semgrep (static analysis)
Run semgrep with automatic rules:
  semgrep --config auto --json --quiet .
Analyze the JSON results. Group by severity and vulnerability type.

## Step 2: npm audit
Run pnpm audit --json to detect vulnerable dependencies.

## Step 3: Complementary manual review
Analyze the project looking for things semgrep doesn't cover well:
- Secrets or API keys hardcoded in the code
- Endpoints without proper authentication/authorization
- Sensitive environment variables exposed
- Insecure configurations (CORS, headers, etc.)
- Incorrect authorization logic (e.g., tenant isolation bypass)

Real result: It detected hardcoded credentials in the seed script (it was just for development, but still), a CVE in the qs dependency, and a CORS exposure in the esbuild dev server.

2. Architecture Scanner (daily, 13:00)

Uses madge to detect circular dependencies and knip for dead code, plus LLM review for files that are too large or functions that are too long.

## Step 1: Circular dependencies (madge)
Run:
  npx madge --circular --extensions ts,tsx apps/web/src/

## Step 2: Dead code (knip)
Run:
  npx knip --no-progress

## Step 3: Complementary manual review
- Duplicated code between files
- Files that are too large (>300 lines)
- Functions that are too long (>50 lines)
- Inconsistent patterns
- Components with too many responsibilities
- Pending TODOs and FIXMEs

Real result: Found 19 technical debt issues, from services with 600+ lines to duplicated CSS in 8 admin modules.

3. Test Scanner (daily, 11:00)

Runs vitest --coverage and analyzes real coverage, prioritizing critical modules.

## Step 1: Real coverage (vitest)
Run:
  pnpm vitest run --coverage --reporter=json
Analyze which files have low (<50%) or zero coverage.
Prioritize files in src/lib/services/, src/app/api/, and src/lib/auth/.

## Step 2: Failing tests
## Step 3: Complementary manual review
- Critical functions without tests (auth, payments, data access, tenant isolation)
- Flaky tests or tests with external dependencies not mocked
- API endpoints without integration tests

4. Performance Scanner (daily, 15:00)

Looks for N+1 queries, components without memoization, large bundles, and redundant API calls.

You are a performance scanner. Your ONLY job is to detect performance
problems and create issues in GitHub. DO NOT implement anything.

Analyze the project looking for:
- N+1 queries in Prisma or inefficient DB access
- React components that should be memoized but aren't
- JavaScript bundles that are too large
- Images not optimized or missing lazy loading
- Unnecessary renders
- Missing cache in endpoints that need it
- Redundant or cascading API calls

Real result: Detected 4 performance issues, including N+1 queries in the analytics dashboard and individual lookups per row in CSV import.

5. DX Scanner (daily, 17:00)

Combines static analysis tools with manual review to detect developer experience friction.

## Step 1: Dead code and unused dependencies (knip)
Run:
  npx knip --no-progress

## Step 2: Type checking
Run:
  pnpm tsc --noEmit
Check for type errors that don't show up in the IDE but break the build.

## Step 3: Outdated dependencies
Run:
  pnpm -r outdated

## Step 4: Complementary manual review
- Unresolved linting errors
- package.json scripts that are missing or broken
- Outdated or missing documentation
- Incomplete .gitignore

Real result: Detected that tsc wasn’t accessible as a command, knip wasn’t loading the config, and several dependencies had pending major versions (Prisma 7, Vitest 4, Zod 4).

6. Feature Scanner (daily, 14:00)

This one’s the most interesting. It reads the project specs (business rules, milestone capabilities, entities) and compares them to the current code to detect functionality that should exist but isn’t implemented.

You are a feature scanner. Your ONLY job is to detect
improvements and new features and create issues in GitHub. DO NOT implement anything.

Process:
1. Read the specs: docs/domain/business-rules.md,
   docs/domain/milestone-capabilities.md,
   docs/domain/entities-and-invariants.md
2. Read docs/architecture/overview.md and docs/design/navigation-map.md
3. Review the current code and compare it to the specs

Look for:
- Functionality specified in docs that's not implemented or incomplete
- User flows missing validations, feedback, or error states
- Partially implemented features
- Obvious UX improvement opportunities
- Data that's collected but not displayed
- Edge cases not covered in critical flows

Real result: Detected that student assessments had no submission flow, student progress wasn’t shown in the UI, and FUNDAE exports were just mocks.


The throttle: so things don’t get out of hand

An important lesson: on the first day, the scanners created 26 issues because they were doing the initial sweep of the whole repo. To keep the queue under control, each scanner has a throttle:

Before creating issues, count how many open issues there are with
label [type]. If there are 10 or more, DO NOT create new issues and stop.

Exception: critical security vulnerabilities are always created, regardless of the throttle.


Automatic triage

A daily cron at 10:00 reviews all issues without a priority and classifies them automatically:

  • p1: active vulnerabilities (CVE), missing core functionality, blocking bugs
  • p2: performance improvements, useful features, tests for critical modules
  • p3: refactors, minor improvements, low-frequency optimizations

The key is that it directly assigns the labels, not just recommends them. I only override if I disagree with a priority.

It also generates a daily summary with issues created, closed, commits, and smoke test status.


The executor: the one that does the work

This is the heart of the system. It runs every hour and picks the highest-priority issue to implement.

Selection process (priority > type > age):
1. Look for p1 issues. If any, select by type order.
2. If no p1, look for p2. If any, select by type order.
3. If no p2, look for p3.
4. If there are no issues with priority, do nothing.

Type order within the same priority level:
1. security (vulnerabilities first)
2. bug (functional errors)
3. feature (new or incomplete functionality)
4. performance (optimization)
5. tests (coverage)
6. architecture (refactors)
7. dx (developer experience)

Important detail: features come before refactors at the same priority level. I don’t want the agent spending all day splitting files when there’s real functionality pending.

The executor works directly on main (no PRs), runs lint + typecheck + tests before each commit, and closes the issue automatically with a reference to the commit.


The safety net: smoke tests

Every 4 hours, an independent agent checks that everything still works:

  1. pnpm build
  2. pnpm typecheck
  3. pnpm test
  4. pnpm lint
  5. Checks that recent commits properly closed their issues

If something fails, it creates an issue with label bug, p1 — and the executor picks it up in the next iteration. Regressions are always top priority.

It logs each run in docs/smoke-log.md for traceability.

Real result: On the first day, the smoke test detected 7 regressions in a row. The executor fixed them automatically one after another.


The numbers

In 3 days of operation:

  • ~80 issues created by the scanners
  • ~50 issues closed by the executor
  • ~60 automatic commits
  • 0 lines of code written by me
  • The 5 p1 security issues were closed the same day
  • Core features implemented: student assessments, progress in UI, real FUNDAE exports, Zoom attendance sync

What I’ve learned

What works well:

  • The scanner/executor separation is key. The one that detects problems should NOT be the one that fixes them. It avoids bias.
  • Deterministic tools (Semgrep, knip, madge, vitest coverage) complement the LLM really well. The LLM catches things the tools miss, and the tools have zero false negatives for their patterns.
  • The throttle is essential. Without it, the scanners overwhelm the executor with issues faster than it can process them.
  • The smoke test as a safety net works: it caught 7 regressions the executor introduced by making concurrent changes.

What to watch out for:

  • Core features (new functionality with business logic) need human review. The agent might implement a requirement incorrectly and you won’t notice unless you check.
  • p3 refactors pile up. The executor always prioritizes features and bugs, so “minor” technical debt grows. You need to do periodic purges or dedicate a day just to p3.
  • The quality of generated tests is questionable. They cover code but sometimes the assertions are weak. Mutation testing (Stryker) would be the next step to verify that the tests actually validate something.

Speed: it’s not magic, it’s your tokens

I’ve been running this for 5 days, and a lot of you ask how the tokens hold up. The reality is that with a $20 Codex account you can’t keep up this pace.

In the end, you have to decide: speed vs price, and find a balance.

Right now I’m managing with 2 $20 ChatGPT (Codex) accounts, and I still think they’ll fall short. This is considering that Codex App tokens are currently doubled.

So if you want to take this seriously and go at a good speed, the $200 account seems pretty necessary.

Is this the future?

Spotify just published that their best developers haven’t written code since December thanks to tools like Claude Code and their internal system Honk. My experiment is much more modest, but it’s pointing in the same direction: the developer’s role shifts from writing code to orchestrating agents.

I don’t think we’re ready to leave this running unsupervised on critical projects. But for a side project or an early product phase, the speed is absurd. 3 days of autonomous work equals what would have taken me weeks to do manually.

If you want to replicate it, the prompts are exactly what I’ve shared here. If you try it, let me know how it goes.

Expert resources for solving real-world problems

View all