> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ensemble.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Your First Project

> From zero to deployed edge workflow in 60 seconds. No ceremony, no boilerplate.

## Quick Start (60 Seconds)

Get a working Conductor project instantly:

<Tabs>
  <Tab title="Unified CLI (Recommended)">
    The interactive wizard handles everything—project creation, package manager detection, and dependency installation:

    ```bash theme={null}
    # Launch the wizard (no installation needed)
    npx @ensemble-edge/ensemble
    ```

    The wizard will:

    1. Ask you to select **Conductor** as the project type
    2. Prompt for your project name
    3. Detect your package manager (npm, pnpm, yarn, bun)
    4. Create the project and install dependencies automatically

    Then start the dev server:

    ```bash theme={null}
    cd my-conductor-app
    ensemble conductor start
    ```

    Open [http://localhost:8787](http://localhost:8787) 🎉
  </Tab>

  <Tab title="Direct Command">
    Skip the wizard and create a project directly:

    ```bash theme={null}
    # Create project with examples (no installation needed)
    npx @ensemble-edge/ensemble conductor init my-conductor-app
    cd my-conductor-app

    # Install and run
    pnpm install
    ensemble conductor start
    ```

    Open [http://localhost:8787](http://localhost:8787) 🎉

    <Tip>
      **For CI/automated environments**, use the `-y` flag to skip all interactive prompts:

      ```bash theme={null}
      npx @ensemble-edge/conductor init my-conductor-app -y
      ```
    </Tip>
  </Tab>
</Tabs>

Your project includes working examples of pages, workflows, and agents!

## Prerequisites

You need:

* **Node.js** 18+ ([nodejs.org](https://nodejs.org))
* **A Cloudflare account** (free tier works - only needed for deployment)

Check Node.js:

```bash theme={null}
node --version  # Should be 18+
```

## Understanding Your Project

The `init` command creates a complete, ready-to-run project:

```
my-conductor-app/
├── conductor.config.ts    # Project settings & observability
├── wrangler.toml         # Cloudflare Workers config
├── src/
│   └── index.ts          # Entry point (custom endpoints)
├── ensembles/            # 🎭 Workflows & Pages (auto-discovered)
│   ├── pages/            # HTTP endpoints that render HTML
│   │   ├── home.yaml         # GET /
│   │   ├── dashboard.yaml    # GET /dashboard
│   │   ├── login.yaml        # GET/POST /login
│   │   └── blog-post.yaml    # GET /blog/:slug
│   ├── api/              # JSON API endpoints
│   │   └── users.yaml
│   └── hello-world.yaml  # CLI workflow example
├── agents/               # 🤖 Agents (auto-discovered)
│   ├── hello/
│   │   ├── agent.yaml        # Agent configuration
│   │   └── index.ts          # Agent implementation
│   └── docs-*/           # Documentation agent examples
├── docs/                 # 📄 Markdown documentation (auto-discovered)
│   └── getting-started.md
└── tests/                # ✅ Test files
    └── basic.test.ts
```

## Explore the Examples

Your project includes working examples for all major features.

### Try the Example Pages

Start the dev server:

<Note>
  **Dev Container Users**: Add `--ip 0.0.0.0` to bind to all interfaces:

  ```bash theme={null}
  npx wrangler dev --local-protocol http --ip 0.0.0.0
  ```

  **Local Development**: Use the standard command:

  ```bash theme={null}
  npx wrangler dev --local-protocol http
  ```
</Note>

Visit these URLs:

* [http://localhost:8787/](http://localhost:8787/) - Homepage
* [http://localhost:8787/examples](http://localhost:8787/examples) - Examples index
* [http://localhost:8787/dashboard](http://localhost:8787/dashboard) - Dashboard with data
* [http://localhost:8787/login](http://localhost:8787/login) - Login form
* [http://localhost:8787/blog/getting-started-with-conductor](http://localhost:8787/blog/getting-started-with-conductor) - Dynamic blog post

### Run the Tests

```bash theme={null}
pnpm test
```

All tests should pass! The template includes examples of:

* Ensemble execution
* Agent testing
* Error handling

## Your First Page

Let's create a simple page using an ensemble with an HTTP trigger.

**Step 1: Create the ensemble file**

Create `ensembles/hello.yaml`:

```yaml theme={null}
name: hello-page
description: Simple hello world page

trigger:
  - type: http
    path: /hello
    methods: [GET]
    public: true

flow:
  - operation: html
    config:
      templateEngine: liquid
      template: |
        <!DOCTYPE html>
        <html>
          <head>
            <title>Hello Page</title>
          </head>
          <body>
            <h1>Hello from Conductor!</h1>
            <p>This page was auto-discovered.</p>
            <p>Current time: {{ "now" | date: "%Y-%m-%d %H:%M:%S" }}</p>
          </body>
        </html>

output:
  format: html
  rawBody: ${html.output}
```

**Step 2: Rebuild**

```bash theme={null}
pnpm run build
```

The dev server will automatically reload.

**Step 3: Visit**

Open [http://localhost:8787/hello](http://localhost:8787/hello)

### Add Dynamic Data

Make your page dynamic by adding an agent that fetches data.

Create `ensembles/hello-dynamic.yaml`:

```yaml theme={null}
name: hello-dynamic
description: Hello page with dynamic data

trigger:
  - type: http
    path: /hello-dynamic
    methods: [GET]
    public: true

agents:
  - name: get_data
    operation: code
    config:
      handler: |
        export default async function({ input, ctx }) {
          return {
            message: 'Hello from the handler!',
            timestamp: new Date().toISOString(),
            userAgent: input.headers?.['user-agent'] || 'Unknown'
          };
        }

flow:
  - agent: get_data

  - operation: html
    config:
      templateEngine: liquid
      template: |
        <!DOCTYPE html>
        <html>
          <head>
            <title>Hello Page</title>
          </head>
          <body>
            <h1>{{ message }}</h1>
            <p>Timestamp: {{ timestamp }}</p>
            <p>Your browser: {{ userAgent }}</p>
          </body>
        </html>
      data:
        message: ${get_data.output.message}
        timestamp: ${get_data.output.timestamp}
        userAgent: ${get_data.output.userAgent}

output:
  format: html
  rawBody: ${html.output}
```

Rebuild and refresh - your dynamic data now appears in the page!

## Your First Workflow

The template includes `ensembles/hello-world.yaml`. Let's explore it:

```yaml theme={null}
name: hello-world
description: Simple greeting workflow

trigger:
  - type: cli
    command: hello

agents:
  - name: hello
    operation: code

flow:
  - agent: hello

output:
  greeting: ${hello.output.message}
```

This workflow calls the `hello` agent (from `agents/examples/hello/`) and returns its output.

### Create a New Ensemble

Create `ensembles/my-workflow.yaml`:

```yaml theme={null}
name: my-workflow
description: Custom greeting with timestamp

trigger:
  - type: cli
    command: greet

agents:
  # Call existing hello agent
  - name: greeter
    operation: code
    config:
      handler: hello  # Reference to agents/examples/hello/

flow:
  - agent: greeter

output:
  greeting: ${greeter.output.message}
  timestamp: ${Date.now()}
```

### Execute from a Page

Create an ensemble that renders the workflow result as HTML:

Create `ensembles/workflow-demo.yaml`:

```yaml theme={null}
name: workflow-demo
description: Display workflow result as a page

trigger:
  - type: http
    path: /workflow
    methods: [GET]
    public: true

agents:
  - name: greeter
    operation: code
    config:
      handler: |
        export default async function({ input }) {
          return {
            message: 'Hello from the workflow!',
            timestamp: new Date().toISOString()
          };
        }

flow:
  - agent: greeter

  - operation: html
    config:
      templateEngine: liquid
      template: |
        <!DOCTYPE html>
        <html>
          <head>
            <title>Workflow Demo</title>
          </head>
          <body>
            <h1>Workflow Result</h1>
            <p>{{ greeting }}</p>
            <p>Timestamp: {{ timestamp }}</p>
          </body>
        </html>
      data:
        greeting: ${greeter.output.message}
        timestamp: ${greeter.output.timestamp}

output:
  format: html
  rawBody: ${html.output}
```

Visit [http://localhost:8787/workflow](http://localhost:8787/workflow) - your ensemble runs on every page load!

## Project Configuration

### wrangler.toml

The `init` command creates a properly configured `wrangler.toml`:

```toml theme={null}
name = "my-conductor-project"
main = "dist/index.mjs"  # Built output, not source!
compatibility_date = "2025-10-29"
compatibility_flags = ["nodejs_compat"]

[build]
command = "pnpm run build"
watch_dirs = ["src", "agents", "ensembles", "docs"]
```

**Important**: Conductor uses Vite/Rolldown to build your project. The output is `dist/index.mjs`, not `src/index.ts`.

### conductor.config.ts

This file controls project settings, observability, and API execution controls. Use `defineConfig()` for full TypeScript autocomplete:

```typescript theme={null}
import { defineConfig } from '@ensemble-edge/conductor';

export default defineConfig({
  name: 'my-conductor-project',
  version: '1.0.0',

  // Documentation UI settings
  docs: {
    ui: 'stoplight',
    cache: { enabled: true, ttl: 3600 }
  },

  // Observability
  observability: {
    logging: { enabled: true, level: 'info' },
    metrics: { enabled: true }
  },

  // API execution controls (optional)
  api: {
    execution: {
      // When true, agents/ensembles must have apiExecutable: true
      agents: { requireExplicit: false },
      ensembles: { requireExplicit: false }
    }
  }
});
```

<Tip>
  The `defineConfig()` helper provides TypeScript autocomplete and validation for all configuration options.
</Tip>

**Note**: Authentication is configured per-route in each ensemble's `trigger:` config using `public: true/false`. See the examples above.

## Deploy to Cloudflare

### Step 1: Login to Cloudflare

```bash theme={null}
npx wrangler login
```

This opens your browser to authorize Wrangler.

### Step 2: Build

```bash theme={null}
pnpm run build
```

### Step 3: Deploy

```bash theme={null}
npx wrangler deploy
```

Output:

```
Published my-conductor-app (0.5 sec)
  https://my-conductor-app.your-subdomain.workers.dev
```

Your app is now live at the edge in 300+ cities worldwide!

Test it:

```bash theme={null}
curl https://my-conductor-app.your-subdomain.workers.dev/hello
```

## Development Workflow

```bash theme={null}
# Start dev server (with network binding)
npx wrangler dev --local-protocol http

# Run tests
pnpm test

# Build for production
pnpm run build

# Deploy
npx wrangler deploy

# View live logs
npx wrangler tail

# Check deployments
npx wrangler deployments list
```

## Troubleshooting

<AccordionGroup>
  <Accordion title="Tests failing with 'waitUntil is not a function'">
    **Problem**: Template tests fail with `TypeError: this.ctx.waitUntil is not a function`

    **Fix**: The ExecutionContext mock in `tests/basic.test.ts` is already fixed in v1.8.0. If you see this error, update the mock:

    ```typescript theme={null}
    // Correct mock (should already be in template)
    const ctx = {
      waitUntil: (promise: Promise<any>) => promise,
      passThroughOnException: () => {}
    } as ExecutionContext;
    ```
  </Accordion>

  <Accordion title="Wrangler hangs or requests timeout">
    **Problem**: `wrangler dev` starts but all requests hang indefinitely

    **Fix**: Use the `--local-protocol http` flag:

    ```bash theme={null}
    npx wrangler dev --local-protocol http
    ```

    This properly binds network access for the Workers runtime.
  </Accordion>

  <Accordion title="New ensembles/agents not showing up">
    **Problem**: Created a new ensemble or agent but it returns 404

    **Fix**: Trigger a rebuild. Ensembles and agents are discovered at build time:

    ```bash theme={null}
    pnpm run build
    ```

    Or with wrangler running, the file watcher should auto-rebuild.
  </Accordion>

  <Accordion title="Dynamic routes return 404">
    **Problem**: Routes with parameters like `/blog/:slug` are not working

    **Status**: Fixed in v1.8.0! Dynamic route parameters now work correctly.

    Make sure your ensemble has the trigger configured properly:

    ```yaml theme={null}
    trigger:
      - type: http
        path: /blog/:slug  # Correct - at root level
        methods: [GET]
        public: true
    ```

    Not nested in config:

    ```yaml theme={null}
    config:
      trigger:  # Wrong! trigger belongs at root level
        - type: http
          path: /blog/:slug
    ```
  </Accordion>

  <Accordion title="Build errors after updating">
    **Problem**: Build fails after updating wrangler.toml or package.json

    **Fix**: Clean rebuild:

    ```bash theme={null}
    rm -rf dist node_modules
    pnpm install
    pnpm run build
    ```
  </Accordion>

  <Accordion title="Module 'virtual:conductor-ensembles' not found">
    **Problem**: Build error about virtual module

    **Fix**: This is a Vite virtual module created at build time. Make sure:

    1. `ensembles/` directory exists
    2. Vite config is correct (should be in template)
    3. Clean rebuild: `rm -rf dist && pnpm run build`
  </Accordion>
</AccordionGroup>

## What's Included in the Template

The `init` command creates:

### ✅ Working Examples

* **10+ example ensembles** showing static, dynamic, forms, and SSR patterns
* **Multiple workflow ensembles** demonstrating different trigger types
* **1 hello agent** showing custom code operations
* **Multiple doc agents** for various operation types

### ✅ Development Tools

* **Vitest** for testing with working examples
* **TypeScript** configured correctly
* **Vite** for fast builds with HMR
* **ESLint & Prettier** for code quality

### ✅ Production Ready

* **Authentication** configured in conductor.config.ts
* **Caching** rules for optimal performance
* **Error handling** with custom 404 page
* **Wrangler config** ready for deployment

### ✅ Documentation

* **README.md** with project overview
* **Inline comments** explaining key concepts
* **Example code** for common patterns

## Next Steps

<CardGroup cols={2}>
  <Card title="Your First Website" icon="file" href="/conductor/getting-started/your-first-website">
    Learn how to build web applications
  </Card>

  <Card title="Your First Agent" icon="robot" href="/conductor/getting-started/your-first-agent">
    Create custom reusable agents
  </Card>

  <Card title="Your First Ensemble" icon="diagram-project" href="/conductor/getting-started/your-first-ensemble">
    Build complex workflows
  </Card>

  <Card title="Operations Reference" icon="bolt" href="/conductor/operations/overview">
    Explore all available operations
  </Card>
</CardGroup>

## Alternative: Manual Setup (Advanced)

If you need to integrate Conductor into an existing Cloudflare Workers project:

<Accordion title="Show manual setup instructions">
  ### Step 1: Create Worker

  ```bash theme={null}
  npm create cloudflare@latest my-conductor-app
  ```

  Select: "Hello World" Worker, TypeScript: Yes

  ### Step 2: Install Conductor

  ```bash theme={null}
  cd my-conductor-app
  pnpm add @ensemble-edge/conductor
  ```

  ### Step 3: Update wrangler.toml

  ```toml theme={null}
  name = "my-conductor-app"
  main = "dist/index.mjs"  # Important: build output!
  compatibility_date = "2025-10-29"
  compatibility_flags = ["nodejs_compat"]

  [build]
  command = "pnpm run build"
  watch_dirs = ["src", "ensembles", "agents", "docs"]
  ```

  ### Step 4: Add Vite Config

  Create `vite.config.ts`:

  ```typescript theme={null}
  import { defineConfig } from 'vite';
  import { cloudflareWorker } from '@ensemble-edge/conductor/vite';

  export default defineConfig({
    plugins: [
      cloudflareWorker({
        ensemblesDir: './ensembles',
        agentsDir: './agents',
        docsDir: './docs',
      }),
    ],
    build: {
      outDir: 'dist',
      lib: {
        entry: './src/index.ts',
        formats: ['es'],
        fileName: 'index',
      },
      rollupOptions: {
        external: ['node:async_hooks'],
      },
    },
  });
  ```

  ### Step 5: Create Directories

  ```bash theme={null}
  mkdir -p ensembles agents docs tests
  ```

  ### Step 6: Update package.json

  ```json theme={null}
  {
    "scripts": {
      "build": "vite build",
      "dev": "wrangler dev --local-protocol http",
      "deploy": "pnpm run build && wrangler deploy",
      "test": "vitest run"
    }
  }
  ```

  **Note**: Manual setup is error-prone and requires more configuration. The `init` command is strongly recommended.
</Accordion>

## Tips & Best Practices

1. **Always use --local-protocol http** with `wrangler dev` to avoid network binding issues
2. **Rebuild after adding files** - Ensembles and agents are discovered at build time
3. **Start with examples** - Modify the included hello examples before creating new ones
4. **Test locally first** - `pnpm test` runs your test suite instantly
5. **Check logs** - `npx wrangler tail` shows real-time production logs
6. **Use git** - The template includes .gitignore configured correctly
7. **Read the generated README.md** - It includes project-specific guidance
