Implementation Plan

Dev Console — Phased Implementation Plan#

This document translates the product design (see DESIGN.md) into an ordered sequence of incremental milestones. Each phase ends with a working, deployable slice of the system that can be used and tested end-to-end before the next phase begins.

The guiding principle is thin vertical slices over horizontal layers: every phase ships something a real user can interact with, even if the feature set is narrow.


Phase 1 — Minimal E2E Terminal#

Goal: A user can open a browser, authenticate with GitHub, pick a workspace, and get a fully functional terminal in that workspace. Nothing else.

This is the foundational slice. Every later phase builds on top of the server, the auth middleware, and the client shell created here.

1.1 Server Scaffolding ✅#

Acceptance: go build ./... succeeds; ./dev-console --config dev-console.yaml starts and listens.

1.2 GitHub OAuth Authentication ✅#

Acceptance: Hitting GET /auth/login redirects to GitHub; after authorization the user lands back on the server with a valid session cookie. A user not on the allowlist sees a 403. A /api/whoami endpoint returns { login, id } for the authenticated user.

1.3 Auth Validation Site ✅#

A minimal server-rendered HTML site (no external JS dependencies) served directly by the Go backend to allow manual testing and validation of the auth system before the full React SPA exists.

Pages / endpoints:

Templates are Go html/template files stored in internal/templates/ and embedded in the binary via go:embed; styling uses only inline CSS so no additional build step is required. This site is intentionally replaced by the React SPA in step 1.7.

Acceptance: After completing step 1.2 configuration, an operator can:

  1. Open the server URL in a browser; when unauthenticated, be redirected to /login and see a page with a “Sign in with GitHub” link.
  2. Click the “Sign in with GitHub” link and be redirected to the GitHub OAuth flow.
  3. Complete the OAuth flow and land on the index page (/) showing their GitHub login name.
  4. Confirm that visiting / with no or an invalid cookie redirects to /login.
  5. Confirm that a GitHub login not on the allowlist receives a 403 page after completing OAuth.
  6. Click “Sign out” and confirm the session cookie is cleared and the browser returns to the login page.

1.4 Demo Login Page#

The earliest deliverable with a previewable frontend: a minimal Vite + React + TypeScript SPA that renders only the LoginPage. This phase ships the entire demo-mode infrastructure and the per-PR CI preview workflow before any real backend plumbing beyond auth exists.

Deployment model for this phase: The React SPA is built as a standalone static bundle deployed as part of the existing documentation site on Cloudflare Pages — it is not embedded in the Go binary at this stage. Vite builds with --base /demo/, and the output is copied into site/static/demo/ before Hugo runs. Hugo treats it as static content and includes it verbatim in site/public/demo/. The demo is therefore accessible at the /demo/ path on the same Cloudflare Pages origin as the documentation, and no separate Cloudflare Pages project is required. The Go-embedded HTML templates from Phase 1.3 (internal/templates/) continue to serve /login and / for any running Go server instance. The SPA does not interfere with Go-served routes because it is hosted on the Cloudflare Pages documentation origin (a separate domain). The compiled SPA replaces the Go templates in Phase 1.7, when it is embedded in the binary via go:embed.

Client setup:

LoginPage component:

MSW infrastructure (created here, extended in later phases):

client/src/mocks/
  handlers.ts   # starts empty except for GET /api/whoami → { login: "demo", id: 0 }
  browser.ts    # startWorker() — MSW Service Worker bootstrap
  server.ts     # setupServer() — Vitest / Node.js mock server

client/src/main.tsx conditionally starts the worker:

if (import.meta.env.VITE_DEMO_MODE === 'true') {
  const { startWorker } = await import('./mocks/browser')
  await startWorker()
}

DemoBanner component rendered at the app root whenever VITE_DEMO_MODE === 'true': a persistent bar reading “Demo mode — no data is saved”.

Cloudflare Pages build configuration:

The demo SPA is built as part of the Cloudflare Pages build — no separate CI workflow is needed. Configure the dev-console Cloudflare Pages project with:

SettingValue
Build commandmake site-build-with-demo
Output directorysite/public
Node.js version22
Environment variableVITE_DEMO_MODE=true

Cloudflare Pages’ native GitHub integration triggers a build on every commit and PR, and posts a deployment status with a preview URL directly on the PR. The demo is accessible at <preview-url>/demo/ alongside the documentation.

When client/ does not yet exist (before Phase 1.4 is implemented), the build command degrades gracefully: the @if [ -d "client" ] && [ -f "client/package.json" ] guard in make site-build-with-demo is a no-op and only the Hugo docs are deployed.

Acceptance:

  1. VITE_DEMO_MODE=true npm run build produces a static bundle with no server dependency.
  2. npm run preview shows the login page; entering demo as the password navigates to the placeholder page; entering anything else shows an error.
  3. Cloudflare Pages posts a preview URL on the PR; the demo is accessible at <preview-url>/demo/ alongside the documentation.

1.5 Project and Workspace Registration#

Acceptance: POST /api/projects with { "repoURL": "…" } creates a project and GET /api/projects returns it. GET /api/github/repos returns a list of repos for the authenticated user. POST /api/projects/:pid/workspaces creates a workspace and GET /api/projects/:pid/workspaces lists it.

1.6 Terminal Backend#

Acceptance: websocat or a small test harness can attach to the WebSocket, send resize + input, and receive shell output.

1.7 Minimal Web Client#

A React + TypeScript SPA (bootstrapped with Vite) that provides exactly:

The compiled SPA is embedded in the Go binary via go:embed and served from /, replacing the Go-embedded HTML templates from Phase 1.3 (internal/templates/). The internal/templates/ package and its routes (GET / and GET /login) are removed in this phase once the SPA takes over.

Styling is minimal — Tailwind CSS with a dark theme matching a terminal aesthetic. No design polish is required at this stage.

Demo mode is a first-class deliverable of this phase, not an afterthought. MSW handlers for every new endpoint must be committed alongside the components — not in a follow-up PR. See the Testing & Validation Strategy for the full pattern.

Demo mode for this phase (extends the handlers from Phase 1.4):

Per-PR Cloudflare Pages deployment is already active from Phase 1.4 — this phase’s changes will automatically trigger a preview.

Acceptance: The full flow works in Chrome and Safari on both desktop and a 375 px wide mobile viewport:

  1. VITE_DEMO_MODE=true npm run build produces a static bundle with no server dependency.
  2. npm run preview shows the demo banner and the full flow (login → project list → workspace list → open terminal → interactive echo session) without any backend.
  3. Cloudflare Pages posts a preview URL on the PR; the demo is accessible at <preview-url>/demo/ alongside the documentation.
  4. Against a real server (no VITE_DEMO_MODE): login → project list → workspace list → open terminal → interactive shell session.

Phase 1 Deliverables#

ArtifactDescription
go.modGo module definition
cmd/dev-console/Server entry point
internal/config/Config loading
internal/auth/GitHub OAuth + session middleware
internal/templates/html/template files (embedded via go:embed) for the auth validation site
internal/project/Project registry
internal/workspace/Workspace store (in-memory, created at runtime)
internal/terminal/PTY session management
client/Vite + React + TypeScript SPA (bootstrapped in Phase 1.4)
client/src/mocks/MSW handlers and browser/server worker entry points (created in Phase 1.4)
docs/examples/dev-console.yaml.exampleAnnotated sample configuration
Makefilemake build, make dev, make test, make site-build-with-demo targets

Phase 2 — File Browsing#

Goal: Users can browse the workspace file tree and read file contents in the browser.

2.1 File API#

Add to internal/workspace/:

Both endpoints validate that the resolved path does not escape the workspace root (path-traversal protection).

Acceptance: curl returns directory listings and file contents; requests for paths outside the root return 400.

2.2 File Browser UI#

Acceptance: User can expand directories, click files, and read their contents. The terminal panel remains accessible. Demo build works end-to-end without a backend.


Phase 3 — Basic Agent Chat#

Goal: Users can open a chat session with an AI assistant that can read files and answer questions about the workspace. No file writes yet.

3.1 LLM Client#

Acceptance: Unit test that stubs the HTTP response and verifies streamed chunks are reassembled correctly.

3.2 Agent Session Backend (read-only)#

Tools enabled in this phase: read_file, list_files (no write_file or run_command)

Acceptance: User can ask “What files are in the root of this workspace?” and receive a correct streamed answer.

3.3 Chat UI#

Acceptance: Full conversational loop visible in the browser; streaming text appears word-by-word. Demo build works end-to-end without a backend.


Phase 4 — Change Proposal & Review#

Goal: The agent can propose file edits; the user reviews diffs and accepts or rejects them before any file is written to disk.

4.1 Pending Change Backend#

Acceptance: Agent proposes a change; the in-memory store holds it; accept endpoint writes the file.

4.2 Git Status & Diff API#

Acceptance: After accepting a change, git/status reflects the modification.

4.3 Diff Review UI#

Acceptance: User can trigger a file edit via chat, review the diff, and accept or reject it. File tree updates after acceptance. Demo build works end-to-end without a backend.


Phase 5 — Full Agent Toolset & Manual Editing#

Goal: The agent has its complete tool set; users can also manually edit files.

5.1 run_command Tool#

Acceptance: Agent can run go test ./... or npm test and report results.

5.2 git_diff Tool#

5.3 Manual File Editor#

Acceptance: User can open a file, edit it, save it, and see the change reflected in git/status. Demo build works end-to-end without a backend.


Phase 6 — Polish & Production Readiness#

Goal: The system is ready for daily use by a small trusted team.

6.1 Error Handling & Resilience#

6.2 Session Persistence (optional)#

6.3 PWA & Mobile UX#

6.4 TLS & Deployment#

6.5 Observability#


Testing & Validation Strategy#

Rule: Demo mode is mandatory for all frontend functionality#

Every piece of frontend functionality must work in demo mode before it may be merged. This is not optional. A PR that adds or modifies frontend components without shipping the corresponding MSW handlers will be rejected.

Demo mode serves two purposes:

  1. Per-PR previews — reviewers can interact with any UI change via the auto-deployed Cloudflare Pages URL without running a server.
  2. Unit testing — the same MSW handlers are reused in Vitest tests, so there is one source of truth for mock behaviour.

Pattern: Mock Service Worker (MSW)#

The project uses Mock Service Worker as the seam between real backend calls and demo/test stubs. MSW intercepts fetch and WebSocket calls at the browser’s Service Worker layer, which means:

File layout:

client/src/mocks/
  handlers.ts      # All MSW request/WebSocket handlers
  browser.ts       # MSW browser worker setup (startWorker())
  server.ts        # MSW Node.js server setup for Vitest (setupServer())

Enabling demo mode:

In client/src/main.tsx:

if (import.meta.env.VITE_DEMO_MODE === 'true') {
  const { startWorker } = await import('./mocks/browser')
  await startWorker()
}

The VITE_DEMO_MODE variable is set to 'true' only in the CI demo build and local npm run demo convenience script. It is never set in the production build.

Handler conventions:

Demo-specific UI:

PR Preview Deployments#

The dev-console Cloudflare Pages project is configured to use make site-build-with-demo as its build command (site/public as the output directory). Cloudflare Pages’ native GitHub integration takes care of the rest:

  1. On every PR commit, Cloudflare Pages runs make site-build-with-demo.
  2. If client/ exists, the target builds the SPA with VITE_DEMO_MODE=true and --base /demo/, copies the output to site/static/demo/, then runs Hugo to produce site/public/ with the documentation and the demo at /demo/.
  3. If client/ does not yet exist (or has no package.json), the guard in make site-build-with-demo is a no-op and only the Hugo docs are built and deployed.
  4. Cloudflare Pages posts a deployment status with the preview URL directly on the PR. The demo is accessible at <preview-url>/demo/.

No GitHub Actions workflow or repository secrets are required for deployments.

PRs that include user-visible UI changes must include a screenshot or screen recording taken from the <preview-url>/demo/ Cloudflare Pages URL in the PR description.

Acceptance Gate (applies to every phase with frontend work)#

A phase is not done until all of the following hold:

  1. VITE_DEMO_MODE=true npm run build succeeds with no errors or warnings.
  2. npm run preview (or the Cloudflare Pages URL) shows a fully functional demo covering all UI flows introduced in the phase — no backend required.
  3. npm test (Vitest) passes; tests exercise components using the same MSW handlers as the demo.
  4. Cloudflare Pages posts a preview URL on the PR with the demo accessible at <preview-url>/demo/.

Dependency Map#

Phase 1 ──► Phase 2 ──► Phase 3 ──► Phase 4 ──► Phase 5
              │                          │
              └──────────────────────────┘
                 (file APIs reused by agent tools)
Phase 6 can be worked on incrementally alongside Phase 4 and 5.

Phase 1 is a hard prerequisite for everything else because it establishes:


Work Sizing Guidance#

PhaseEstimated EffortPrimary Risk
1~3–4 daysOAuth flow edge cases; PTY on macOS vs Linux
2~1–2 daysPath-traversal validation; large binary files
3~2–3 daysLLM streaming; tool-call parsing across providers
4~2–3 daysDiff rendering; atomic file writes
5~1–2 daysCommand sandboxing; editor UX
6~2–3 daysPWA quirks on iOS; SQLite CGo build

Estimates assume a single focused engineer. They grow if providers other than OpenAI are tested simultaneously.


Definition of Done for Each Phase#

  1. make build succeeds with no warnings.
  2. make test passes with no failures.
  3. The acceptance criteria listed in each section are manually verified.
  4. For phases with frontend work: all items in the Acceptance Gate in the Testing & Validation Strategy are satisfied — in particular, the demo build works without a backend and the demo-preview CI workflow produces a preview URL.
  5. A brief entry is added to CHANGELOG.md describing what shipped.