|
1 | 1 | # CLAUDE.md |
2 | 2 |
|
3 | | -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 3 | +This file provides guidance to Claude Code when working in this repository. |
4 | 4 |
|
5 | 5 | ## Project Overview |
6 | 6 |
|
7 | | -Visual workflow builder for agentic LLM pipelines. Users drag-and-drop nodes (Start, Agent, If/Else, Approval) onto a canvas, connect them, configure LLM prompts and branching logic, then execute workflows server-side against OpenAI. Run results are persisted as JSON audit trails. |
| 7 | +AgentFlow is a visual workflow editor and runtime for LLM pipelines. |
8 | 8 |
|
9 | | -## Monorepo Layout |
| 9 | +Users compose workflows with `Start`, `Agent`, `Condition`, and `Approval` nodes, then execute server-side with persisted run records. |
| 10 | +In the UI, `Condition` maps to runtime node type `"if"` in workflow JSON and persisted run records. |
10 | 11 |
|
11 | | -npm workspace monorepo: |
| 12 | +## Monorepo Layout |
12 | 13 |
|
13 | 14 | | Package | Purpose | |
14 | | -|---------|---------| |
15 | | -| `packages/types` | Shared TypeScript contracts (`WorkflowNode`, `WorkflowGraph`, `WorkflowRunResult`, etc.) | |
16 | | -| `packages/workflow-engine` | Pure runtime executor (`WorkflowEngine` class, `WorkflowLLM` interface) — no OpenAI dependency | |
17 | | -| `apps/server` | Express API + Vite dev middleware. Routes: `POST /api/run`, `POST /api/run-stream`, `POST /api/resume`, `GET /api/config`, `GET /api/default-workflow` | |
18 | | -| `apps/web` | Vite SPA — `WorkflowEditor` class handles canvas, node palette, and run console | |
19 | | -| `design-system/` | Git submodule (CodeSignal DS) — CSS tokens and components consumed by web app | |
| 15 | +| --- | --- | |
| 16 | +| `packages/types` | Shared TypeScript contracts (`WorkflowGraph`, `WorkflowRunResult`, etc.) | |
| 17 | +| `packages/workflow-engine` | Runtime executor (`WorkflowEngine`, `WorkflowLLM`) | |
| 18 | +| `apps/server` | Express API + Vite middleware/static hosting | |
| 19 | +| `apps/web` | Vite SPA editor (`WorkflowEditor`) | |
| 20 | +| `design-system/` | Git submodule for UI foundations/components | |
| 21 | + |
| 22 | +## API Surface |
| 23 | + |
| 24 | +- `POST /api/run-stream` |
| 25 | +- `POST /api/run` |
| 26 | +- `POST /api/resume-stream` |
| 27 | +- `POST /api/resume` |
| 28 | +- `GET /api/run/:runId` |
| 29 | +- `GET /api/config` |
| 30 | +- `GET /api/default-workflow` |
20 | 31 |
|
21 | 32 | ## Common Commands |
22 | 33 |
|
23 | 34 | ```bash |
24 | | -npm install # Install all workspace deps |
25 | | -npm run dev # Start integrated server+UI on http://localhost:3000 |
26 | | -npm run build # Build packages → server → web (production) |
27 | | -npm run lint # ESLint across all TypeScript |
28 | | -npm run typecheck # tsc --noEmit for server and web |
29 | | -npm test # Run workflow-engine + server tests |
30 | | - |
31 | | -# Workspace-specific |
32 | | -npm --workspace apps/web run test # Vitest for web |
33 | | -npm --workspace packages/workflow-engine run test # Engine tests |
34 | | -npm run build:packages # Build only shared packages (types + engine) |
| 35 | +npm install |
| 36 | +npm run dev |
| 37 | +npm run build |
| 38 | +npm run build:packages |
| 39 | +npm run lint |
| 40 | +npm run typecheck |
| 41 | +npm test |
| 42 | + |
| 43 | +npm --workspace apps/web run test |
35 | 44 | ``` |
36 | 45 |
|
37 | | -## Architecture |
38 | | - |
39 | | -**Request flow (streaming):** Browser (`api.ts` `runWorkflowStream`) → `POST /api/run-stream` → `WorkflowEngine.run()` with `onLog` callback → each `WorkflowLogEntry` is streamed to the client as an SSE event → final result persisted to `data/runs/run_<id>.json` → `done` event sent to close stream. This is the primary run path — the UI renders agent responses progressively as they arrive. |
40 | | - |
41 | | -**Request flow (batch):** `POST /api/run` runs the same engine synchronously and returns the full `WorkflowRunResult` as JSON. Still available but not used by the default UI. |
42 | | - |
43 | | -**Approval/pause flow:** When engine hits an Approval node, it sets `waitingForInput=true` and the engine instance is stored in an in-memory `Map` (`store/active-workflows.ts`). Client calls `POST /api/resume` with user input to continue. |
| 46 | +## Architecture Notes |
44 | 47 |
|
45 | | -**Agent backend:** Server agent execution is implemented through OpenAI Agents SDK (`apps/server/src/services/openai-agents-llm.ts`). Agent runs are capped with `maxTurns: 20` to bound loop iterations. |
| 48 | +## Execution path |
46 | 49 |
|
47 | | -**Subagent hierarchy:** Agent nodes may expose other agent nodes as tools through subagent links. These links are not execution-flow edges. The subagent graph must be acyclic, and subagent targets are tool-only (no regular execution edges). |
| 50 | +Primary path is streaming: |
48 | 51 |
|
49 | | -**Build dependency chain:** `packages/types` → `packages/workflow-engine` → `apps/server` / `apps/web`. Always run `build:packages` before typechecking or building apps. |
| 52 | +`apps/web` -> `POST /api/run-stream` -> `WorkflowEngine.run()` -> SSE log events -> persisted run record -> final `done` event. |
50 | 53 |
|
51 | | -## Design System (Git Submodule) |
| 54 | +Resume follows equivalent streaming path through `POST /api/resume-stream`. |
52 | 55 |
|
53 | | -`design-system/` is a CodeSignal design system git submodule. It is the **source of truth** for all UI primitives — always prefer existing DS tokens and components over custom CSS or new UI elements. If a needed component doesn't exist in the DS, consult the user before adding alternatives. |
| 56 | +## Persistence |
54 | 57 |
|
55 | | -### Token layers |
| 58 | +Each run/resume operation persists `data/runs/run_<runId>.json` with: |
56 | 59 |
|
57 | | -Tokens live in three foundation files linked as static CSS in `apps/web/index.html`: |
| 60 | +- workflow graph |
| 61 | +- logs |
| 62 | +- status |
| 63 | +- state snapshot |
| 64 | +- `currentNodeId` |
| 65 | +- `waitingForInput` |
58 | 66 |
|
59 | | -- **Colors** (`colors/colors.css`): Two-tier system — base scales (`--Colors-Base-Primary-700`) and semantic names (`--Colors-Backgrounds-Main-Default`, `--Colors-Text-Body-Strong`, `--Colors-Stroke-Default`, etc.). Dark mode is automatic via `@media (prefers-color-scheme: dark)`. |
60 | | -- **Spacing** (`spacing/spacing.css`): Spacing scale `--UI-Spacing-spacing-{none|min|xxs|xs|s|mxs|ms|m|ml|mxl|l|xl|xxl|xxxl|4xl|max}`, border radii `--UI-Radius-radius-{size}`, and input heights `--UI-Input-{min|xs|sm|md|lg}`. |
61 | | -- **Typography** (`typography/typography.css`): Font families (`--body-family`, `--heading-family`, `--code-family`), size variables (`--Fonts-Body-Default-md`), and utility classes (`.body-small`, `.heading-xxxsmall`, `.label-small`, `.code`). |
| 67 | +## Paused-run restoration |
62 | 68 |
|
63 | | -### Component CSS + JS |
| 69 | +On server startup, paused runs are rehydrated into in-memory active workflow map when restore fields are present. |
64 | 70 |
|
65 | | -Component CSS is loaded statically in `index.html` (button, boxes, dropdown, icons, input, modal, split-panel, tags). Interactive components with JS (Dropdown, Modal, SplitPanel) are **lazy-loaded at runtime** via dynamic `import()` from the submodule path: |
| 71 | +## Subagent hierarchy |
66 | 72 |
|
67 | | -```typescript |
68 | | -// Pattern used in workflow-editor.ts |
69 | | -const mod = await import(`${origin}/design-system/components/dropdown/dropdown.js`); |
70 | | -const DropdownCtor = mod.default; |
71 | | -const dropdown = new DropdownCtor(container, { items, selectedValue, onSelect }); |
72 | | -``` |
73 | | - |
74 | | -Components currently used in the web app: |
75 | | -- **SplitPanel** — main layout (canvas left, run console right). Constructor: `new SplitPanel(el, { initialSplit, minLeft, minRight })`. |
76 | | -- **Dropdown** — model and reasoning-effort selectors. Constructor: `new Dropdown(el, { items, selectedValue, placeholder, width, onSelect })`. |
77 | | -- **Modal** — help dialog, confirmation prompts. Constructor: `new Modal({ size, title, content, footerButtons })`. Also `Modal.createHelpModal()` factory. |
78 | | -- **Button** — pure CSS (`.button .button-primary`, `.button-secondary`, `.button-danger`, sizes via `.button-small`/`.button-xsmall`). |
79 | | -- **Input** — pure CSS (`.input` for text/number, `.input-checkbox` / `.input-radio` with wrapper structure). |
80 | | - |
81 | | -### Styling rules for the web app |
| 73 | +Subagent links are tool-delegation edges (`sourceHandle: "subagent"`), not execution edges. Hierarchy must be acyclic and subagent targets are tool-only nodes. |
82 | 74 |
|
83 | | -`apps/web/src/workflow-editor.css` consumes DS tokens throughout. When writing new CSS: |
84 | | -- Use semantic color tokens (`--Colors-Backgrounds-Main-Top`, `--Colors-Stroke-Default`) rather than base scales or raw hex values. |
85 | | -- Use spacing tokens (`--UI-Spacing-spacing-s`) instead of hardcoded pixel values. |
86 | | -- Use radius tokens (`--UI-Radius-radius-xs`) for border-radius. |
87 | | -- Use typography variables/classes (`--body-family`, `.body-small`) for font styling. |
| 75 | +## Design System |
88 | 76 |
|
89 | | -## Coding Conventions |
| 77 | +`design-system/` is a git submodule and source of truth for UI primitives. |
90 | 78 |
|
91 | | -- TypeScript strict mode everywhere. Use `import type` (enforced by `@typescript-eslint/consistent-type-imports`). |
92 | | -- File naming: kebab-case. Classes: PascalCase. Constants: UPPER_SNAKE_CASE. |
93 | | -- Prefix unused parameters with `_`. |
94 | | -- Tests: `*.test.ts` co-located near the feature. Vitest for web, CI runs lint → build:packages → typecheck → build. |
95 | | -- Commits: short imperative subjects, Conventional Commit prefixes (`feat(web):`, `fix:`, `chore:`). |
| 79 | +- CSS tokens/components are linked in `apps/web/index.html`. |
| 80 | +- Interactive DS components are dynamically imported in `workflow-editor.ts`. |
| 81 | +- `apps/web/public/design-system` is a symlink to root submodule. |
96 | 82 |
|
97 | | -## Local Configuration (`.config/`) |
| 83 | +Initialize submodule in fresh worktrees: |
98 | 84 |
|
99 | | -The `.config/` directory holds developer-local files that are partially gitignored: |
| 85 | +```bash |
| 86 | +git submodule update --init --recursive |
| 87 | +``` |
100 | 88 |
|
101 | | -- **`config.json`** *(committed)* — provider and model definitions. The server serves this via `GET /api/config`; the web app loads it on startup to populate the model and reasoning-effort dropdowns. Structure: `{ providers: [{ id, name, enabled, models: [{ id, name, reasoningEfforts[] }] }] }`. |
102 | | -- **`default-workflow.json`** *(gitignored)* — optional startup workflow. If present, the editor loads it instead of the blank Start node. Same `{ nodes, connections }` shape as a run record's `workflow` field. |
| 89 | +## Configuration |
103 | 90 |
|
104 | | -Agent node `userPrompt` fields support `{{PREVIOUS_OUTPUT}}` as a template token, which is substituted with the previous node's output before the LLM is called. |
| 91 | +- `OPENAI_API_KEY`: required for agent-node execution. |
| 92 | +- `PORT`: server port (default `3000`). |
| 93 | +- `PROJECT_ROOT`: optional root override. |
| 94 | +- `.config/config.json`: provider/model config served by API. |
| 95 | +- `.config/default-workflow.json`: optional startup workflow (gitignored). |
105 | 96 |
|
106 | | -## Environment |
| 97 | +## References |
107 | 98 |
|
108 | | -- Requires Node.js 20+. |
109 | | -- `OPENAI_API_KEY` must be exported in your shell for Agent node execution. |
110 | | -- `data/runs/` is gitignored — created automatically at runtime. |
111 | | -- `.config/default-workflow.json` is gitignored — create it locally to preload a workflow on startup. |
112 | | -- Clone with `--recurse-submodules` to pull the design-system submodule. |
113 | | -- In a brand new git worktree, run `git submodule update --init --recursive` before development so the design-system submodule is available. |
| 99 | +- `docs/README.md` |
| 100 | +- `docs/architecture.md` |
| 101 | +- `docs/api.md` |
| 102 | +- `docs/workflow-semantics.md` |
| 103 | +- `docs/run-persistence.md` |
| 104 | +- `docs/configuration.md` |
| 105 | +- `docs/troubleshooting.md` |
| 106 | +- `apps/web/docs/run-readiness.md` |
0 commit comments