KoderKoder.ai
PricingEnterpriseEducationFor investors
Log inGet started

Product

PricingEnterpriseFor investors

Resources

Contact usSupportEducationBlog

Legal

Privacy PolicyTerms of UseSecurityAcceptable Use PolicyReport Abuse

Social

LinkedInTwitter
Koder.ai
Language

© 2026 Koder.ai. All rights reserved.

Home›Blog›Claude Code greenfield workflow: from empty repo to first slice
Dec 12, 2025·7 min

Claude Code greenfield workflow: from empty repo to first slice

Use a Claude Code greenfield workflow to set up structure, scripts, and a first vertical slice you can run, test, and improve week by week.

Claude Code greenfield workflow: from empty repo to first slice

What you are trying to avoid with a greenfield start

Starting from an empty repo feels like freedom, but it often turns into messy momentum: lots of generated files, a half-working build, and no clear place to put the next change. The point of a Claude Code greenfield workflow is to avoid that first-week chaos.

A few failures show up over and over:

  • Code that “works on my machine” because setup lives in someone’s memory, not in scripts.
  • A folder tree that reflects the order things were created, not how the app should grow.
  • A loop where each new prompt rewrites previous choices, so nothing becomes stable.

Early decisions are painful to undo because everything stacks on top of them. A confusing structure keeps getting reinforced. A manual build turns into ten different setups. If you don’t lock in a simple dev command early, you can’t tell whether a change broke the app or just broke the environment.

When this post says “running app,” it means something specific: one command that starts the project, prints predictable output, and fails loudly when something is missing. You should be able to delete your local install, clone the repo, run that command, and see the same result.

A “vertical slice” is the smallest end-to-end feature that proves your app is real. Not a UI mock. Not a database table by itself. It’s one thin line through the whole system, like a page with a form, one API endpoint that saves data, one database write and read, and one visible result back on the page.

If you can run the app with one command and ship one vertical slice, you have a base you can iterate on without guessing.

Decide the first slice before you generate anything

A clear first slice keeps your repo tidy and your prompts focused. This is the moment to decide what you want to demo end to end, not what you hope the full product becomes.

Pick the smallest user story that proves the app works across the whole path. A good slice touches UI, data, and one real action. Example: “As a user, I can add a task and see it appear in a list after refresh.” It’s tiny, but it forces routing, validation, storage, and a basic screen.

Choose one target platform for week 1 and stick to it. If you start web, do web only. Don’t add mobile screens “just in case.” Even if you plan to use a platform like Koder.ai later, you’ll get better results if the first slice stays in one lane (React web, or a Go API, or Flutter).

Define what “done for week 1” means in plain terms:

  • Runs locally from a fresh clone with one command
  • One working feature you can click through end to end
  • Errors show a human message (not a stack trace)
  • Data persists somewhere simple (even a local database)

Then write down three non-goals that protect the scope. For example: no auth, no theme system, no background jobs.

Once those decisions are written down, your generation prompt can be strict: build only what supports the slice, and leave everything else as a TODO.

A few upfront decisions that save rework

Before you ask Claude to generate anything, lock in a handful of defaults. They seem small, but they prevent the “rename everything later” mess.

First, decide the app’s shape. If you truly need a browser UI and a backend, start with two clear parts (frontend + API) and a shared place for contracts (API types or a simple schema). If the app can be a single server-rendered web app, keep it one codebase so local dev stays simple.

Next, agree on configuration rules. Use a local env file, keep it out of git, and commit a template instead (for example, .env.example) with safe placeholders and short comments. This makes onboarding easier and reduces secret leaks.

Pick default dev ports and keep them stable. Ports end up in scripts, docs, and error messages, so changing them later is annoying. Do the same for naming: folders, services, and packages should follow one convention. Consistency matters more than the “perfect” convention.

A simple starting set of decisions:

  • App shape: single app or frontend + API
  • Config: .env locally, .env.example committed
  • Ports: one for web, one for API, one for DB (if needed)
  • Names: one casing style for folders, consistent service names
  • Secrets: never committed, rotated if exposed

Example: you pick web on port 3000 and api on port 8080. Your env template includes API_URL=http://localhost:8080 and DATABASE_URL=.... When Claude generates scripts and docs later, everything snaps into place instead of drifting.

How to prompt Claude Code so it stays structured

Start by asking for a runnable scaffold, not “the whole app.” The quickest path to messy output is requesting features before you have a place to put them.

Be explicit about structure. Ask for a folder layout with short comments that explain what belongs where, and what does not. That forces decisions up front instead of scattering files as it goes.

A simple way to keep it disciplined is to set rules in the prompt:

  • Generate the smallest runnable skeleton first (hello page, health endpoint, or one screen).
  • Propose a folder structure and explain each folder in 1 sentence.
  • Add scripts that work on a fresh machine (install, dev, test, build) and state prerequisites.
  • Keep changes in one PR-sized chunk and list exactly which files will be created or edited.
  • Stop after scaffolding and tell me how to run it.

Here is a prompt you can reuse and tweak:

You are working in an empty repo. Create a minimal runnable skeleton.

Constraints:
- Keep it small: no real features yet.
- Propose a clear folder structure and add brief comments in each folder’s README.
- Add scripts for: setup, dev, test, build. They must work on a fresh machine.
- Tell me exactly how to run it, and what output I should see.
- After generating, stop and wait for my “ran it” confirmation.

Output:
1) File tree
2) Key files (only)
3) Run instructions

Then keep the loop tight. Don’t ask for five changes at once. Generate one small change, run it, paste the exact error (or success), then ask for a minimal fix. That generate-run-adjust rhythm keeps the project predictable and makes it harder for the structure to drift.

Step-by-step: empty repo to a runnable skeleton

Start with one promise: anyone can clone the repo and run one command to see something working. That gives you a stable base before you ask an AI to add real features.

Create the repo and write a tiny README while everything is fresh. Keep it practical: prerequisites, the one dev command, and how to run tests (even if tests are empty for now).

Next, pick a top-level layout that matches the app shape you chose.

If you’re building multiple deployable pieces (for example, frontend + API), a workspace layout can help:

/
  apps/
  packages/
  scripts/
  docs/
  README.md

If you’re building a single app, keep it simpler and avoid extra levels until you need them.

Now add the minimum guardrails so the code stays consistent. Pick one formatter and one linter, accept their defaults, and add a single config file for each. The goal is clean diffs, not perfect rules on day one.

Make developer experience predictable with one command that always works from the repo root. Here’s a simple shape:

{
  "scripts": {
    "dev": "echo \"start dev server here\"",
    "build": "echo \"build here\"",
    "test": "echo \"tests here\"",
    "lint": "echo \"lint here\""
  }
}

Before you generate anything else, run that dev command, confirm it exits cleanly (or boots a placeholder server), then make your first commit with only scaffolding. If a teammate (or future you) can reproduce the setup from scratch, you’re ready to build the first slice.

A folder structure you can keep as the app grows

Validate a mobile slice
Create a Flutter slice that proves the end-to-end path before adding more screens.
Build Mobile

A good greenfield structure does two things: it helps you find code quickly, and it gives Claude less room to invent new patterns every time you ask for a change. The goal isn’t perfection. It’s stability.

If you’re working inside a single app (or inside an apps/<name>/ folder), a simple internal layout usually holds up well:

  • src/ app code (features, shared pieces, entry points)
  • config/ non-secret configuration
  • tests/ higher-level tests that read like user behavior
  • scripts/ helper scripts (dev setup, db reset, release tasks)
  • docs/ short notes and checklists you actually maintain

Inside src/, separate feature code from shared code based on change patterns. Feature code changes often and should live close together. Shared code should be boring and reusable.

A practical rule: put UI screens, handlers, and feature-specific logic under src/features/<featureName>/.... Put things like logging, API clients, design system components, and generic utilities under src/shared/.... If a helper only makes sense for one feature, keep it in that feature even if it looks reusable. Move it later when you have a second real use.

Folder names should describe purpose, not tech. “features” and “shared” stay meaningful as your stack changes. Avoid names like “misc” or “new.”

Keep docs/ small. A good starter is a docs/checklists.md with a few lines: how to run, how to test, how to add a new feature folder, and what “done” means.

Build scripts that make the project predictable

A repo feels real when anyone can run the same commands and get the same result. Scripts are guardrails: they reduce guesswork, keep changes small, and make it obvious when something broke.

Start with a small set of commands and keep them boring. If someone new joins (or you come back in two weeks), they shouldn’t need special flags or hidden steps.

Here’s a simple baseline you can adapt to any stack:

{
  "scripts": {
    "dev": "node ./scripts/dev.js",
    "build": "node ./scripts/build.js",
    "test": "node ./scripts/test.js",
    "test:quick": "node ./scripts/test.js --quick",
    "test:full": "node ./scripts/test.js --full",
    "format": "node ./scripts/format.js",
    "lint": "node ./scripts/lint.js",
    "smoke": "node ./scripts/smoke.js"
  }
}

Make the dev script the happy path. It should start the app, print where it’s running, and keep logs readable. If the server can’t start, fail fast with one clear message (missing env var, port already used, database not reachable).

The build script should always create a clean output directory. Delete the old output first, then produce fresh artifacts. That avoids strange bugs caused by yesterday’s files.

For tests, split quick checks from slow checks. Quick tests run on every change (unit tests, type checks). Full tests include integration checks and run before merge.

Keep style consistent with one command. A simple rule is: format fixes things, lint complains about things.

Finally, add a smoke check that validates the basics before you waste time debugging:

  • Required env vars are set (and not empty)
  • Chosen ports are free
  • App can start and respond to one simple request
  • Database connection works (if used)
  • Build output exists after build

Build the first vertical slice feature

Build your first slice fast
Turn your first vertical slice into a working app by building through chat.
Start Free

Your first vertical slice should prove the app works end to end, not just that the UI looks nice. That means one small feature that touches the screen, the logic, and some kind of storage, even if the storage is temporary.

Pick something boring and useful, like “Add a note” or “Create a task.” Keep it small enough to finish in one sitting, but complete enough that you can click around and see real state change.

A good slice has four parts: one route or screen, one form, one save action, and one display. Example: a “New Task” page with a title input, a Save button that calls a single function, and a list that shows saved tasks.

Start with a placeholder store so you can move fast. An in-memory array, a local JSON file, or a simple stub interface is fine. The key is to create the boundary you’ll later replace. If your code calls taskRepository.save(task) today, swapping to a real database later becomes a small change, not a rewrite.

Keep the UI plain. Skip design system debates, empty states, and animations.

Acceptance checks you can do in two minutes:

  • Page opens without errors
  • You can type a value and press Save
  • The new item appears immediately
  • Reload shows the expected behavior (persisted if real storage, reset if fake)
  • Bad input is handled (empty title shows a message and does not save)

Make it stable enough to iterate on

After you have a runnable skeleton and one vertical slice, the goal shifts: make breakage obvious, and fixes quick. This is where many greenfield starts fall apart, not because the feature is hard, but because small changes start causing surprises.

Set a tiny stability bar you meet every time you add a slice:

  • One smoke test that proves the app boots and the main route/screen renders
  • One smoke test that hits the slice end-to-end (even if it uses a test database)
  • Clear error messages a normal user can act on (not stack traces)
  • Dev logs that explain what happened without printing secrets
  • Minimal dependencies, versions pinned, upgrades done on purpose

Concrete example: your first slice lets a user create a “Project” and see it in a list. Add a test that starts the server, calls the create endpoint, then fetches the list and checks the new item appears. If it fails, it should fail loudly with one helpful message, like “Create Project endpoint returned 500,” not a wall of output.

For error handling, stick to a small set of consistent responses. Validation errors return a short message (“Name is required”) and a field name. Unexpected errors return “Something went wrong. Try again.” Save details for logs.

Logging is most useful when it answers: what request, what user (or anonymous), what failed, and where. In dev, include a request id and timing, but avoid dumping tokens, passwords, API keys, or full payloads by default.

Add a tiny health check. On web, it can be a /health endpoint that returns ok. On mobile, it can be a “Connected” state that flips to “Offline” when the app can’t reach the backend. It’s a fast signal before you debug the wrong thing.

Common traps when using AI for greenfield projects

The fastest way to waste a greenfield start is to ask the model for a whole app, then only run it later. Big generations hide small mistakes: missing dependencies, wrong import paths, scripts that assume tools you don’t have. Treat every output as something you should be able to run within minutes.

Another trap is designing the perfect architecture before there is a feature. Debating folder names feels productive, but without a real slice you can’t tell what’s awkward. A simple structure that supports one working path beats a clever one you haven’t tested.

Command drift is also common. The AI adds a new way to start the server, you add another for tests, and soon nobody knows which is “the” command. If a teammate clones the repo and asks “How do I run this?”, you’re already paying interest.

Mistakes that cause the most rework:

  • Generating multiple services, screens, and configs in one go instead of building one runnable path first
  • Pulling in auth, payments, complex styling, and a full data model before the first feature works end-to-end
  • Letting setup instructions live in chat instead of scripts (or a single README)
  • Forgetting a clean env template, so the next machine can’t start without guesswork

A simple example: you generate a “complete” app with login, theming, and billing, but the first run fails because a secret key is missing and there is no .env.example. You then spend an hour fixing setup instead of learning whether the feature is useful.

Keep it honest: one runnable command, one small feature, one env template, then expand.

Quick checklist before you start iterating

Start with a backend slice
Stand up a Go API with predictable scripts and clear error messages.
Build API

Before you add “one more feature,” make sure the project is easy to pick up tomorrow (or by someone else). Speed isn’t the goal by itself. Predictability is.

  • One-command run: a new dev can copy an env template, set the few required values, and start the app with a single command. If it needs extra steps (DB setup, migrations, seed data), capture them in a script.
  • Scripts cover the basics: clear commands for dev, test, build, and a fast smoke check.
  • Obvious structure: the layout tells a story (app code, config, scripts, tests) without reading the whole codebase.
  • Vertical slice demo path: you can describe the demo in one sentence, like “create an item, see it in a list, refresh, it is still there.”
  • Rollback point: before big changes, you have a safe point to return to (a clean commit, a tag, or a snapshot/rollback mechanism).

If any item fails, fix it now. Tightening scripts and naming is cheap when the repo is small.

Next steps: turn the workflow into a repeatable habit

A greenfield start only pays off if you can repeat it. After your first vertical slice runs end to end, freeze the good parts into a small template: the same folder patterns, the same script names, and the same way you wire UI, API, and data together.

Treat your first slice like a reference implementation. When you start slice #2, copy the shape, not the code. If slice #1 has a route, a handler, a data access layer, and a basic test, slice #2 should follow the same path.

Keep planning lightweight. A one-page note is enough for the next 2-3 slices: the goal and user action for each slice (one sentence), the data you need, the “done” checks, and any risks you should test early.

Then make maintenance a habit. Once a week, do a short cleanup pass: tighten scripts, update the README with any new setup steps, and refresh your env example file so onboarding stays easy.

If you prefer a chat-first build loop, Koder.ai (koder.ai) is one option that supports planning mode plus snapshots and rollback, and it can export source code when you want to take the project elsewhere.

The goal is a workflow you can run without thinking: plan 2-3 slices, build one slice, stabilize, repeat. "}

Contents
What you are trying to avoid with a greenfield startDecide the first slice before you generate anythingA few upfront decisions that save reworkHow to prompt Claude Code so it stays structuredStep-by-step: empty repo to a runnable skeletonA folder structure you can keep as the app growsBuild scripts that make the project predictableBuild the first vertical slice featureMake it stable enough to iterate onCommon traps when using AI for greenfield projectsQuick checklist before you start iteratingNext steps: turn the workflow into a repeatable habit
Share