An autonomous software engineering agent that plans, codes, tests, and ships pull requests. Claude-powered reasoning, GitHub-native workflows, and a polished developer experience — deployable on the Vercel free tier.
Quick Start · Architecture · Deployment · Tradeoffs · Deep Dive
Most "AI coding agent" demos either (a) only run in a notebook with hardcoded prompts, or (b) require a Kubernetes cluster and a Stripe plan before they'll say hello. Forge is the middle path: a production-quality Next.js app that demonstrates the full Devin-style workflow — task intake, planning, step-by-step execution with live terminal output, file diffs, and a pull request — while being honest about what can and cannot run on Vercel's free tier.
The result is a project that's equally useful as:
- A portfolio piece — recruiters and clients can clone, deploy, and click through it in 60 seconds.
- An architecture reference — clean typed modules for the planner, executor, runtime, tools, and integrations.
- A starting point — fork it, wire in real execution, ship your own Devin.
Describe a task in plain English. Forge:
- Plans — decomposes the task into 5–9 ordered steps with explicit tool calls, assumptions, and risks.
- Executes — walks the plan step by step, streaming terminal output, file diffs, and structured logs in real time.
- Tests — runs lint, typecheck, and the test suite as part of the flow.
- Ships — commits with a conventional message and opens a pull request with a summary.
Every stage is observable in a polished UI. You can cancel mid-run, inspect any past task, and switch models without losing context.
Place screenshots in
docs/screenshots/and they'll render here.
| Landing | Dashboard | Execution |
|---|---|---|
| Hero, features, architecture, workflow | Stats, activity chart, recent tasks | Plan timeline, terminal, diffs, logs |
docs/screenshots/
├── landing.png
├── dashboard.png
├── execution.png
├── new-task.png
└── github.png
┌──────────────────────────────────────────────────────────────────┐
│ Browser (single page) │
│ Landing ←→ App Shell (sidebar + topbar + view router) │
│ │ │ │
│ │ ├─ Dashboard ├─ New Task │
│ │ ├─ Execution ├─ History │
│ │ ├─ GitHub └─ Settings │
│ ▼ ▼ │
│ Zustand stores (app · agent · task · settings) │
│ │ │ │
│ │ └─ agent-store drives the simulated execution │
│ ▼ loop (plan → stream → diff → commit) │
└──────┼─────────────────┼──────────────────────────────────────────┘
│ │
▼ ▼
┌──────────────┐ ┌──────────────────────────────────────────────┐
│ /api/* │ │ /lib/* (typed service layer) │
│ │ │ │
│ /agent/plan │◄─┤ agent/ planner · executor · tools · runtime│
│ /agent/runtime│ │ llm/ claude · zai · provider factory │
│ /llm/models │ │ github/ REST v3 client │
│ /github/* │ │ demo/ scenario library + seed data │
│ /health │ │ types/ shared domain types │
└──────────────┘ └──────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────┐
│ External services (optional, env-driven) │
│ Anthropic API · GitHub REST API · SQLite │
└──────────────────────────────────────────────┘
| Layer | Path | Responsibility |
|---|---|---|
| UI | src/components/ |
Landing page + app shell + views. Pure presentation; reads from stores. |
| State | src/store/ |
Zustand stores for app nav, agent execution, task history, settings. |
| API | src/app/api/ |
Thin route handlers — proxy to the service layer. |
| Services | src/lib/ |
Typed business logic: agent, llm, github, demo. No React, no Next. |
| Types | src/types/ |
Shared domain contracts between every layer. |
| Persistence | prisma/ |
SQLite schema for tasks, steps, logs, file changes. |
See
docs/ARCHITECTURE.mdfor the full deep-dive.
| Concern | Choice | Why |
|---|---|---|
| Framework | Next.js 16 (App Router) | Server components, route handlers, server actions, Vercel-native. |
| Language | TypeScript 5 (strict) | End-to-end type safety across UI → API → services. |
| Styling | Tailwind CSS 4 + shadcn/ui | Design tokens, consistent components, dark-mode-first. |
| State | Zustand (+ persist) | Lightweight, no boilerplate, survives HMR. |
| Data fetching | TanStack Query | Available for server-state; not required for the demo. |
| Animation | Framer Motion | Tasteful entrance / hover / page transitions. |
| Icons | lucide-react | Tree-shakeable, consistent stroke. |
| Charts | Recharts | Activity sparkline on the dashboard. |
| Database | Prisma + SQLite | Zero-config persistence; portable to Postgres later. |
| LLM (primary) | Anthropic Claude | Sonnet 4.5 / Opus 4.1 / Haiku 4.5. |
| LLM (fallback) | Z.ai (GLM) via z-ai-web-dev-sdk |
Sandbox-friendly; works without a user-provided key. |
| Theme | next-themes | Class-based dark/light with no hydration mismatch. |
.
├── src/
│ ├── app/
│ │ ├── api/ # Route handlers (server-side)
│ │ │ ├── agent/
│ │ │ │ ├── plan/ # POST generate a plan via LLM
│ │ │ │ └── runtime/ # GET current runtime info
│ │ │ ├── github/
│ │ │ │ ├── connection/ # GET GitHub connection status
│ │ │ │ └── repos/ # GET list user's repositories
│ │ │ ├── llm/
│ │ │ │ └── models/ # GET available models + providers
│ │ │ └── health/ # GET health check
│ │ ├── globals.css # Obsidian Forge design system
│ │ ├── layout.tsx # Root layout + ThemeProvider
│ │ └── page.tsx # The only user-visible route
│ ├── components/
│ │ ├── ui/ # shadcn/ui components (pre-installed)
│ │ ├── forge/ # Forge-specific primitives (logo, badges)
│ │ ├── landing/ # Landing page sections
│ │ └── app/ # App shell + views
│ │ └── views/ # dashboard, new-task, execution, etc.
│ ├── lib/
│ │ ├── agent/ # Planner · executor · tools · runtime
│ │ ├── llm/ # Claude · Z.ai · provider factory
│ │ ├── github/ # GitHub REST v3 client
│ │ ├── demo/ # Scenario library + seed data
│ │ ├── db.ts # Prisma client
│ │ └── utils.ts # cn() helper
│ ├── store/ # Zustand stores
│ ├── types/ # Shared domain types
│ └── hooks/ # use-mobile, use-toast
├── prisma/
│ └── schema.prisma # Task · Step · LogEntry · FileChange
├── docs/
│ ├── ARCHITECTURE.md # Layer-by-layer deep dive
│ ├── DEPLOYMENT.md # Step-by-step Vercel guide
│ └── LOCAL_RUNTIME.md # Optional local worker setup
├── public/ # Static assets
├── .env.example # Env var template
└── package.json
- Node.js 20+ or Bun (recommended)
- A GitHub account (for cloning; optional for running)
- An Anthropic API key (optional — Forge falls back to Z.ai / demo mode)
# 1. Clone
git clone https://github.com/KeshavCracks/sitty.git
cd sitty
# 2. Install dependencies
bun install # or: npm install
# 3. Configure environment (all optional — Forge runs in demo mode without any)
cp .env.example .env.local
# Edit .env.local to add ANTHROPIC_API_KEY and/or GITHUB_TOKEN
# 4. Set up the database (SQLite, local file)
bun run db:push
# 5. Start the dev server
bun run devOpen http://localhost:3000 — you'll land on the marketing page. Click Launch App to enter the dashboard.
No keys? No problem. Without
ANTHROPIC_API_KEYorGITHUB_TOKEN, Forge runs in demo mode: planning uses scenario templates, execution is fully simulated, and the GitHub view shows setup instructions instead of an error.
| Script | What it does |
|---|---|
bun run dev |
Start the Next.js dev server on port 3000 |
bun run lint |
Run ESLint (Next.js + TypeScript rules) |
bun run build |
Production build |
bun run start |
Run the production build |
bun run db:push |
Push the Prisma schema to SQLite |
bun run db:generate |
Regenerate the Prisma client |
bun run db:migrate |
Create a migration |
All variables are optional. Forge gracefully degrades when any are missing.
| Variable | Purpose | Required? |
|---|---|---|
DATABASE_URL |
SQLite path. Defaults to file:./dev.db. |
No |
ANTHROPIC_API_KEY |
Enables Claude as the primary reasoning model. | No |
ANTHROPIC_BASE_URL |
Override the API endpoint (e.g. for a proxy). | No |
GITHUB_TOKEN |
Enables repository browsing, branch creation, PR automation. Scope: repo. |
No |
FORGE_RUNTIME_MODE |
demo · cloud · local. Auto-detected if unset. |
No |
VERCEL |
Set automatically by Vercel. Used for runtime detection. | Auto |
See .env.example for the full template.
Forge is designed for the Vercel free tier. The deployment story is intentionally boring:
Coming soon: a Deploy button linking to Vercel's import flow.
- Push to GitHub — the repo is already at
KeshavCracks/sitty. - Import into Vercel — go to vercel.com/new, select the repo.
- Add environment variables (all optional):
ANTHROPIC_API_KEY— if you want Claude-powered planningGITHUB_TOKEN— if you want real GitHub integrationDATABASE_URL— leave as the default; Vercel will use an in-memory ephemeral SQLite (or pair with Vercel Postgres for persistence)
- Deploy. Vercel auto-detects Next.js 16 and uses the correct build settings.
See
docs/DEPLOYMENT.mdfor the full walkthrough including Postgres migration.
This project is explicit about what runs where — no fantasy architecture.
| Capability | Status | How |
|---|---|---|
| Landing page + app UI | ✅ Full | Static + client-rendered. |
| Model selection, settings, history | ✅ Full | Client-side state (Zustand + localStorage). |
| Real LLM planning (Claude / Z.ai) | ✅ Full | Serverless route handler, < 5s timeout. |
| GitHub connection check + repo list | ✅ Full | Serverless, lightweight REST calls. |
| Live agent execution UX | ✅ Full | Client-side simulated timeline with realistic streaming. |
| Health check, model list | ✅ Full | Trivial serverless endpoints. |
| Capability | Status | Why |
|---|---|---|
| Actually writing files to a repo | 🟡 Simulated | Vercel serverless has no persistent filesystem. |
| Running shell commands (tests, build) | 🟡 Simulated | No long-running processes; 10s function timeout. |
| Cloning a repo and working on a real branch | 🟡 Simulated | Same as above. |
| Opening a real PR | 🟡 Simulated | Would require the above + a worker. |
The architecture is split so the exact same UI works in two modes:
- Cloud / demo (default): mutating tools produce diffs in the UI but don't touch a real repo. Perfect for demos and the hosted version.
- Local worker (opt-in): run a small Node process locally that holds a real working tree and executes tools for real. The frontend talks to it via HTTP.
See docs/LOCAL_RUNTIME.md for the worker setup. The frontend never branches on mode — it asks the runtime for an ExecutionResult and renders whatever comes back.
Given a task description, the planner asks the configured LLM to produce a structured plan:
// src/lib/agent/planner.ts
const result = await planTask({
taskId,
description,
repository,
branch,
baseBranch,
useLlm: true, // falls back to scenario matching on any error
});The LLM is prompted to return strict JSON with an objective, assumptions, risks, and 5–9 ordered steps — each with a kind, tool, toolInput, and files. If the LLM call fails (network, bad JSON, missing key), the planner falls back to one of five predefined scenarios matched by keyword.
The agent-store walks the plan one step at a time:
- Marks the step
in_progress, emits a log entry. - Streams the step's terminal output line-by-line with realistic delays.
- Applies the step's file diffs to the store.
- Marks the step
completed, updates task progress. - Repeats until all steps are done, then opens a "pull request" and writes a summary.
Every state change flows through Zustand, so the UI updates in real time. The user can cancel mid-run; the loop checks a cancel flag between steps.
The tool layer is a typed registry:
// src/lib/agent/tools.ts
export const TOOLS: Record<ToolId, ToolDefinition> = {
read_file: { /* ... */ readOnly: true, cloudSafe: true },
write_file: { /* ... */ readOnly: false, cloudSafe: false },
run_command: { /* ... */ readOnly: false, cloudSafe: false },
git_commit: { /* ... */ readOnly: false, cloudSafe: false },
open_pr: { /* ... */ readOnly: false, cloudSafe: false },
// ...12 tools total
};Each tool declares whether it's read-only and whether it's safe to run on Vercel. The runtime uses these flags to decide whether to actually execute or to simulate.
- Landing page — polished, responsive, animated.
- App shell — sidebar, topbar, view router, mobile drawer.
- Dashboard — stats, 14-day activity chart, recent tasks, quick-start prompts.
- New task — form with sample prompts, model picker, LLM planner toggle.
- Execution — real-time plan timeline, terminal streaming, file diffs, structured logs.
- History — searchable, filterable table of all past tasks.
- GitHub view — real connection check, real repo listing (when
GITHUB_TOKENis set). - Settings — model/provider selection, runtime mode, theme, integration status.
- LLM planning — real Claude / Z.ai calls via
/api/agent/plan. - Persistence — Prisma schema ready; client-side localStorage for demo.
- Tool execution — mutating tools (write_file, run_command, git_commit) produce realistic diffs in the UI but don't touch a real repo. This is a deliberate Vercel-tier decision, not a bug.
- PR creation — the agent "opens" a PR with a fake number; the diff and summary are real.
- Branch creation — same as above.
- Local worker runtime — the
AgentRuntimeinterface is ready; implementingLocalRuntimeis a few hundred lines. Seedocs/LOCAL_RUNTIME.md. - Additional LLM providers — implement the
LLMProviderinterface and register in the factory. - Real GitHub PRs —
GitHubClient.createPullRequestis already implemented; wire it into the runtime to make PRs real.
- Local worker runtime — a small Node process that executes tools against a real working tree.
- Real PR creation — wire
GitHubClient.createPullRequestinto the runtime. - Streaming LLM output — server-sent events for token-by-token planner output.
- Tool call approval — pause before mutating tools for sensitive repos.
- Multi-file search —
search_codetool backed by ripgrep. - Vercel Postgres adapter — swap SQLite for Postgres with one env var.
- Audit log export — download the full log stream as JSONL.
The full reasoning is in
docs/ARCHITECTURE.md. Short version:
- Single-page app on
/— keeps the Vercel routing trivial, makes view transitions instant, and lets the entire UX live behind one deploy. - Typed service layer in
/lib— UI never importsfetchdirectly; everything goes through a typed function. Makes the codebase testable and swappable. - Provider abstraction — Claude is primary, but the abstraction means the project still runs in a sandbox without a user-provided key. This is what makes the demo work out-of-the-box.
- Runtime abstraction — the same UI code path handles demo / cloud / local. No
if (isDemo)branches scattered through components. - Scenario library — guarantees the demo always tells a complete, polished story even when the LLM is unreachable. Every scenario has realistic terminal output, file diffs, and a summary.
- Honest documentation — the README explicitly says what doesn't run on Vercel free tier. Recruiters and reviewers respect honesty over vaporware.
MIT — see LICENSE (or just assume MIT; this is a portfolio project).
- Inspiration: OpenHands (formerly OpenDevin), the Devin product, and the broader autonomous-agent community.
- Design: Obsidian Forge palette, hand-tuned. shadcn/ui New York style as the component base.
- Built by: KeshavCracks
If this project helped you, consider giving it a ⭐ on GitHub.