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

# Project Structure

> How to organize your Runflow agent project

Every Runflow project follows a simple convention: a `main.ts` file at the root that exports an `async function main()`. As your project grows, you organize code into folders that map directly to SDK concepts.

## Entry Point: `main.ts`

The `main.ts` file is the only required file. It must export an `async function main(input)` — this is the contract between your code and the Runflow engine.

```typescript main.ts theme={null}
import { Agent, openai } from '@runflow-ai/sdk';
import { identify } from '@runflow-ai/sdk/observability';

const agent = new Agent({
  name: 'My Agent',
  instructions: '...',
  model: openai('gpt-4o'),
});

export async function main(input: any) {
  identify(input.email || input.phone);

  const result = await agent.process({
    message: input.message,
    sessionId: input.sessionId,
  });

  return { message: result.message };
}
```

**What `main()` receives:**

* `input.message` — the user's message (always present)
* `input.sessionId` — session identifier (for memory continuity)
* `input.email`, `input.phone` — user identifiers (depends on your integration)
* Any other fields your integration sends

**What `main()` returns:**

* An object with at least `message` — the agent's response
* Any additional metadata you want to pass back

## Project Sizes

### Simple Project

For a basic agent with one or two tools, keep everything minimal:

```
my-agent/
├── main.ts              # Agent + main function
├── tools/
│   └── weather.ts       # One file per tool
├── .runflow/
│   └── rf.json
├── package.json
└── tsconfig.json
```

### Medium Project

When you have multiple tools and want better organization:

```
my-agent/
├── main.ts              # Entry point + orchestration
├── agent.ts             # Agent definition (separated from main)
├── tools/
│   ├── index.ts         # Re-exports all tools
│   ├── create-ticket.ts
│   ├── search-orders.ts
│   └── send-email.ts
├── prompts/
│   └── index.ts         # System prompt + templates
├── .runflow/
│   └── rf.json
├── package.json
└── tsconfig.json
```

### Complex Project

For enterprise agents with workflows, connectors, and integrations:

```
my-agent/
├── main.ts              # Entry point + routing logic
├── agent.ts             # Agent definition
├── tools/
│   ├── index.ts
│   ├── create-ticket.ts
│   ├── classify-intent.ts
│   └── send-notification.ts
├── prompts/
│   └── index.ts         # System prompt + scenario prompts
├── workflows/
│   └── lead-qualification.ts
├── connectors/
│   └── hubspot.ts       # Connector configurations
├── config/
│   └── settings.ts      # Constants, enums, configurations
├── .runflow/
│   └── rf.json
├── package.json
└── tsconfig.json
```

## Folder Guide

### `tools/`

One file per tool. Each file exports a single tool created with `createTool()`.

```typescript tools/create-ticket.ts theme={null}
import { createTool } from '@runflow-ai/sdk';
import { z } from 'zod';

export const createTicketTool = createTool({
  id: 'create-ticket',
  description: 'Create a support ticket in the system',
  inputSchema: z.object({
    subject: z.string(),
    description: z.string(),
    priority: z.enum(['low', 'medium', 'high']),
  }),
  execute: async (params) => {
    // Your logic here
    return { ticketId: 'TICKET-123', success: true };
  },
});
```

Use an `index.ts` to re-export all tools:

```typescript tools/index.ts theme={null}
export { createTicketTool } from './create-ticket';
export { searchOrdersTool } from './search-orders';
export { sendEmailTool } from './send-email';
```

Then import them cleanly in your agent:

```typescript agent.ts theme={null}
import { createTicketTool, searchOrdersTool, sendEmailTool } from './tools';

const agent = new Agent({
  tools: {
    createTicket: createTicketTool,
    searchOrders: searchOrdersTool,
    sendEmail: sendEmailTool,
  },
});
```

### `prompts/`

Centralize your prompts in a dedicated file, especially when they're long or have multiple scenarios:

```typescript prompts/index.ts theme={null}
export const systemPrompt = `You are a customer support agent for ACME Corp.

## Behavior
- Always be professional and empathetic
- Respond in the customer's language
- Search the knowledge base before answering technical questions

## Tools
- Use create-ticket for issues that need human follow-up
- Use search-orders when customers ask about their orders
- Use send-email to notify the team about urgent issues

## Response Format
- Be concise but complete
- Use bullet points for lists
- Always confirm actions taken`;

export const escalationPrompt = `A customer issue needs escalation.
Customer: {{customerName}}
Issue: {{issue}}
Priority: {{priority}}

Write a brief summary for the support team.`;
```

<Tip>
  For prompts managed through the Runflow portal, use `loadPrompt()` instead of local files. See [Prompts](/core-concepts/prompts) for details.
</Tip>

### `workflows/`

Store workflow definitions in dedicated files:

```typescript workflows/lead-qualification.ts theme={null}
import { createWorkflow } from '@runflow-ai/sdk';
import { z } from 'zod';

export const leadQualificationWorkflow = createWorkflow({
  id: 'lead-qualification',
  inputSchema: z.object({
    email: z.string().email(),
    company: z.string(),
    notes: z.string(),
  }),
  // ... workflow steps
});
```

### `connectors/`

When using multiple connectors, configure them in dedicated files:

```typescript connectors/hubspot.ts theme={null}
import { createConnectorTool } from '@runflow-ai/sdk';

export const createContactTool = createConnectorTool('hubspot', 'create_contact');
export const updateDealTool = createConnectorTool('hubspot', 'update_deal');
```

### `config/`

For projects with many constants, enums, or configuration values:

```typescript config/settings.ts theme={null}
export const PRIORITIES = ['low', 'medium', 'high', 'urgent'] as const;
export type Priority = (typeof PRIORITIES)[number];

export const AGENT_CONFIG = {
  model: 'gpt-4o',
  temperature: 0,
  maxTokens: 3000,
  memoryMaxTurns: 50,
};
```

## Separating the Agent from `main.ts`

As your project grows, move the agent definition to its own file. This keeps `main.ts` focused on orchestration:

```typescript agent.ts theme={null}
import { Agent, openai } from '@runflow-ai/sdk';
import { systemPrompt } from './prompts';
import { createTicketTool, searchOrdersTool } from './tools';

export const supportAgent = new Agent({
  name: 'Support Agent',
  instructions: systemPrompt,
  model: openai('gpt-4o'),
  memory: { maxTurns: 20 },
  tools: {
    createTicket: createTicketTool,
    searchOrders: searchOrdersTool,
  },
  observability: 'full',
});
```

```typescript main.ts theme={null}
import { identify, track } from '@runflow-ai/sdk/observability';
import { supportAgent } from './agent';

export async function main(input: any) {
  identify(input.email || input.phone);

  const result = await supportAgent.process({
    message: input.message,
    sessionId: input.sessionId,
  });

  track('support_request', {
    channel: input.channel,
    resolved: !result.metadata?.toolsUsed?.includes('createTicket'),
  });

  return { message: result.message };
}
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Best Practices" icon="lightbulb" href="/best-practices">
    Tips for writing effective agents
  </Card>

  <Card title="Tools" icon="wrench" href="/core-concepts/tools">
    Learn how to create tools
  </Card>

  <Card title="Workflows" icon="diagram-project" href="/core-concepts/workflows">
    Build multi-step workflows
  </Card>

  <Card title="Prompts" icon="file-lines" href="/core-concepts/prompts">
    Manage prompt templates
  </Card>
</CardGroup>
