Front-end companion to Dander — a visual editor for Dander's canonical
PipelineGraph files (drag/drop nodes, wire connections, configure sources/transforms/writes).
Druff opens and saves one graph file through Dander's localhost API. Dander owns parsing,
validation, conflict detection, and atomic filesystem writes. When the operator binds that graph
to one manifest pipeline, Druff can also validate it, manually run its already-deployed Cloud Run
job, and show compact execution/run-ledger status. A version-1 dander.yaml can still be imported
as a detached, one-way visualization. When Dander explicitly enables it with complete operator
inputs, Druff can also request a source-free candidate and display its non-applyable Terraform
plan; Druff never writes the manifest or applies infrastructure.
When that manifest pins installed connector plugins, Druff discovers their presentation-safe descriptors from Dander and adds them to the palette dynamically. The first dynamic connector is Salesforce Accounts. Greenhouse remains a static fallback for offline/document-only authoring; Druff never receives API URLs, authentication settings, secret references, or credentials.
See CLAUDE.md and steering/00-project-overview.md for the full picture (why this exists, the
module map, decision log).
Next.js (App Router) + TypeScript · React Flow · Tailwind + shadcn/ui · Zustand · Zod · Monaco · pnpm.
src/ Next.js app (src/app), features (src/features/pipeline-canvas), src/lib
steering/ binding rules for humans + agents (read these)
tickets/ work items
scripts/ dev tooling (e.g. the workflow monitor)
.claude/ agent workforce, feature workflow, /feature command
Prerequisites: Node 22+, pnpm (corepack enable && corepack prepare pnpm@latest --activate).
pnpm install
pnpm dev # http://localhost:3000In a second terminal, select the graph file Dander may expose:
dander graph serve --file /absolute/path/to/pipeline.yamlThen choose Open from Dander. Druff uses explicit Save, shows unsaved/conflict state, and will not overwrite a file that changed after it was opened. Graph YAML formatting and comments may be normalized because Dander writes its canonical model.
To enable the narrow operational controls for one graph that is already deployed, start Dander with its matching manifest pipeline and GCP project:
dander graph serve \
--file /absolute/path/to/graphs/greenhouse_jobs.yaml \
--config /absolute/path/to/dander.yaml \
--pipeline greenhouse_jobs_graph \
--project my-gcp-projectChoose Open from Dander, then Refresh status. Validate and Run are enabled only while the
opened graph is saved and no execution is active. Run uses the operator's local gcloud identity
and targets only the fixed job Dander derived at startup. Use Refresh to read completion and the
latest Dander run-ledger result. These controls do not deploy edits, write dander.yaml, enable a
schedule, or expose cloud credentials to the browser.
To preview the deployment impact of a saved graph, restart the same command with
--enable-deployment-preview, the current billing/cost-guard inputs, and an explicit
--failure-alert-email. Build candidate & plan pushes an Artifact Registry candidate and shows
the exact full-manifest Terraform plan, including every job sharing that image. Save itself remains
file-only. The temporary binary plan is deleted by Dander; Druff cannot apply it or alter a
schedule.
To visualize a hosted Dander project manifest, choose Import graph or dander.yaml and select its
dander.yaml. Druff draws each schedule, source, and selected model. Exported .druff.yaml/JSON
files are editor drafts, not deployable Dander manifests.
pnpm lint # eslint
pnpm typecheck # tsc --noEmit
pnpm format:check # prettier --check .
pnpm test # vitest (unit/component)
pnpm test:e2e # playwright (canvas drag/drop/connect — not reliable under jsdom)
pnpm build # production buildGreen baseline = lint, typecheck, format:check, test, and build all pass. Keep it green; the
pr-review agent enforces it on every ticket.
Features are built by a workforce of agents defined in .claude/ — the feature workflow runs the
loop Product → Design → Code → PR-Review, looping a ticket back to Code with an addendum until
it passes review. See CLAUDE.md for the full picture.
First, register it. .claude/agents/, .claude/workflows/, and .claude/commands/ are loaded
only at Claude Code startup. After cloning (or after editing anything under .claude/),
restart Claude Code in this project root so /feature, the agents, and the workflow become
available by name (until then, invoke by scriptPath: ".claude/workflows/feature.js").
Run it (costs tokens, so each run is an explicit opt-in):
/feature Add a node inspector panel for editing a selected node's properties
(or just ask Claude in chat) run the feature workflow with: <describe the feature>
It writes tickets to tickets/ (lifecycle open → in-design → in-code → in-review → done),
implements + reviews each until PASS, and leaves the code + tests in your working tree.
A workflow run spawns many background agents. scripts/watch_workflows.py is a dependency-free
(stdlib-only) live dashboard — ported from Dander's script of the same name — run it in a
separate terminal while a workflow is going:
python3 scripts/watch_workflows.py # live dashboard, refresh every 2s
python3 scripts/watch_workflows.py --all # include finished / idle runs
python3 scripts/watch_workflows.py -n 5 # refresh every 5s
python3 scripts/watch_workflows.py --once # print one snapshot and exitIt auto-discovers all runs across sessions (so it handles several concurrent workflows), and shows each run's agents with their role, ticket, and live PASS/FAIL verdicts:
● wf_b3fcaba8-cb0 RUNNING elapsed 2m08s agents 1 done, 1 running
✓ product — 6 ticket(s)
▸ design DRUFF-1 working…
Working canonical graph editor with Dander-backed single-file Open/Save, canvas inspectors, validation, source view, static Greenhouse plus dynamically discovered connector configuration, one-way hosted-manifest preview, manual execution/status, and an explicit source-free candidate/full-manifest plan for one operator-bound graph. Manifest write-back and Terraform apply are not implemented.