docs: design workflow console foundation
This commit is contained in:
@@ -42,13 +42,15 @@ Implementation order:
|
|||||||
2. Completed: deterministic `examples/lda_report_workflow/` case study with
|
2. Completed: deterministic `examples/lda_report_workflow/` case study with
|
||||||
local document, report, issue-board sources, and typed issue-review
|
local document, report, issue-board sources, and typed issue-review
|
||||||
interrupt.
|
interrupt.
|
||||||
3. Add a top-level `web/` Astro/Effect app with loopback JSON-RPC connection and
|
3. Add a top-level `web/` pnpm workspace with a React/Vite console, Hono local
|
||||||
method registry.
|
server, Effect JSON-RPC boundary, loopback connection flow, and method
|
||||||
|
registry. Design:
|
||||||
|
[`workflow console foundation`](superpowers/specs/2026-07-01-workflow-console-foundation-design.md).
|
||||||
4. Add console read/inspect views for sources, drafts, artifacts, deployments,
|
4. Add console read/inspect views for sources, drafts, artifacts, deployments,
|
||||||
runs, traces, and raw RPC drawers.
|
runs, traces, and raw RPC drawers.
|
||||||
5. Add lifecycle autoplay, typed approval, issue-board output, and replay.
|
5. Add lifecycle autoplay, typed approval, issue-board output, and replay.
|
||||||
6. Add a constrained demo agent that invokes one prepared recipe macro.
|
6. Add a constrained demo agent that invokes one prepared recipe macro.
|
||||||
7. Add presentation and appendix routes for the 15-minute defense.
|
7. Add an Astro presentation app and appendix routes for the 15-minute defense.
|
||||||
|
|
||||||
Boundaries: this is not a production admin panel, generic visual workflow
|
Boundaries: this is not a production admin panel, generic visual workflow
|
||||||
editor, scheduler, external Google Drive/mail integration, or benchmark evidence
|
editor, scheduler, external Google Drive/mail integration, or benchmark evidence
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ Related:
|
|||||||
- [Workflow API architecture](../../wf_api_architecture.md)
|
- [Workflow API architecture](../../wf_api_architecture.md)
|
||||||
- [Persisted run/resume contract](2026-06-03-persisted-run-resume-contract.md)
|
- [Persisted run/resume contract](2026-06-03-persisted-run-resume-contract.md)
|
||||||
- [Self-describing interrupt contracts](2026-07-01-self-describing-interrupt-contracts.md)
|
- [Self-describing interrupt contracts](2026-07-01-self-describing-interrupt-contracts.md)
|
||||||
|
- [Workflow console foundation design](2026-07-01-workflow-console-foundation-design.md)
|
||||||
- [Thesis system design](../../thesis/system-design-implementation.md)
|
- [Thesis system design](../../thesis/system-design-implementation.md)
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
Build one local-first web application that serves three related needs:
|
Build one local-first web workspace that serves three related needs:
|
||||||
|
|
||||||
1. a reusable Workflow Console for inspecting a running `wf` JSON-RPC server;
|
1. a reusable Workflow Console for inspecting a running `wf` JSON-RPC server;
|
||||||
2. a reliable defense demonstration of the complete workflow lifecycle;
|
2. a reliable defense demonstration of the complete workflow lifecycle;
|
||||||
@@ -38,22 +39,14 @@ Create a top-level `web/` package rather than putting product code under
|
|||||||
```text
|
```text
|
||||||
web/
|
web/
|
||||||
package.json
|
package.json
|
||||||
astro.config.mjs
|
pnpm-workspace.yaml
|
||||||
src/
|
apps/
|
||||||
pages/
|
console/ # React + Vite
|
||||||
connect.astro
|
server/ # Hono + Effect boundary
|
||||||
console/
|
presentation/ # Astro, added in the presentation slice
|
||||||
demo/
|
packages/
|
||||||
replay/
|
rpc/
|
||||||
presentation/
|
ui/ # added only after shared components exist
|
||||||
appendix/
|
|
||||||
components/
|
|
||||||
agent/
|
|
||||||
lifecycle/
|
|
||||||
rpc/
|
|
||||||
trace/
|
|
||||||
workflow-graph/
|
|
||||||
presentation/
|
|
||||||
```
|
```
|
||||||
|
|
||||||
The first release is a local-development Workflow Console. It is not a
|
The first release is a local-development Workflow Console. It is not a
|
||||||
@@ -64,8 +57,8 @@ multi-user administration, or safe access to arbitrary remote servers.
|
|||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TB
|
flowchart TB
|
||||||
Browser[Astro and React UI]
|
Browser[React + Vite UI]
|
||||||
Routes[Astro server routes]
|
Routes[Hono server routes]
|
||||||
Agent[DemoAgent service]
|
Agent[DemoAgent service]
|
||||||
Recipe[Prepared ReportRecipe]
|
Recipe[Prepared ReportRecipe]
|
||||||
Job[LifecycleJob service]
|
Job[LifecycleJob service]
|
||||||
@@ -108,7 +101,7 @@ Use Effect for server-side orchestration and protocol handling:
|
|||||||
- timeouts and retries apply only where semantically safe.
|
- timeouts and retries apply only where semantically safe.
|
||||||
|
|
||||||
Do not spread Effect through every React component. React components consume
|
Do not spread Effect through every React component. React components consume
|
||||||
ordinary view models and event streams. Astro route handlers are the
|
ordinary view models and event streams. Hono route handlers are the
|
||||||
`Effect.runPromise` boundary.
|
`Effect.runPromise` boundary.
|
||||||
|
|
||||||
Mutation calls such as artifact creation, deployment saving, run start, and
|
Mutation calls such as artifact creation, deployment saving, run start, and
|
||||||
@@ -120,11 +113,11 @@ small bounded retry policy.
|
|||||||
The connection page accepts a JSON-RPC URL such as
|
The connection page accepts a JSON-RPC URL such as
|
||||||
`http://127.0.0.1:8765/rpc`.
|
`http://127.0.0.1:8765/rpc`.
|
||||||
|
|
||||||
1. The Astro server validates the URL.
|
1. The Hono server validates the URL.
|
||||||
2. The first slice accepts only loopback hosts.
|
2. The first slice accepts only loopback hosts.
|
||||||
3. `workflow.health` verifies the endpoint.
|
3. `workflow.health` verifies the endpoint.
|
||||||
4. The connection is retained for the browser session.
|
4. The connection is retained for the browser session.
|
||||||
5. Astro proxies JSON-RPC calls server-side to avoid browser CORS coupling.
|
5. Hono proxies JSON-RPC calls server-side to avoid browser CORS coupling.
|
||||||
6. Every call records its raw request, raw response, interpreted result,
|
6. Every call records its raw request, raw response, interpreted result,
|
||||||
duration, and equivalent CLI command.
|
duration, and equivalent CLI command.
|
||||||
|
|
||||||
@@ -188,8 +181,8 @@ The UI uses focus modes instead of showing every panel simultaneously:
|
|||||||
- **Output:** rendered readiness report and created issues.
|
- **Output:** rendered readiness report and created issues.
|
||||||
- **Raw:** collapsible JSON-RPC request and response drawer.
|
- **Raw:** collapsible JSON-RPC request and response drawer.
|
||||||
|
|
||||||
Use an interactive graph component, expected to be `@xyflow/react`, inside an
|
Use an interactive graph component, expected to be `@xyflow/react`, inside the
|
||||||
Astro React island. Static presentation diagrams remain Mermaid.
|
React console. Static presentation diagrams remain Mermaid.
|
||||||
|
|
||||||
A small graph embedded in a lifecycle card can expand into the primary canvas.
|
A small graph embedded in a lifecycle card can expand into the primary canvas.
|
||||||
Selecting a node opens a side drawer with capability, source, bindings,
|
Selecting a node opens a side drawer with capability, source, bindings,
|
||||||
@@ -383,19 +376,21 @@ Routes:
|
|||||||
- `/replay`: recorded fallback;
|
- `/replay`: recorded fallback;
|
||||||
- `/appendix`: backup architecture, evaluation, and implementation slides.
|
- `/appendix`: backup architecture, evaluation, and implementation slides.
|
||||||
|
|
||||||
The presentation transitions directly into the demo and back. The exact slide
|
The presentation transitions directly into the demo and back. Astro may be
|
||||||
library is selected in the presentation slice; the route and shared component
|
added as a separate static presentation app and served by the Hono process. The
|
||||||
boundaries are fixed by this design.
|
exact slide library is selected in the presentation slice; the route and shared
|
||||||
|
component boundaries are fixed by this design.
|
||||||
|
|
||||||
## Implementation Order
|
## Implementation Order
|
||||||
|
|
||||||
1. Self-describing interrupt request/resume contracts.
|
1. Self-describing interrupt request/resume contracts.
|
||||||
2. Deterministic `lda.chat` report workflow and Python sources.
|
2. Deterministic `lda.chat` report workflow and Python sources.
|
||||||
3. `web/` Astro and Effect foundation, connection flow, and RPC registry.
|
3. `web/` React/Vite, Hono, and Effect foundation, connection flow, and RPC
|
||||||
|
registry.
|
||||||
4. Workflow Console read/inspect views, graph, trace, and raw drawers.
|
4. Workflow Console read/inspect views, graph, trace, and raw drawers.
|
||||||
5. Lifecycle job, autoplay, typed approval, issue board, and replay.
|
5. Lifecycle job, autoplay, typed approval, issue board, and replay.
|
||||||
6. Constrained demo agent and replaceable model gateway.
|
6. Constrained demo agent and replaceable model gateway.
|
||||||
7. Defense presentation and appendix routes.
|
7. Astro defense presentation and appendix routes.
|
||||||
|
|
||||||
Each slice gets its own executable implementation plan. Do not combine the
|
Each slice gets its own executable implementation plan. Do not combine the
|
||||||
Python contract change, web foundation, agent integration, and presentation
|
Python contract change, web foundation, agent integration, and presentation
|
||||||
|
|||||||
@@ -0,0 +1,429 @@
|
|||||||
|
# Workflow Console Foundation Design
|
||||||
|
|
||||||
|
Date: 2026-07-01
|
||||||
|
|
||||||
|
Status: Approved design for the first web implementation slice.
|
||||||
|
|
||||||
|
Related:
|
||||||
|
|
||||||
|
- [Workflow console, agent demo, and defense presentation](2026-07-01-workflow-console-agent-demo.md)
|
||||||
|
- [Self-describing interrupt contracts](2026-07-01-self-describing-interrupt-contracts.md)
|
||||||
|
- [Workflow API architecture](../../wf_api_architecture.md)
|
||||||
|
- [Current roadmap](../../current_roadmap.md)
|
||||||
|
|
||||||
|
## Goal
|
||||||
|
|
||||||
|
Create the first executable `web/` slice for lda.chat: a local React console
|
||||||
|
that connects to a loopback `wf-rpc-server` through a small Node proxy, proves
|
||||||
|
typed JSON-RPC decoding with Effect, and presents both interpreted connection
|
||||||
|
state and raw protocol evidence.
|
||||||
|
|
||||||
|
This slice establishes durable package and protocol boundaries. It does not
|
||||||
|
build lifecycle browsing, workflow graphs, autoplay, replay, the demo agent, or
|
||||||
|
the defense presentation.
|
||||||
|
|
||||||
|
## Architecture Decision
|
||||||
|
|
||||||
|
Use an app-first React architecture rather than Astro as the primary console
|
||||||
|
shell:
|
||||||
|
|
||||||
|
- Vite builds and serves the React development application.
|
||||||
|
- Hono provides the local Node HTTP server and production static-file host.
|
||||||
|
- Effect owns URL validation, JSON-RPC schemas, typed errors, and upstream RPC
|
||||||
|
execution.
|
||||||
|
- React consumes plain view models and never runs Effect programs directly.
|
||||||
|
- Astro remains available for a later static presentation application and is
|
||||||
|
not a dependency of the console.
|
||||||
|
|
||||||
|
The Hono server is not a second workflow API. It is a narrow browser-facing
|
||||||
|
adapter over the existing public JSON-RPC endpoint.
|
||||||
|
|
||||||
|
```mermaid
|
||||||
|
flowchart LR
|
||||||
|
Browser[React + Vite console]
|
||||||
|
Hono[Hono local server]
|
||||||
|
Policy[Loopback target policy]
|
||||||
|
Effect[Effect WorkflowRpc service]
|
||||||
|
Rpc[wf-rpc-server]
|
||||||
|
|
||||||
|
Browser -->|POST /api/connect| Hono
|
||||||
|
Browser -->|POST /api/rpc| Hono
|
||||||
|
Hono --> Policy
|
||||||
|
Hono --> Effect
|
||||||
|
Effect -->|JSON-RPC HTTP| Rpc
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workspace Layout
|
||||||
|
|
||||||
|
Create a pnpm workspace under the existing repository root:
|
||||||
|
|
||||||
|
```text
|
||||||
|
web/
|
||||||
|
package.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
pnpm-workspace.yaml
|
||||||
|
tsconfig.base.json
|
||||||
|
apps/
|
||||||
|
console/
|
||||||
|
package.json
|
||||||
|
index.html
|
||||||
|
vite.config.ts
|
||||||
|
src/
|
||||||
|
app/
|
||||||
|
components/
|
||||||
|
connection/
|
||||||
|
rpc/
|
||||||
|
styles/
|
||||||
|
main.tsx
|
||||||
|
server/
|
||||||
|
package.json
|
||||||
|
src/
|
||||||
|
app.ts
|
||||||
|
index.ts
|
||||||
|
static.ts
|
||||||
|
packages/
|
||||||
|
rpc/
|
||||||
|
package.json
|
||||||
|
src/
|
||||||
|
errors.ts
|
||||||
|
method-registry.ts
|
||||||
|
protocol.ts
|
||||||
|
service.ts
|
||||||
|
target-policy.ts
|
||||||
|
index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
The first slice creates only `console`, `server`, and `rpc`. Later slices may
|
||||||
|
add:
|
||||||
|
|
||||||
|
```text
|
||||||
|
web/apps/presentation/ # Astro presentation and appendix routes
|
||||||
|
web/packages/ui/ # shared components after real reuse exists
|
||||||
|
```
|
||||||
|
|
||||||
|
Do not create empty placeholder packages for future work.
|
||||||
|
|
||||||
|
The root package pins `[email protected]`. The supported runtime is Node.js 22 or
|
||||||
|
newer; the current development environment uses Node.js 26.
|
||||||
|
|
||||||
|
## Process Model
|
||||||
|
|
||||||
|
Development uses two processes started through one root command:
|
||||||
|
|
||||||
|
1. Vite serves the React application with hot reload.
|
||||||
|
2. Hono serves `/api/*` and proxies validated JSON-RPC calls.
|
||||||
|
|
||||||
|
Vite forwards `/api/*` to Hono during development. The browser therefore uses
|
||||||
|
one apparent origin and does not depend on Python CORS configuration.
|
||||||
|
|
||||||
|
Production uses one Hono process:
|
||||||
|
|
||||||
|
1. Vite builds static assets.
|
||||||
|
2. Hono serves the Vite output.
|
||||||
|
3. Hono retains the same `/api/*` routes.
|
||||||
|
4. Unknown non-API paths fall back to `index.html` for client routing.
|
||||||
|
|
||||||
|
The first slice does not start or supervise `wf-rpc-server`. Operators run it
|
||||||
|
separately and paste its loopback JSON-RPC URL into the console.
|
||||||
|
|
||||||
|
## Connection Contract
|
||||||
|
|
||||||
|
The connection form accepts a URL such as:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://127.0.0.1:8765/rpc
|
||||||
|
```
|
||||||
|
|
||||||
|
Accepted targets must satisfy all rules:
|
||||||
|
|
||||||
|
- scheme is `http`;
|
||||||
|
- hostname is exactly `127.0.0.1`, `localhost`, or `[::1]`/`::1` after URL
|
||||||
|
parsing;
|
||||||
|
- username and password are absent;
|
||||||
|
- port is explicit and in the valid TCP port range;
|
||||||
|
- URL has no query string or fragment;
|
||||||
|
- redirects are not followed by the upstream fetch;
|
||||||
|
- the normalized URL is validated again for every proxy request.
|
||||||
|
|
||||||
|
`POST /api/connect` accepts:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"target": "http://127.0.0.1:8765/rpc"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It sends `workflow.health` with an empty params object and returns a view model:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"connection": {
|
||||||
|
"status": "connected",
|
||||||
|
"target": "http://127.0.0.1:8765/rpc",
|
||||||
|
"serverStatus": "ok",
|
||||||
|
"durationMs": 12
|
||||||
|
},
|
||||||
|
"exchange": {
|
||||||
|
"request": {},
|
||||||
|
"response": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The exact raw JSON-RPC request and response are retained inside `exchange`.
|
||||||
|
They are omitted from the compact connection card but available in the raw
|
||||||
|
drawer.
|
||||||
|
|
||||||
|
The browser stores only the normalized target URL in `sessionStorage`. The
|
||||||
|
server remains stateless: every `/api/rpc` request carries the target and is
|
||||||
|
validated again. No cookies, server sessions, authentication tokens, or target
|
||||||
|
registry are introduced in this slice.
|
||||||
|
|
||||||
|
## JSON-RPC Contract
|
||||||
|
|
||||||
|
The RPC package defines Effect schemas for:
|
||||||
|
|
||||||
|
- JSON-RPC request envelopes;
|
||||||
|
- success response envelopes;
|
||||||
|
- error response envelopes;
|
||||||
|
- `workflow.health` results;
|
||||||
|
- `workflow.sources.list` parameters and the selected result fields required by
|
||||||
|
the first console screen.
|
||||||
|
|
||||||
|
The request id is generated by the server adapter and represented as a string.
|
||||||
|
Responses must have `jsonrpc: "2.0"`, the matching id, and exactly one of
|
||||||
|
`result` or `error`.
|
||||||
|
|
||||||
|
The first method registry contains two entries:
|
||||||
|
|
||||||
|
```text
|
||||||
|
workflow.health
|
||||||
|
workflow.sources.list
|
||||||
|
```
|
||||||
|
|
||||||
|
Each registry entry includes:
|
||||||
|
|
||||||
|
- method name;
|
||||||
|
- parameter schema;
|
||||||
|
- result schema;
|
||||||
|
- human label and explanation;
|
||||||
|
- idempotency classification;
|
||||||
|
- equivalent CLI formatter;
|
||||||
|
- result-to-view-model interpreter.
|
||||||
|
|
||||||
|
Unknown methods are rejected by the Hono adapter. This is a mapped console
|
||||||
|
surface, not an unrestricted arbitrary JSON-RPC relay.
|
||||||
|
|
||||||
|
## Server API
|
||||||
|
|
||||||
|
The first Hono application exposes:
|
||||||
|
|
||||||
|
- `GET /api/health`: confirms the web server itself is running;
|
||||||
|
- `POST /api/connect`: validates a target and calls `workflow.health`;
|
||||||
|
- `POST /api/rpc`: invokes one registered read-only JSON-RPC operation;
|
||||||
|
- static Vite assets and SPA fallback in production.
|
||||||
|
|
||||||
|
`POST /api/rpc` accepts:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"target": "http://127.0.0.1:8765/rpc",
|
||||||
|
"operation": "workflow.sources.list",
|
||||||
|
"params": {}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
It returns:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": true,
|
||||||
|
"operation": "workflow.sources.list",
|
||||||
|
"label": "List sources",
|
||||||
|
"interpreted": {},
|
||||||
|
"exchange": {
|
||||||
|
"request": {},
|
||||||
|
"response": {}
|
||||||
|
},
|
||||||
|
"equivalentCli": "uv run wf source list",
|
||||||
|
"durationMs": 8
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The server accepts only registry operations. It does not accept a raw method
|
||||||
|
string supplied directly by the browser.
|
||||||
|
|
||||||
|
Failures use one browser-facing shape:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ok": false,
|
||||||
|
"error": {
|
||||||
|
"code": "upstream_unreachable",
|
||||||
|
"message": "Could not connect to the workflow RPC server."
|
||||||
|
},
|
||||||
|
"exchange": {
|
||||||
|
"request": {},
|
||||||
|
"response": null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
HTTP status mapping is fixed:
|
||||||
|
|
||||||
|
- `400`: invalid target, unknown operation, or invalid browser request;
|
||||||
|
- `502`: upstream connection, JSON-RPC remote, protocol, or decode failure;
|
||||||
|
- `504`: upstream timeout.
|
||||||
|
|
||||||
|
An upstream JSON-RPC error remains visible in the raw exchange but is mapped to
|
||||||
|
a safe browser-facing code and message.
|
||||||
|
|
||||||
|
## Effect Boundary
|
||||||
|
|
||||||
|
Effect is confined to `web/packages/rpc` and the Hono handler boundary.
|
||||||
|
|
||||||
|
Services:
|
||||||
|
|
||||||
|
- `TargetPolicy`: parse and validate loopback RPC targets;
|
||||||
|
- `WorkflowRpc`: execute one registered JSON-RPC call;
|
||||||
|
- `MethodRegistry`: resolve operation metadata and schemas;
|
||||||
|
- `Clock` through Effect for measured duration and deterministic tests.
|
||||||
|
|
||||||
|
Tagged errors:
|
||||||
|
|
||||||
|
- `InvalidTargetError`;
|
||||||
|
- `UnknownOperationError`;
|
||||||
|
- `UpstreamConnectionError`;
|
||||||
|
- `UpstreamTimeoutError`;
|
||||||
|
- `RpcProtocolError`;
|
||||||
|
- `RpcRemoteError`;
|
||||||
|
- `RpcDecodeError`.
|
||||||
|
|
||||||
|
Hono handlers call `Effect.runPromise` once per request and map tagged errors to
|
||||||
|
stable HTTP responses. React receives JSON DTOs and ordinary discriminated
|
||||||
|
unions, not Effect values, causes, layers, or services.
|
||||||
|
|
||||||
|
No retries are applied in this slice. Even health and list operations should
|
||||||
|
report the first real failure so connection diagnostics remain honest.
|
||||||
|
|
||||||
|
## Console UI
|
||||||
|
|
||||||
|
The first page has three regions:
|
||||||
|
|
||||||
|
1. **Connection header**: target URL, connect/reconnect action, connection
|
||||||
|
status, server status, and measured duration.
|
||||||
|
2. **Source inventory**: a compact read-only list produced by
|
||||||
|
`workflow.sources.list` after connection succeeds.
|
||||||
|
3. **Protocol evidence**: a collapsible drawer showing the selected operation,
|
||||||
|
equivalent CLI, raw request, raw response, and any typed error.
|
||||||
|
|
||||||
|
The UI must distinguish:
|
||||||
|
|
||||||
|
- not configured;
|
||||||
|
- connecting;
|
||||||
|
- connected;
|
||||||
|
- invalid target;
|
||||||
|
- unreachable server;
|
||||||
|
- JSON-RPC remote error;
|
||||||
|
- malformed response.
|
||||||
|
|
||||||
|
Connection failures keep the entered URL editable. Reconnect replaces the
|
||||||
|
session target only after a successful health call. Reload restores the last
|
||||||
|
successful target from `sessionStorage` but does not silently call it until the
|
||||||
|
user reconnects.
|
||||||
|
|
||||||
|
The first slice uses React local state and reducers. Do not add Redux, Zustand,
|
||||||
|
Pinia, XState, TanStack Query, or a client Effect runtime before lifecycle data
|
||||||
|
creates a demonstrated need.
|
||||||
|
|
||||||
|
## Visual Direction
|
||||||
|
|
||||||
|
The console should look like an operational instrument, not a generic admin
|
||||||
|
template:
|
||||||
|
|
||||||
|
- warm off-white workspace background with a subtle technical grid;
|
||||||
|
- ink, slate, signal green, amber, and red tokens;
|
||||||
|
- expressive condensed heading face paired with a readable technical body
|
||||||
|
face;
|
||||||
|
- dense but calm source rows;
|
||||||
|
- raw evidence presented as an intentional inspection surface, not a debug
|
||||||
|
afterthought;
|
||||||
|
- desktop-first layout that remains usable on a narrow laptop or tablet.
|
||||||
|
|
||||||
|
Avoid dark-mode-first styling, purple gradients, interchangeable dashboard
|
||||||
|
cards, and motion without semantic purpose. The first meaningful animation is
|
||||||
|
the connection transition and staggered source reveal.
|
||||||
|
|
||||||
|
## Error And Security Boundaries
|
||||||
|
|
||||||
|
- The proxy never forwards non-loopback URLs.
|
||||||
|
- Upstream redirects are rejected rather than followed.
|
||||||
|
- Browser request bodies are limited to 256 KiB.
|
||||||
|
- Upstream response bodies are limited to 4 MiB.
|
||||||
|
- Upstream calls have a five-second timeout and abort signal.
|
||||||
|
- Raw evidence is JSON-serialized and rendered as text, never inserted as HTML.
|
||||||
|
- Hono error responses contain a stable error code and safe message; stack
|
||||||
|
traces remain server-side.
|
||||||
|
- The app binds to loopback by default.
|
||||||
|
- This slice does not claim authentication or protection from other local
|
||||||
|
processes running as the same user.
|
||||||
|
|
||||||
|
## Testing Strategy
|
||||||
|
|
||||||
|
Use Vitest for all TypeScript tests and React Testing Library for component
|
||||||
|
behavior.
|
||||||
|
|
||||||
|
Required tests:
|
||||||
|
|
||||||
|
- target policy accepts the three loopback host forms and rejects remote,
|
||||||
|
credentialed, query, fragment, implicit-port, and redirect targets;
|
||||||
|
- JSON-RPC schemas accept valid success/error envelopes and reject mismatched
|
||||||
|
ids or malformed envelopes;
|
||||||
|
- method registry exposes only health and source-list operations;
|
||||||
|
- Hono connect route returns interpreted and raw health data through an injected
|
||||||
|
fake upstream fetch;
|
||||||
|
- Hono RPC route rejects unknown operations before any fetch;
|
||||||
|
- Hono maps timeout, connection, remote RPC, and decode failures to stable error
|
||||||
|
DTOs;
|
||||||
|
- React connection form preserves failed input and persists only successful
|
||||||
|
normalized targets;
|
||||||
|
- source inventory renders interpreted source rows;
|
||||||
|
- raw evidence drawer exposes request, response, and equivalent CLI;
|
||||||
|
- production build completes and the Hono static fallback serves the console.
|
||||||
|
|
||||||
|
Do not require a live Python server in the default frontend test suite. Add a
|
||||||
|
documented optional smoke command against:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
uv run wf-rpc-server --config wf.config.json --host 127.0.0.1 --port 8765
|
||||||
|
```
|
||||||
|
|
||||||
|
## First-Slice Success Criteria
|
||||||
|
|
||||||
|
The foundation slice is complete when:
|
||||||
|
|
||||||
|
1. `pnpm --dir web install`, test, typecheck, and build commands are documented
|
||||||
|
and pass;
|
||||||
|
2. one root development command starts Vite and Hono;
|
||||||
|
3. a user can enter a loopback RPC URL and receive interpreted
|
||||||
|
`workflow.health` state;
|
||||||
|
4. a connected user can list workflow sources;
|
||||||
|
5. every displayed operation has raw request/response evidence and an
|
||||||
|
equivalent CLI string;
|
||||||
|
6. unknown methods and non-loopback targets fail before upstream fetch;
|
||||||
|
7. the production Hono process serves the built React application;
|
||||||
|
8. no Python CORS change, direct store access, workflow mutation, graph UI,
|
||||||
|
autoplay, replay, or agent integration is included.
|
||||||
|
|
||||||
|
## Deferred Slices
|
||||||
|
|
||||||
|
After this foundation:
|
||||||
|
|
||||||
|
1. read-only lifecycle inspectors for drafts, artifacts, deployments, runs,
|
||||||
|
traces, and graph rendering;
|
||||||
|
2. prepared lifecycle job, autoplay, typed interrupt form, issue-board output,
|
||||||
|
and replay;
|
||||||
|
3. constrained demo agent and recipe macro;
|
||||||
|
4. Astro presentation and appendix app consuming shared React components only
|
||||||
|
where interactivity is useful.
|
||||||
Reference in New Issue
Block a user