# struere add

> Scaffold new agents, data types, roles, and automations

The `add` command scaffolds a new resource file with a starter template in the appropriate directory.

## Usage

```bash
bunx struere add <type> <name>
```

## Resource Types

| Type | Directory | Definition Function |
|------|-----------|-------------------|
| `agent` | `agents/` | `defineAgent()` |
| `data-type` | `entity-types/` | `defineData()` |
| `role` | `roles/` | `defineRole()` |
| `trigger` | `triggers/` | `defineTrigger()` |
| `workflow` | `workflows/` | `workflow()` builder |
| `eval` / `suite` | `evals/` | `defineEvalSuite()` |
| `router` | `routers/` | `defineRouter()` |
| `view` | `views/` | `defineView()` |
| `fixture` | `fixtures/` | YAML fixture definition |

## Examples

### Scaffold an Agent

```bash
bunx struere add agent scheduler
```

Creates `agents/scheduler.ts`:

```typescript
import { defineAgent } from 'struere'

export default defineAgent({
  name: "Scheduler",
  slug: "scheduler",
  version: "0.1.0",
  description: "Scheduler Agent",
  model: {
    model: "openai/gpt-5-mini",
    temperature: 0.7,
    maxTokens: 4096,
  },
  systemPrompt: `You are {{agentName}}, an AI assistant for {{organizationName}}.

Current time: {{currentTime}}

Your capabilities:
- Answer questions accurately and helpfully
- Use available tools when appropriate
- Maintain conversation context

Always be concise, accurate, and helpful.`,
  tools: ["entity.query", "entity.get"],
})
```

### Scaffold a Data Type

```bash
bunx struere add data-type customer
```

Creates `entity-types/customer.ts`:

```typescript
import { defineData } from 'struere'

export default defineData({
  name: "Customer",
  slug: "customer",
  schema: {
    type: "object",
    properties: {
      name: { type: "string", description: "Name" },
      email: { type: "string", format: "email", description: "Email address" },
      status: { type: "string", enum: ["active", "inactive"], description: "Status" },
    },
    required: ["name"],
  },
  searchFields: ["name", "email"],
  displayConfig: {
    listFields: ["name", "email", "status"],
  },
})
```

### Scaffold a Role

```bash
bunx struere add role support
```

Creates `roles/support.ts`:

```typescript
import { defineRole } from 'struere'

export default defineRole({
  name: "support",
  description: "Support role",
  policies: [
    { resource: "*", actions: ["list", "read"], effect: "allow" },
  ],
  scopeRules: [],
  fieldMasks: [],
})
```

### Scaffold an Automation

```bash
bunx struere add trigger notify-on-signup
```

Creates `triggers/notify-on-signup.ts`:

```typescript
import { defineTrigger } from 'struere'

export default defineTrigger({
  name: "notify-on-signup",
  slug: "notify-on-signup",
  on: {
    entityType: "ENTITY_TYPE_HERE",
    action: "created",
  },
  actions: [
    {
      tool: "entity.query",
      args: {
        type: "{{trigger.entityType}}",
        filters: { "data.id": "{{trigger.entityId}}" },
      },
    },
  ],
})
```

### Scaffold a Router

```bash
bunx struere add router support-router
```

Creates `routers/support-router.ts`:

```typescript
import { defineRouter } from 'struere'

export default defineRouter({
  name: "Support Router",
  slug: "support-router",
  mode: "rules",
  agents: [
    { slug: "agent-one", description: "Handles ..." },
  ],
  rules: [
    {
      conditions: [{ field: "channel", operator: "eq", value: "whatsapp" }],
      route: "agent-one",
    },
  ],
  fallback: "agent-one",
})
```

### Scaffold a Workflow

```bash
bunx struere add workflow vip-payment
```

Creates `workflows/vip-payment.ts`:

```typescript
import { workflow } from 'struere'

const wfVipPayment = workflow({
  name: "vip-payment",
  slug: "vip-payment",
})

wfVipPayment
  .onEntity({
    entityType: "ENTITY_TYPE_HERE",
    action: "created",
  })
  .tool("entity.update", {
    type: "{{ $trigger.entityType }}",
    id: "{{ $trigger.entityId }}",
    data: { handled: true },
  }, { name: "Mark handled" })

export default wfVipPayment.build()
```

See [defineWorkflow](/sdk/define-workflow) for the full builder reference.

### Scaffold a Custom View

```bash
bunx struere add view operations-dashboard
```

Creates `views/operations-dashboard.tsx`:

```tsx
import { defineView, Card, DataTable, Stack, EmptyState, useViewQuery } from "struere/view"

export default defineView({
  name: "Operations Dashboard",
  slug: "operations-dashboard",
  description: "Operations Dashboard dashboard",
  queries: {
    rows: { type: "todo", limit: 100 }
  },
  render: () => {
    const rows = useViewQuery<{ id: string; title: string }>("rows")
    if (!rows.data) return null
    if (rows.data.length === 0) {
      return <EmptyState title="Nothing here yet" description="Define a 'todo' entity type or change the query." />
    }
    return (
      <Stack gap="md">
        <Card title="Operations Dashboard">
          <DataTable
            rows={rows.data}
            rowKey={(r) => r.id}
            columns={[{ key: "title", header: "Title" }]}
          />
        </Card>
      </Stack>
    )
  }
})
```

See [Authoring a Custom View](./views) for the full walkthrough.

### Scaffold a Fixture

```bash
bunx struere add fixture classroom-data
```

Creates `fixtures/classroom-data.fixture.yaml`:

```yaml
name: "Classroom Data"
slug: "classroom-data"

entities:
  - ref: "example-1"
    type: "ENTITY_TYPE_HERE"
    data:
      name: "Example Entity"
    status: "active"

  - ref: "example-2"
    type: "ENTITY_TYPE_HERE"
    data:
      name: "Another Entity"

relations:
  - from: "example-1"
    to: "example-2"
    type: "related_to"
```

## With Dev Running

If you have `struere dev` running in another terminal, newly scaffolded files will be detected and synced to Convex automatically. You can immediately edit the generated file and see your changes reflected in the development environment.

## Naming Conventions

The `<name>` argument is used to generate both the filename and the resource slug:

- Filename: `<name>.ts` (e.g., `scheduler.ts`, `notify-on-signup.ts`)
- Slug: derived from the name (e.g., `scheduler`, `notify-on-signup`)
- Display name: derived from the name with capitalization (e.g., `Scheduler`, `Notify on Signup`)
