Thank you for your interest in contributing! This guide will help you get started.
- Bun ≥ 1.3.10
git clone https://github.com/anthropics/nexus-workflow-studio.git
cd nexus-workflow-studio
bun install
bun run dev| Script | Description |
|---|---|
bun run dev |
Start the development server |
bun run build |
Build for production |
bun run start |
Start the production server |
bun run lint |
Run ESLint |
bun run typecheck |
Run TypeScript type checking |
bun run test |
Run the full test suite |
bun run test:store |
Run store-domain tests |
bun run test:lib |
Run shared library tests |
bun run test:nodes |
Run node-module tests |
bun run check |
Run typecheck, lint, and tests together |
The project uses a modular node architecture — each node type is a self-contained module under src/nodes/ that exports its schema, component, fields, generator, and registry entry.
src/store/— Zustand stores for workflow state and library statesrc/lib/— Core utilities (node registry, persistence, code generation, theme)src/hooks/— Shared React hooks (canvas interactions, auto-layout, etc.)src/nodes/— Node type modules (each with constants, fields, generator, types)src/components/workflow/— Workflow editor UI components
Each node type is a module under src/nodes/<node-type>/ with these files:
import type { BaseNodeData } from "@/types/workflow";
export interface MyNodeData extends BaseNodeData {
type: "my-node";
myField: string;
}import { z } from "zod/v4";
import { NodeCategory } from "@/nodes/shared/registry-types";
import type { NodeRegistryEntry } from "@/nodes/shared/registry-types";
import { NodeSize } from "@/nodes/shared/base-node";
import { MyIcon } from "lucide-react";
export const myNodeSchema = z.object({
type: z.literal("my-node"),
label: z.string().min(1),
name: z.string(),
myField: z.string(),
});
export const myNodeRegistryEntry: NodeRegistryEntry = {
type: "my-node",
displayName: "My Node",
description: "Description here",
icon: MyIcon,
accentHex: "#ffffff",
size: NodeSize.Medium,
category: NodeCategory.Basic,
defaultData: () => ({
type: "my-node" as const,
label: "My Node",
myField: "",
}),
};After creating the module, register it in:
src/lib/node-registry.tssrc/types/workflow.ts(add toNodeTypeunion)src/components/workflow/properties/type-specific-fields.tsx
- Fork the repository and create a feature branch from
main - Make your changes with clear, descriptive commits
- Ensure
bun run lintandbun run typecheckpass - Ensure
bun run buildsucceeds - Update documentation if you've changed public APIs
- Submit a PR with a clear description of the change
Use a hybrid test layout so tests stay close to the domain they protect without scattering shared store coverage across the repo.
src/store/__tests__/— keep store tests centralized and grouped by domain barrel:workflow/prompt-gen/workflow-gen/opencode/library/(when library-specific store tests are added)compat/for legacy shim/backward-compatibility coverage only
src/nodes/<node-type>/__tests__/— colocate tests with the node module they validatesrc/lib/__tests__/— keep cross-cutting utility tests here until a lib subfolder becomes large enough to justify its own__tests__/folder
- Test the public domain where teammates will look first.
- Example: store helper tests should live under
src/store/__tests__/workflow/, not under a legacy shim path.
- Example: store helper tests should live under
- Keep compatibility tests separate from feature tests.
- Shim/export parity belongs in
src/store/__tests__/compat/because it spans multiple domains.
- Shim/export parity belongs in
- Colocate feature-specific tests when the feature owns the logic.
- Node-specific parsing, utils, generators, and field logic belong next to that node.
- Prefer folder-level grouping over filename prefixes once a domain has multiple tests.
workflow/helpers.test.tsandworkflow/subworkflow.test.tsscale better than flat names likeworkflow-store-helpers.test.ts.
- Mirror canonical exports, not deprecated shims.
- New tests should import from canonical entrypoints such as
@/store/workflow,@/store/prompt-gen,@/store/opencode, and@/store/library.
- New tests should import from canonical entrypoints such as
- When a domain grows past a few tests, add a subfolder instead of inventing longer filenames.
- Keep one test file focused on one primary module or behavior.
- Add regression tests for extracted helpers before removing compatibility shims or moving files.
- If UI tests are introduced later, colocate them under the feature directory instead of expanding
src/store/__tests__/for component behavior.
- TypeScript strict mode
- Functional React components with hooks
- Zustand for state management (individual selectors preferred over object destructuring)
- Zod v4 for schema validation (import from
"zod/v4") - Tailwind CSS for styling (dark theme)
- Lucide React for icons
Use GitHub Issues for bug reports and feature requests. Please include:
- Steps to reproduce (for bugs)
- Expected vs actual behavior
- Browser and OS information
- Screenshots if applicable
This project follows the Contributor Covenant Code of Conduct. By participating, you are expected to uphold this code.