This document describes the architecture and design of Knight.dev, including authentication, sandboxing, background jobs, API layer, UI system, and database schema. It also outlines key request flows and configuration.
- Authentication (Clerk sign-in)
- Signed-in Home with User Menu
- Builder: Video Homepage Example (Sidebar + Grid)
-Builder: Generated Code
- Landing Page with Animations (Preview)
- Framework: Next.js 15 (App Router)
- Auth: Clerk
- API: tRPC (server via fetch adapter, React Query client)
- Background Jobs / Events: Inngest (Next.js handler)
- Sandboxing: E2B sandboxes for running code and commands
- UI: Shadcn UI + Tailwind CSS
- DB: PostgreSQL with Prisma ORM
- UI routes under
src/apprender client components, connect viatRPCto server procedures. - Clerk wraps the app to provide authentication context;
src/middleware.tsprotects non-public routes. - Server-side logic is encapsulated in
tRPCrouters (src/trpc/routers/_app.ts) with protected procedures enforced by Clerk auth insrc/trpc/init.ts. - User requests trigger domain procedures (e.g., create project), which may enqueue an Inngest event.
- Inngest function (
knightFunction) provisions/uses an E2B sandbox to run commands, create/update files, and persists outputs via Prisma. - Prisma models store
Project,Message,Fragment, andUsagedata in Postgres.
[Next.js App] --tRPC--> [Procedures] --Prisma--> [Postgres]
| |
+--Clerk (auth)---------------------+
|
+--(enqueue)--> [Inngest] --> [E2B Sandbox] --> (results) --> [Prisma]
- Provider:
src/app/layout.tsxwraps app withClerkProvider. - Public/protected routing:
src/middleware.tsusesclerkMiddlewareandcreateRouteMatcherto protect non-public routes. Public:/,/sign-in,/sign-up,/api/inngest,/projects(.*),/pricing(.*). - Sign-in/up pages:
src/app/(home)/sign-in/[[...sign-in]]/page.tsx,src/app/(home)/sign-up/[[...sign-up]]/page.tsxusing@clerk/nextjscomponents with theme adapted to current theme. - Navbar integration:
src/modules/home/ui/components/navbar.tsxusesSignedIn,SignedOut,SignInButton,SignUpButton, and rendersUserControlwhen authenticated. - tRPC auth:
src/trpc/init.tsimports Clerk context to enforceprotectedProcedurevia middleware (UNAUTHORIZEDif noctx.auth.userId).
Environment:
CLERK_PUBLISHABLE_KEYCLERK_SECRET_KEY
- Template config:
sandbox-templates/nextjs/e2b.toml, Dockerfile, andcompile_page.shdefine a Next.js + Shadcn template for rapid boot. - Inngest
knightFunctioncreates a sandbox from templateknights-nextjs-test3and connects via@e2b/code-interpreter. - Utility:
src/inngest/utils.ts#getSandboxconnects bysandboxIdand sets generous timeouts. Used to run terminal commands and file ops within the sandbox.
- Client:
src/inngest/client.ts(id: "knight.dev"). - API handler:
src/app/api/inngest/route.tsexposes Next.js route viaserve({ client, functions: [knightFunction] })for GET/POST/PUT. - Function:
src/inngest/functions.tslistens to eventknight/run:- Fetches last messages for context via Prisma.
- Creates state and an AI agent with a prompt (
src/prompt/prompt.ts), modelgemini-2.5-flash. - Provides tools, notably
Terminalto run commands in the sandbox, and a file write tool, then persists results.
- Triggering:
src/modules/projects/server/procedures.tssends the event after creating a project.
Note: Current setup is event-driven (no explicit cron). Cron can be added by scheduling Inngest functions if needed in future.
Environment:
INNGEST_EVENT_KEY/ project env as required by Inngest (and framework defaults)GEMINI_API_KEYfor modelE2B_API_KEYfor sandbox client (if used by runtime/SDK)
- Router composition:
src/trpc/routers/_app.tscombinesmessages,projects, andusagerouters. - Server adapter:
src/app/api/trpc/[trpc]/route.tsvia@trpc/server/adapters/fetch. - Context/middleware:
src/trpc/init.tssetssuperjsontransformer andprotectedProcedureusing Clerk auth. - Server utilities:
src/trpc/server.tsxexposestrpcproxy andcallerfor server-only usage. - Client:
src/trpc/client.tsxsets up React Query + SSR-safe client providerTRPCReactProviderwrapped insrc/app/layout.tsx.
Key procedures (examples):
projects.createcreates a project, consumes credits viasrc/lib/usage.ts, persists initial user message, and enqueuesknight/run.projects.getOne/list fetch user projects with auth.messages.*andusage.*provide message persistence and credit usage tracking.
- Components live under
src/components/ui/*and are consumed across modules. - Global theming:
src/app/layout.tsxwraps with aThemeProviderand includesToasterfor notifications;useCurrentThemehook influences Clerk components. - Example usage:
NavbarusesButton, authenticated Clerk buttons, andUserControl.
src/components/hint.tsxwraps ShadcnTooltipto provide a simpleHintAPI:- Props:
children,text, optionalside(defaulttop), andalign. - Usage: Wrap the target element to show a tooltip with provided text.
- Props:
- Prisma client: generated to
src/generated/prisma; instantiated insrc/lib/db.tswith global reuse in dev. - Schema:
prisma/schema.prismaProject: user-scoped container withmessagesrelationMessage: content withrole(USER|ASSISTANT),type(RESULT|ERROR), belongs toProjectFragment: one-to-one withMessage, storessandboxUrl,title, andfiles(JSON tree)Usage: tracks rate/credits (key, points, expiry)
- Migrations are in
prisma/migrations/*.
Environment:
DATABASE_URL(Postgres connection string)
- Create Project (and trigger agent)
- User submits a prompt in
MessageForm→projects.create(protected) consumeCredits()validates usage →prisma.project.create()with initial message- Event
knight/runis sent to Inngest →knightFunctionruns agent in E2B sandbox - Outputs (messages/fragments/files) are persisted and rendered in project view
- Authentication
- Public pages are accessible; protected routes invoke
auth.protect()via middleware - UI reacts using
SignedIn/SignedOutand Clerk components
- Tooling inside Inngest function
- Terminal tool runs commands inside sandbox and streams stdout/stderr
- File tool creates/updates files in sandbox; results summarize back to messages/fragments
-
Install dependencies
npm install
-
Environment variables (example
.env.local)DATABASE_URL="postgresql://user:pass@localhost:5432/knight" CLERK_PUBLISHABLE_KEY=pk_... CLERK_SECRET_KEY=sk_... GEMINI_API_KEY=... E2B_API_KEY=... -
Database
npx prisma migrate dev npx prisma generate
-
Run app
npm run dev
- Auth:
src/app/layout.tsx,src/middleware.ts,src/app/(home)/sign-in/*,src/app/(home)/sign-up/*,src/modules/home/ui/components/navbar.tsx - Inngest:
src/app/api/inngest/route.ts,src/inngest/client.ts,src/inngest/functions.ts,src/inngest/utils.ts - Sandboxes:
sandbox-templates/nextjs/* - tRPC:
src/app/api/trpc/[trpc]/route.ts,src/trpc/*, routers undersrc/modules/*/server/procedures.ts - UI:
src/components/ui/*,src/components/hint.tsx, module components undersrc/modules/*/ui - DB:
prisma/schema.prisma,src/lib/db.ts, migrations underprisma/migrations/*
- Add Inngest schedules for periodic maintenance (credits reset, cleanup)
- Improve sandbox lifecycle management (timeouts, teardown)
- Expand usage metering and pricing integrations
src/
app/
(home)/
layout.tsx
page.tsx
pricing/
page.tsx
sign-in/[[...sign-in]]/
page.tsx
sign-up/[[...sign-up]]/
page.tsx
projects/[projectId]/
page.tsx
api/
trpc/[trpc]/route.ts (tRPC fetch adapter endpoint)
inngest/route.ts (Inngest handler)
error.tsx
globals.css
layout.tsx (Root layout: Clerk, tRPC provider, ThemeProvider)
components/
hint.tsx (Tooltip wrapper)
file-explorer.tsx
tree-view.tsx
code-view/
index.tsx
code-theme.css
ui/ (Shadcn UI components)
button.tsx, input.tsx, dialog.tsx, ...
modules/
home/
ui/components/
navbar.tsx
project-form.tsx
project-list.tsx
projects/
ui/components/
fragment-web.tsx
message-card.tsx
message-container.tsx
message-form.tsx
message-loading.tsx
project-header.tsx
usage.tsx
ui/views/
project-view.tsx
hooks/
use-current-theme.ts
use-mobile.ts
use-scroll.ts
types/
prismjs-components.d.ts
types.ts
src/app/
(home)/
page.tsx → GET / (public)
pricing/page.tsx → GET /pricing (public)
sign-in/[[...sign-in]]/ → ALL /sign-in (public)
page.tsx
sign-up/[[...sign-up]]/ → ALL /sign-up (public)
page.tsx
projects/[projectId]/ → GET /projects/:id (public per middleware)
page.tsx
api/
trpc/[trpc]/route.ts → /api/trpc (server adapter)
inngest/route.ts → /api/inngest (public)
error.tsx → error boundary
layout.tsx → root layout (Clerk, tRPC provider, ThemeProvider)
Middleware:
src/middleware.ts → protects non-public routes using Clerk
Public matchers: '/', '/sign-in(.*)', '/sign-up(.*)', '/api/inngest(.*)', '/projects(.*)', '/pricing(.*)'
[Navbar]
├─ Uses Clerk: SignedIn / SignedOut
└─ Shows SignIn/SignUp buttons or UserControl
[Home Page]
└─ Links to create/view projects
[Project View]
├─ <MessageForm>
│ └─ tRPC: projects.create (protected)
│ ├─ consumeCredits() (usage)
│ ├─ prisma.project.create(..., messages: [USER])
│ └─ inngest.send('knight/run', { projectId, value })
├─ <MessageContainer>
│ └─ Renders messages (USER/ASSISTANT) via tRPC queries
└─ <FragmentPreview> / <FileExplorer>
└─ Shows files and outputs returned by Inngest agent
[tRPC Client Provider]
└─ Wraps the app in root layout; enables hooks in UI components
[ThemeProvider + Toaster]
└─ Global UI state, notifications, and theming
# --- Core App ---
# Base URL of your app (optional, used by some services)
# NEXT_PUBLIC_APP_URL=http://localhost:3000
# --- Database (PostgreSQL) ---
# Example: postgresql://USER:PASSWORD@HOST:PORT/DB_NAME?schema=public
DATABASE_URL="postgresql://postgres:postgres@localhost:5432/knight?schema=public"
# --- Clerk Authentication ---
# Public key is safe to expose to the browser
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY="pk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# Secret key must stay on server only
CLERK_SECRET_KEY="sk_test_XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# Optional Clerk routes (uncomment to override defaults)
# NEXT_PUBLIC_CLERK_SIGN_IN_URL="/sign-in"
# NEXT_PUBLIC_CLERK_SIGN_UP_URL="/sign-up"
# NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL="/"
# NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL="/"
# --- Inngest ---
# If using Inngest Cloud or authenticated event delivery
# INNGEST_EVENT_KEY=""
# INNGEST_APP_ID="knight.dev"
# --- E2B Sandbox ---
# Needed to create/connect sandboxes via SDK
E2B_API_KEY="e2b_XXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# --- AI Model (Gemini) ---
GEMINI_API_KEY="AIzaSyXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
# --- Node / Runtime ---
# Set by scripts or environment; included here for completeness
# NODE_ENV="development"



