March 20, 202610 min readai-cli-tools

Scaffold a Full-Stack App with 3 AI CLI Tools in Parallel

Coordinate three AI CLIs with Git worktrees and Termdock, from a shared spec to handoff, integration, and verification.

DH
Danny Huang

What You Will Build

This illustrative task-board project assigns a Node.js/Express backend, a React frontend, and PostgreSQL data and tests to Claude Code, Gemini CLI, and Codex CLI. Commit a shared spec first, then create three Git worktrees so each agent works on its own branch.

This is an adaptable tutorial, not a verified one-shot result or a time guarantee. Inspect the generated code, dependencies, integration steps, and test results. Use a new disposable test database, not production data.

Why Three Tools Instead of One

The point is clear ownership and handoff, not an assumption that a model is always best or the split always saves money. Substitute CLIs you can access, or practice with three sessions of the same tool. Check each tool's account, permissions, and costs separately.

Prerequisites

  • Claude Code, Gemini CLI, and Codex CLI: install and verify eligibility using the official Claude Code, Gemini CLI, and Codex CLI docs.
  • Gemini CLI access: Google's transition announcement says individual free and Google AI Pro/Ultra Gemini CLI requests stopped on June 18, 2026, while the authentication and quota docs still list personal accounts and free quotas. Official sources conflict. Verify your own access; do not assume 1,000 free daily requests.
  • Git 2.28 or later, plus Node.js and Docker as required by each tool's docs. Model usage, Docker, and packages may cost extra.
  • A new practice directory and a local test database verified to contain no production data.

Step 1: Create an Empty Project

This creates a new taskboard in your home directory. If the directory already exists, the first command stops; choose a new name rather than overwriting a project. Configure your Git author name and email first.

(
  set -e
  mkdir "$HOME/taskboard"
  cd "$HOME/taskboard"
  git init -b main
  printf 'node_modules/\n.env\n' > .gitignore
  git add .gitignore
  git commit -m "init"
)

Only if every command succeeds, run cd "$HOME/taskboard" before continuing.

Step 2: Write the Shared Spec

Before launching any agent, create a shared specification. Every agent must agree on the data model and API contract. Without this, you get three layers that do not fit together. Three walls meeting at different angles.

Create SPEC.md in the main branch:

# Taskboard — Shared Specification

## Data Model
- **User**: id (uuid), email (unique), name, created_at
- **Task**: id (uuid), title, description (nullable), status (enum: todo/in_progress/done), priority (enum: low/medium/high), assignee_id (fk → User), created_at, updated_at, deleted_at (nullable)

## API Endpoints
- GET    /api/tasks         — list all tasks, supports ?status= and ?assignee_id= filters
- POST   /api/tasks         — create task (title required, status defaults to "todo")
- PATCH  /api/tasks/:id     — update task fields
- DELETE /api/tasks/:id     — soft delete (set deleted_at)
- GET    /api/users         — list all users
- POST   /api/users         — create user

## Conventions
- Backend: Node.js + Express + TypeScript
- Frontend: React 19 + Vite + TypeScript + Tailwind CSS 4
- Database: PostgreSQL 16 with Drizzle ORM
- All API responses: { data: T } on success, { error: string } on failure
- Port: API on 4000, frontend on 3000, DB on 5432

Commit to main:

git add SPEC.md && git commit -m "add shared spec"

After committing the spec, create three new branches and worktrees from that commit so each contains SPEC.md:

git worktree add -b feature/api ../taskboard-api main
git worktree add -b feature/ui  ../taskboard-ui  main
git worktree add -b feature/db  ../taskboard-db  main

If a path or branch already exists, stop and inspect it; do not overwrite it. Worktrees separate working directories but do not guarantee conflict-free merges. Assign the API to backend/, the UI to frontend/, and database work to db/ and tests/.

Step 3: Launch All Three Agents

Open three terminal panels. If you are using Termdock, drag to create a three-panel layout -- one panel per agent. All three outputs visible at once. Resize to focus on whichever agent needs attention.

Panel 1: Claude Code -- Backend API

cd ~/taskboard-api
claude

> Read SPEC.md. Under backend/, scaffold an Express + TypeScript backend API
> implementing every endpoint in the spec. Include:
> - src/ directory with routes, controllers, middleware, types
> - Error handling middleware with proper HTTP status codes
> - Input validation using zod
> - CORS configured for localhost:3000
> - Docker-compatible: reads DATABASE_URL from env
> - package.json with scripts: dev, build, start
> Do not implement database queries yet — use placeholder functions
> that return mock data matching the schema in SPEC.md.
> We will integrate the real DB layer after merge.

Claude Code creates the project structure, installs dependencies, writes route handlers, adds validation schemas, sets up error handling. Multi-file architectural work -- exactly where its reasoning depth pays off.

Panel 2: Gemini CLI -- Frontend UI

cd ~/taskboard-ui
gemini

> Read SPEC.md. Under frontend/, scaffold a React 19 + Vite + TypeScript frontend for
> the task management app. Include:
> - Vite config with proxy to localhost:4000/api
> - Components: TaskBoard, TaskCard, TaskForm, UserSelect, StatusFilter
> - Tailwind CSS 4 for styling — clean, minimal design
> - API client module using fetch, typed to match the spec endpoints
> - State management with React 19 use() and context
> - package.json with scripts: dev, build, preview
> Focus on a working Kanban-style board with three columns:
> Todo, In Progress, Done. Tasks are draggable between columns.

Check whether generated components match the spec before iterating. Model, usage, and cost depend on your access path.

Panel 3: Codex CLI -- Database + Tests

cd ~/taskboard-db
codex

> Read SPEC.md. Create the database layer:
> - Drizzle ORM schema matching the data model exactly
> - Migration files generated from the schema
> - Seed script that creates 3 users and 10 sample tasks
> - docker-compose.yml for PostgreSQL 16
> - Connection config reading DATABASE_URL from .env
> - Tests for the DB schema and migrations using vitest.
> - Outline endpoint integration tests for after the API is merged.
>   Test CRUD operations, filters, and soft delete.
> Structure: db/ directory with schema.ts, migrate.ts, seed.ts,
> and a tests/ directory.

Codex CLI generates structured, predictable output. Schema definitions, migration files, test assertions -- template-driven tasks where it performs reliably.

Step 4: Monitor and Adjust

Three agents running. Your role shifts from writing code to reviewing output. Check each panel periodically.

Common issues to watch for:

  • Type mismatches -- if an agent invents a field name not in SPEC.md, correct it immediately. The shared spec exists to prevent this, but agents occasionally improvise.
  • Port conflicts -- verify each layer uses the ports defined in the spec.
  • Dependency version mismatches -- if both the API and DB layers install Drizzle ORM, ensure they pin the same version.

Wait for each session to report its actual result. Time and output depend on the project, models, permissions, and environment.

Collect the Handoffs Before Integration in Termdock

Ask each session for its worktree, branch, changed files, test results, and interfaces that need another session's cooperation. The coordinator compares the API and data types against the shared spec and lists inconsistencies before deciding integration order. With Termdock CLI/API handoff, explicitly send the spec and output locations; conversations do not share them automatically. Verify account eligibility and costs for each CLI first. Termdock does not include model subscriptions.

Step 5: Merge the Three Branches

After the agents finish, inspect git status, the diff, and test results in each worktree. Decide whether to commit each branch only after checking its scope. Return to the practice repository's main branch and merge only after each branch has its intended commits.

cd ~/taskboard

# Merge the database layer first — it has no dependencies on the others
git merge feature/db --no-ff -m "merge: database schema, migrations, seed, tests"

# Merge the backend API
git merge feature/api --no-ff -m "merge: Express API with routes and validation"

# Merge the frontend
git merge feature/ui --no-ff -m "merge: React frontend with Kanban board"

Separate directories reduce overlap but cannot guarantee conflict-free merges. Inspect each branch first and preserve existing data while resolving conflicts.

If conflicts occur: almost always in shared config files like package.json or tsconfig.json. Resolve manually -- combine dependencies from all three branches, keep the strictest TypeScript config.

Step 6: Integration Wiring

Three layers in one branch now. Not yet connected. The backend has mock data functions. The frontend calls localhost:4000. You need the real database wired into the backend.

This is a focused task for Claude Code:

claude

> The backend in backend/src/ uses placeholder functions for database queries.
> The database layer in db/ has the Drizzle schema and connection setup.
> Replace all placeholder functions with real Drizzle queries.
> Update the backend to import from db/schema.ts.
> Ensure the docker-compose.yml starts both the API and the database.
> Add a top-level package.json with a "dev" script that starts
> API + frontend concurrently.

Inspect the proposed integration, dependencies, and configuration, particularly the database target, before running appropriate tests.

Step 7: Run and Verify

Inspect the generated docker-compose.yml, .env, package.json, and migrations first. Confirm the services, database, ports, and scripts. Use only a disposable local test database; do not run migrations or seeds if the connection target is uncertain.

Start services using the commands actually produced, inspect API responses, frontend interactions, and database changes, and run the project's unit and integration tests. Record the actual commands, output, and failures; generated test files do not mean tests passed.

Workflow Summary

Commit the spec, create worktrees, assign ownership, and hand off each branch's diff and test results. Inspect, integrate, and verify. Time and cost depend on tools, task, and environment; this article has no verifiable parallel-speed comparison.

Adapting This to Your Own Projects

The three-tool split generalizes to any full-stack architecture. Same principle: assign each tool to the layer matching its strength.

Different tech stacks: Replace Express with FastAPI, React with Svelte, PostgreSQL with MongoDB. The worktree structure and parallel workflow remain identical.

More layers: Add a fourth worktree for infrastructure (Terraform, CI/CD). Assign it to whichever agent handles template-driven config files best.

Fewer tools: If you only have Claude Code and Gemini CLI, assign the database layer to whichever agent finishes its primary task first. The dual-tool strategy covers this two-agent approach in detail.

A shared spec helps. Document the data model and interfaces, then verify each branch against them. It does not guarantee problem-free integration.

Troubleshooting

Gemini CLI hits an access or usage limit. Check the authentication path and current provider usage for your account, then decide whether to wait, finish manually, or switch to another authorized tool. Do not apply the old free quota.

Codex CLI sandbox blocks network access. Codex runs in a sandboxed environment by default. If it needs to install npm packages, ensure your Codex configuration allows network access during setup, or pre-install dependencies before launching the agent.

Merge conflicts in package.json. The most common issue. Both the API and DB layers may create their own package.json. Structure the project as a monorepo from the start -- each layer gets its own directory with its own package.json, plus a root-level package.json for shared scripts.

Agent ignores SPEC.md. Some agents prioritize their own conventions over the spec. If an agent generates status as a string instead of the specified enum, correct it: "Use the exact field types from SPEC.md. Status must be an enum: todo, in_progress, done."

Three agents. Three terminal panels. All outputs visible simultaneously. Resize to focus on the one that needs attention. Recover sessions if a terminal crashes. That is the difference between orchestrating agents effectively and constantly losing your place.

DH
#claude-code#gemini-cli#codex-cli#scaffold#fullstack#parallel-development#ai-cli

Related Posts