Files
nettee 6b90486c97 docs: reconcile stale documentation with current code (#5829)
* fix(docs): align question guidance with form flow

* docs: reconcile stale documentation with current code

* fix(docs): remove retired template metadata from guides

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)

* fix(e2e): stabilize visual workspace helper

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)

* fix(docs): align localized template guide metadata

Generated-By: looper 0.10.6 (runner=fixer, agent=codex)
2026-07-18 03:41:08 +00:00

13 KiB

Maintainability Roadmap

Purpose

This document captures the maintainability risks in the current apps/web + apps/daemon architecture and the recommended optimization path.

The architectural boundary stays unchanged:

  • apps/web: Next.js frontend and thin BFF/proxy layer.
  • apps/daemon: local runtime/backend for SQLite, daemon-managed filesystem state, AI agent CLI processes, and SSE streaming. This roadmap MUST NOT define daemon data paths; read root AGENTS.md → Daemon data directory contract before documenting storage.

The first-principles maintainability goals are:

  • Understandability: engineers can locate behavior quickly and reason about data flow.
  • Changeability: common changes can be made with bounded blast radius.
  • Verifiability: contracts, tests, and types catch regressions early.
  • Isolation: high-risk capabilities are contained behind explicit boundaries.
  • Recoverability: failures produce actionable state, logs, and cleanup behavior.

Priority Scale

Priority Meaning
P0 Blocks safe evolution or creates high-risk runtime/security failure modes.
P1 Major maintainability risk that increases regression and debugging cost.
P2 Medium-term risk that affects reliability, portability, or architecture clarity.
P3 Supporting documentation/process improvement.

Risk List and Optimization Plan

ID Priority Risk Evidence Impact Optimization Plan
R1 P0 Daemon TypeScript enforcement still has suppression gaps. apps/daemon typechecks, but @ts-nocheck remains in high-risk core modules (server.ts, agents.ts, projects.ts, runtimes/runs.ts, cli.ts), newer brand/memory modules, and several tests. Payload, DB row, process, and event changes inside suppressed modules can bypass the guarantees reported by package typecheck. Keep TypeScript as the source default, prevent new suppressions, remove existing suppressions owner-by-owner, and route shared API/SSE/error shapes through packages/contracts.
R2 P0 Shared web/daemon contracts need complete adoption. packages/contracts now owns shared API DTOs, error shapes, and SSE unions consumed by both runtimes, while some legacy daemon handlers still shape JSON locally. New or legacy endpoints that bypass the package can still drift from web and CLI consumers at runtime. Extend packages/contracts before changing shared wire shapes, use the daemon HTTP response helpers at route boundaries, and add contract-focused tests for every migrated endpoint.
R3 P0 Runtime validation is incomplete at the daemon boundary. Daemon requests can trigger local filesystem access, SQLite writes, and child_process.spawn(). Type correctness alone cannot protect against malformed runtime input, path traversal, invalid agent IDs, or unsafe args. Add schema validation at HTTP boundaries with Zod/TypeBox; centralize validation for workspace paths, task IDs, agent IDs, models, reasoning options, uploaded files, and command arguments.
R4 P0 Local capability security boundary needs explicit rules. Daemon owns high-permission capabilities: local files, daemon-managed storage, project workspaces, agent CLIs, and logs. Unsafe path handling, broad command execution, token leakage, and unintended workspace access become possible failure modes. Treat daemon as a capability server: bind to localhost, use workspace/path allowlists, normalize and jail paths, allowlist agent commands, and redact sensitive output.
R5 P0 Agent process lifecycle needs a first-class manager. /api/chat spawns multiple agent runtimes and streams output to the frontend. Zombie processes, cancellation gaps, orphaned tasks, inconsistent exit handling, and concurrent process conflicts. Introduce a process/task manager with task state machine, cancellation, timeout, cleanup, exit code capture, signal handling, and concurrency limits.
R6 P1 server.ts remains oversized after partial modularization. Many domain registrars now live under apps/daemon/src/routes/ and shared HTTP primitives under apps/daemon/src/http/, but server.ts still owns substantial legacy routes and run orchestration alongside composition. Unrelated changes can still collide in the composition root, and large lifecycle paths remain difficult to isolate in tests. Continue extracting touched domains into narrow route registrars and services while keeping server.ts as the composition root; avoid a broad mechanical rewrite.
R7 P1 Error handling is only partially centralized. packages/contracts/src/errors.ts and apps/daemon/src/http/ provide typed errors and response adapters, while legacy handlers still contain local try/catch blocks and ad hoc JSON failures. Consumers can still receive inconsistent status/envelope semantics, and local catches can lose context or leave partial state. Migrate touched routes to the shared error/response boundary, preserve named recovery paths, and add adapter-level mappings for domain failures.
R8 P1 Versioned SSE contracts need consistent end-to-end use. packages/contracts now defines versioned chat/proxy SSE unions and the critique event union, but legacy producers and consumers can still emit or parse locally shaped events. A bypass can reintroduce disconnect, terminal-event, replay, and error-semantic drift despite the shared types. Keep canonical event names/payloads in contracts, route producers and consumers through typed helpers, and pin replay/disconnect/terminal semantics with contract tests.
R9 P1 SQLite schema and migration lifecycle need stronger guarantees. apps/daemon/src/db.ts owns local better-sqlite3 tables and migrations. Local user data upgrades can fail unpredictably; schema drift is hard to diagnose and recover. Add explicit migration table, ordered forward migrations, startup migration checks, schema version logging, backup-before-migrate strategy, and migration tests.
R10 P1 Broad daemon coverage is not yet organized as an explicit test pyramid. apps/daemon/tests/ now covers routes, DB behavior, agents, SSE, critique, media, connectors, config, and filesystem boundaries, but layer ownership and some lifecycle/migration gaps remain uneven. Large suites can still hide which boundary failed, while unmodeled migration or process-lifecycle paths retain regression risk. Make the layers explicit: shared contract tests, route integration suites, service units, migration tests, canonical SSE tests, and mocked process-lifecycle tests.
R11 P1 Logging and observability are insufficient for local runtime debugging. Agent execution involves long-lived tasks, subprocess output, filesystem state, and frontend SSE consumption. User issues are hard to reproduce; failures lack correlated context. Add structured logs with requestId, taskId, agentId, workspace, exit code, and duration; separate app logs from agent output; redact secrets.
R12 P2 Configuration, port, and readiness behavior remains only partially centralized. Web proxies /api/* to the daemon, tools-dev coordinates the two listeners, and GET /api/health exposes basic process health but not full dependency readiness. Port conflicts, daemon-not-ready states, and mismatched environment variables can still break startup or distribution. Centralize config resolution, enrich health with readiness checks, and make port selection plus UI fallback deterministic.
R13 P2 Cross-platform behavior is a recurring risk. Daemon uses filesystem paths, SQLite native bindings, shell/process behavior, and signals. macOS, Linux, and Windows/WSL can differ in path normalization, quoting, permissions, and process termination. Use Node path APIs consistently, avoid shell string composition, isolate platform-specific process logic, and add CI coverage for supported platforms.
R14 P2 Framework migration can distract from core maintainability issues. Current complexity is concentrated in FS/spawn/SSE/SQLite and module boundaries. A framework rewrite can consume time while preserving the risky domain logic. Keep Express for now; revisit Fastify only after TS, contracts, validation, tests, and modularization are in place and Express becomes a clear limiter.
R15 P2 Web/daemon boundary can erode over time. Next.js has BFF capability and daemon has backend capability; future edits may blur ownership. High-permission local runtime logic may leak into apps/web; deployment and security assumptions become unclear. Document and enforce ownership: web handles UI/BFF/proxy; daemon owns local runtime capabilities; shared code contains contracts and pure logic only.
R16 P3 Operational documentation is incomplete. Local-first daemon behavior depends on ports, daemon-managed storage, agent CLIs, runtime logs, and recovery flows. Onboarding and support costs rise; troubleshooting relies on oral knowledge. Document daemon architecture, API/SSE contract, task lifecycle, storage contract index, agent dependency checks, and common recovery procedures.

Optimization Dependencies

The optimization work should proceed in dependency order. Some items can run in parallel once their prerequisites are stable.

Workstream Status Optimization Covers Depends on Output
W1 Completed Confirm architecture and capability boundaries R4, R15 — Written ownership rules for web, daemon, shared contracts, and dangerous local capabilities. See specs/current/architecture-boundaries.md.
W2 Completed Define API, SSE, and error contracts R2, R7, R8 W1 packages/contracts now provides shared request/response types, SSE event unions, and error model helpers consumed by web and daemon.
W3 Partial Migrate project-owned code to TypeScript R1 W2 for highest-value shared types TypeScript is the project-owned source default and the daemon package typechecks, but suppressions remain in core runtime files, newer brand/memory modules, and some tests. Remove them in owner-sized slices, then run pnpm --filter @open-design/daemon typecheck, pnpm typecheck, and pnpm guard.
W4 Planned Add runtime validation at daemon boundaries R3, R4 W2 Schemas for HTTP requests, paths, agents, models, uploads, task IDs, and command args.
W5 Partial Modularize server.ts R6 W2, W3, W4 Domain registrars, typed route dependencies, and shared HTTP helpers now live under apps/daemon/src/routes/, server-context.ts, route-context-contract.ts, and apps/daemon/src/http/. Remaining work is to extract substantial legacy route/orchestration blocks from server.ts without mixing broad moves with behavior changes.
W6 Partial Introduce agent process/task manager R5, R8, R11 W2, W5 apps/daemon/src/runtimes/runs.ts now provides an in-memory chat run service with run states, event replay, SSE streaming, cancellation, waiting, terminal cleanup, and exit metadata; critique also has an in-process run registry for interrupts. Remaining work is a unified agent process manager with explicit concurrency limits, stronger timeout/cleanup policy, and consistent lifecycle ownership across agent surfaces.
W7 Planned Strengthen SQLite migrations R9 W5 or a clear DB adapter boundary Migration table, ordered migrations, startup checks, backup strategy, migration tests.
W8 Partial Build the daemon test pyramid R10 W2, W4, W5 Daemon now has broad Vitest coverage under apps/daemon/tests/, including route, agent, DB, SSE, critique, live-artifact, connector, config, and filesystem behavior. Remaining work is to make the layers explicit: shared contract tests, route integration suites, service unit tests, migration tests, canonical SSE protocol tests, and mocked agent-process lifecycle tests.
W9 Planned Add structured logs and observability R11 W2, W6 Correlated request/task logs, sanitized agent output, durations, exit status, and diagnostic context.
W10 Partial Harden config, port, and readiness behavior R12 W1 Daemon exposes GET /api/health with basic { ok, version } health data. Remaining work is centralized config resolution, richer readiness checks, deterministic port behavior, and UI-visible daemon-not-ready handling.
W11 Partial Harden cross-platform behavior R13 W4, W6, W5 Some process and path hardening exists, including shared platform command invocation and Windows command-line budget checks for agent CLIs. Remaining work is to formalize platform-specific process handling, path normalization rules, and supported-platform CI coverage.
W12 Planned Revisit HTTP framework choice R14 W2, W3, W4, W5, W8 Evidence-based decision on whether Express remains adequate or Fastify provides clear net value.
W13 Partial Complete operational documentation R16 W1 through W11 as sections stabilize Boundary and ownership documentation exists in AGENTS.md, apps/AGENTS.md, packages/AGENTS.md, and specs/current/architecture-boundaries.md. Remaining work is current-state daemon docs, API/SSE lifecycle docs, runbooks, troubleshooting guides, and recovery procedures.
Phase 1: W1 -> W2 -> W3 -> W4
Phase 2: W5 -> W6 -> W7 -> W8
Phase 3: W9 -> W10 -> W11 -> W13
Phase 4: W12

The core principle is to reduce risk before changing framework foundations: establish contracts, types, validation, and module boundaries first; then evaluate whether Express remains the right transport layer.