These rules apply to files under apps/sim/ in addition to the repository root AGENTS.md.
- Single Responsibility: Each component, hook, store has one clear purpose
- Composition Over Complexity: Break down complex logic into smaller pieces
- Type Safety First: TypeScript interfaces for all props, state, return types
- Predictable State: Zustand for global state, useState for UI-only concerns
apps/sim/
├── app/ # Next.js app router (pages, API routes)
├── blocks/ # Block definitions and registry
├── components/ # Shared UI (emcn/, ui/)
├── executor/ # Workflow execution engine
├── hooks/ # Shared hooks (queries/, selectors/)
├── lib/ # App-wide utilities
├── providers/ # LLM provider integrations
├── stores/ # Zustand stores
├── tools/ # Tool definitions
└── triggers/ # Trigger definitions
Features live under app/workspace/[workspaceId]/:
feature/
├── components/ # Feature components
├── hooks/ # Feature-scoped hooks
├── utils/ # Feature-scoped utilities (2+ consumers)
├── feature.tsx # Main component
└── page.tsx # Next.js page entry
- Components: PascalCase (
WorkflowList) - Hooks:
useprefix (useWorkflowOperations) - Files: kebab-case (
workflow-list.tsx) - Stores:
stores/feature/store.ts - Constants: SCREAMING_SNAKE_CASE
- Interfaces: PascalCase with suffix (
WorkflowListProps)
- Always use absolute imports from
@/...; do not add relative imports. - Use barrel exports only when a folder has 3+ exports; do not re-export through non-barrel files.
- Use
import typefor type-only imports. - Do not use
any; prefer precise types orunknownwith guards.
- Use
'use client'only when hooks or browser-only APIs are required. - Define a props interface for every component.
- Extract constants with
as constwhere appropriate. - Use Tailwind classes and
cn()for conditional classes; avoid inline styles unless CSS variables are the intended mechanism. - Keep styling local to the component; do not modify global styles for feature work.
- Use Vitest.
- Prefer
@vitest-environment nodeunless DOM APIs are required. - Use
vi.hoisted()+vi.mock()+ static imports; do not usevi.resetModules()+vi.doMock()+ dynamic imports except for true module-scope singletons. - Do not use
vi.importActual(). - Prefer mocks and factories from
@sim/testing.
- Never create
utils.tsfor single consumer - inline it - Create
utils.tswhen 2+ files need the same helper - Check existing sources before duplicating (
lib/has many utilities) - Location:
lib/(app-wide) →feature/utils/(feature-scoped) → inline (single-use)