Building an application with Claude Code and Codex in a week
A practical account of taking an idea from an empty repository to a tested, deployed, multi-client application—with two coding agents, a short feedback loop, and a bias toward reversible decisions.
A week is enough to build a surprisingly complete first version if “build” means more than making a screen look convincing. The useful finish line is a system that can store real data, survive bad input, support more than one client, be tested, and be operated by someone who did not write every line.
This article describes the process without relying on the application’s subject matter. The repository’s commits record what changed and when, but not which agent produced each change. The division of labor below is therefore a workflow pattern—not an attempt to assign individual commits retroactively.
Start with a thin vertical slice
The first evening established the shape of the system rather than chasing features. The sequence in the history was deliberate:
- create the frontend and backend toolchain;
- add a test runner, linting, and continuous integration;
- make a small local persistence prototype;
- replace that prototype with an authenticated API and isolated user data;
- connect the frontend to the API before broadening the feature set.
That produced a vertical slice early. It was not polished, but it answered the important questions: Can a user create data? Does it come back after a reload? Is it scoped to the right account? Can the behavior be tested without clicking through the browser?
Use two agents as a relay, not a lottery
Claude Code and Codex are most useful when they have different jobs in the loop. Asking both to “build the app” creates duplicated effort and conflicting assumptions. A better pattern is a relay:
- Frame the task. Describe the user outcome, constraints, acceptance criteria, and files that are in scope.
- Explore and propose. Have one agent inspect the repository, trace the relevant code paths, and identify the smallest coherent change.
- Implement in a bounded slice. Let the other agent make the change, including tests and documentation where the behavior warrants it.
- Review the diff. Ask for an adversarial pass: authorization, data ownership, failure modes, migrations, mobile behavior, and stale docs.
- Run the checks. Tests, lint, type checking, and a focused manual smoke test are part of the task—not a later cleanup phase.
The human remains the product manager and release engineer. Agents can propose a good implementation; they cannot decide what “good enough to ship” means without a clear boundary.
The week, reconstructed from the commits
Tooling, tests, CI, a local persistence experiment, then an authenticated API with tenant isolation. The prototype was useful because it clarified the data model; it was not treated as the final architecture.
The web client was wired to the server, then a native client was added against the same API. Shared contracts mattered more than shared UI code: both clients could evolve independently while reading the same source of truth.
Forms, editing, deletion, validation, account recovery, confirmation messaging, and a narrowly scoped sharing flow were added. Small fixes in the history—hidden fields, stuck saves, date-time behavior—show why device-level testing belongs in the first week.
The native client gained a local read-through cache and an outbox for writes. Idempotency was added at the API boundary so reconnecting would not duplicate a submission. Backups, retention, and failure alerts followed.
Limits, entitlements, notifications, data export, deletion, and admin controls were implemented as explicit server-side rules rather than UI-only behavior. This is where a demo starts becoming a product.
The hosting path was made repeatable, static assets were moved to edge hosting, deep links were fixed, health checks were made database-aware, and the API environment was moved to redundant infrastructure with rolling deployment procedures.
Architecture: one source of truth, several delivery surfaces
The system settled on a simple boundary: clients own presentation and local experience; the API owns authorization, validation, and business rules; the database owns durable state. Background jobs and object storage sit behind the API rather than becoming second application paths.
Decisions that paid for themselves
Prototype locally, then graduate
A local persistence layer provided momentum on day one. Moving to the API early prevented the prototype from becoming a hidden production dependency.
Keep clients additive
The native client used bearer authentication while the web client retained its cookie flow. That reduced migration risk and kept the shared API contract explicit.
Make writes idempotent
Offline retries are normal, not exceptional. A client-generated request identity turned a network problem into a safe retry instead of a duplicate record.
Prefer additive migrations
Rolling deployments mean old and new server versions can briefly coexist. Expand/contract database changes let that transition happen safely.
Hide protected routes
Unauthorized data routes returned a non-enumerating response. This reduced account and endpoint discovery without putting security logic in the clients.
Write the runbook while building
Deployment, backups, restore, incident response, and release steps were documented beside the code. Documentation became an operational test of whether the system was understandable.
What the agents did not replace
The most important work was judgment:
- choosing the first narrow workflow instead of implementing every idea;
- deciding what data must never cross an account boundary;
- rejecting infrastructure changes that could recreate a live database;
- testing on an actual device when browser behavior was not representative;
- checking that documentation matched the deployed system;
- stopping to simplify when a feature created more policy than value.
AI is excellent at turning a precise request into a lot of coherent code. It is much less reliable at noticing that the request itself is underspecified, that a “temporary” shortcut has become a dependency, or that a successful test is testing the wrong thing.
A repeatable working loop
For a new feature, the effective prompt was close to a small engineering ticket:
Outcome: a signed-in user can create and later retrieve one record.
In scope: API route, validation schema, migration, client form, tests.
Constraints: isolate by account; preserve existing auth; additive migration.
Acceptance: happy path, invalid input, anonymous request, wrong-account request,
retry after timeout, and a focused UI smoke test.
Before editing: inspect the current route, schema, tests, and deployment notes.
After editing: show the diff, run checks, and list any remaining assumptions.
That format gives both agents enough context to be useful and enough constraints to be reviewable. It also makes context switching cheap: the next session can start from the ticket, the diff, and the failing test rather than from a long conversational history.
The real speed multiplier
A week-long build with Claude Code and Codex is not a shortcut around software engineering. It is a way to spend more of the week on the parts that matter: boundaries, feedback, tradeoffs, and proof.
Start with a vertical slice. Keep the architecture plain. Give each agent a bounded role. Make every important behavior executable as a test or a runbook step. Ship the smallest system that can teach you what to build next.