Architecture
Current component boundaries and the reasons behind them.
Redpact is a local development review tool. It connects project checkouts, captures submitted test intent and source, executes tests, and presents observed evidence. Test success, configuration validity, application freshness and human acceptance are different facts. A result never implies the others.
The primary experience is the GPT-embedded viewer: users follow agent work, inspect test evidence, approve execution and manage test environments. The standalone browser remains supported with the same UI and runtime. Chat MCP returns structured results and links to web review; it has no inline cards. Frontend conventions defines their navigation boundary.
Agents use CLI operations over local HTTP to enter shared workflows. Model-facing MCP is limited to runtime status, shutdown and opening the app; the App Page companion can also start its owned runtime. The full embedded app retains App-only MCP transport. Settings use revision-checked CLI reads and partial updates; JSON remains the internal storage format. General files and Git use host tools. See interfaces.
Supported product scope
Redpact supports the standalone web app and the full web app embedded inside OpenAI through MCP. Both use one shared React UI and server runtime; HTTP/SSE and MCP are transport adapters, with host-specific capabilities and limits described in installation. Execution approval and detailed evidence remain in the full web viewer.
The viewer prioritizes evidence, execution approval and environment lifecycle over manual Git operations. Source/commit inspection stays available; Git writes and publication belong to agents using host tools and retained backend workflows. Removing a viewer button does not remove its server contract or authorize an agent operation. Test execution approval remains distinct from acceptance of code or Git changes. See Git operations.
The app uses one page-owned shared header in Full, Half View and Mobile. Keep it on one row, remove low-value controls before adding density, and preserve content width at half view. Frontend conventions owns responsive details and verification viewports; the embedded and standalone entries share this design.
CI verifies the shared web UI and server on Ubuntu with Node 24, without an OS/Node matrix. This is the release verification baseline, not evidence of behavior on every host. See development for automated and manual checks.
Components
Web viewer ───────── HTTP ─┐
├── workflows (Imperative Shell) ── core (pure decisions)
Agent ─── MCP ───┤ │
Startup / observation ──────┘ └── adapters ── Git / files / runtimes
Documentation site ── docs/*.md| Source | Responsibility |
|---|---|
app/server/src/interfaces | Hono HTTP routes and MCP transport, request validation and response shaping |
app/server/src/workflows | All application use cases, including single-feature queries, execution, approval, observation, recovery and termination |
app/server/src/core | Pure policies, calculations, validation schemas and formatting; explicit input data produces decisions or values |
app/server/src/core/types | Type-only data and dependency contracts; no runtime exports or barrel |
app/server/src/adapters | Files, native Git, source parsing, processes, Docker and Playwright |
app/server/src/main.ts | Concrete dependency wiring and process lifecycle |
app/web | Connected React viewer shared by browser and sidebar App Page |
Separate redpact-web repository | Website and documentation renderer; reads this repository’s docs/ directly |
Boundary rules
The server uses Functional Core, Imperative Shell. HTTP, MCP and internal application
triggers enter workflows for use cases. Transport code may use pure schemas and
formatters directly, but does not reach adapters to implement application behavior.
The workflow directory includes feature-level service factories as well as operations
that combine several services; an existing createXxx name does not make it Core.
Workflows gather facts, call pure policies when needed, and perform effects through injected dependencies. They own sequencing, cancellation, locking, recovery and cleanup. A simple read can return an adapter result directly: do not create a Core function that only forwards data, or require every workflow to call Core. Use the same use-case implementation from HTTP and MCP instead of duplicating behavior.
Core receives data, not storage, runner or other effectful service capabilities. It must not import workflows, adapters or interfaces, including through type imports. Time, random identifiers and external observations are supplied by the Shell when a policy needs them. Local calculation and deterministic hashing are allowed; Core must not change caller-owned data or access ambient external state. Schemas and formatters remain reusable by transports and adapters. Adapters never import workflows or interfaces, and workflows never import transport implementations.
Extract a policy when it expresses a meaningful rule, such as verdict precedence, review-tab availability or container selection. Keep related rules together rather than extracting every assignment. Straight-line I/O and its control flow belong in the Shell. Run admission and terminal verdicts remain distinct from Environment reservations, resource state and stop admission. The stop workflow blocks admission, confirms cancellation, then removes owned resources. Cleanup failure remains separate from a test verdict. Preserve locking and observation order when moving decisions: a pure decision does not make a read/check/write sequence atomic.
The architecture tests check layer imports, server dependency cycles (including type imports), type-only contracts, reviewed Core external imports and common ambient effects such as clocks, randomness and process environment access. These are static regression guards, not proof of purity; injected callbacks, input mutation and library behavior still require review and focused behavior tests.
Use TypeScript, Hono and ordinary functions. Avoid controller classes, DI containers, generic storage engines and speculative wrappers. Reuse existing libraries and Node primitives. There is no generic event bus, command interpreter or transaction engine between record files.
Current implementation choices
- Runtime storage uses JSON and artifact files with one writer per instance. Ordered Umzug startup migrations upgrade supported runtime layouts; see storage. There is no SQLite/Drizzle runtime.
- Native Git owns status and exclude semantics for all index formats, patches and mutations. Repository discovery and supported blob reads retain isomorphic-git.
- Parcel file observation drives scoped invalidations; observation never runs tests.
- ts-morph extracts static test intent from isolated submitted-file symbols without loading TypeScript standard-library declarations. Vitest records actual integration results. Static parsing does not prove assertion execution or full import coverage.
- Testcontainers owns temporary container, Compose and network lifecycles through live worker handles and Ryuk fallback. Redpact owns input capture, admission, evidence, health observations, resource identities, cancellation and recovery cleanup. The persistent main-checkout Container retains its independent lifecycle.
- Unit, Integration Vitest and Playwright execute in temporary containers. Integration and Playwright join a per-execution network with service-name access to the application.
- The connected web viewer implements explicit request approval. MCP returns review paths without approval capabilities. Approval does not establish code acceptance or isolation from trusted local processes.
- GitHub publication reuses native Git and authenticated
gh; GitHub owns PR identity.
Standalone npm installs use a CLI parent to stop the owned server before delegating package replacement to its detected npm/pnpm owner. The viewer exposes update availability; SemVer comparison uses the existing node-semver implementation. See runtime updates for installation limits and restart behavior.
Scope and evidence
Live Git checkout discovery and immutable execution identities are separate. A missing checkout can keep historical results while becoming unavailable for new execution. Shared fixed configuration is described in settings ownership, not copied into worktree identity.
Use execution, storage, interfaces, Git operations and frontend conventions for their contracts. Current limitations belong beside the affected feature. Historical proposals, superseded decisions, test counts and merge journals remain in Git history, not a second current-state document.
Implementation: composition, core contracts, architecture tests.
Docker runtime access uses the exported Testcontainers runtime clients and checked-in library patch. The delegated operations, patch maintenance and Redpact-owned lifecycle policies are described in execution.