Project Layout
Purpose and Scope
Flue projects are organized around discoverable application surfaces rather than a large required framework skeleton. The practical rule is simple: put new application code under src/, then use a small set of conventional files and directories when you want Flue to build something automatically. Those conventions are the difference between ordinary helper code and addressable Flue resources. This page explains the source layout that new projects should use, what each discovered entrypoint means, and how to keep supporting code flexible without hiding agents, workflows, channels, or persistence configuration from the build.
Sources: apps/docs/src/content/docs/guide/project-layout.md
The layout guide defines six core surfaces that Flue treats specially: app.ts, db.ts, cloudflare.ts, agents/, workflows/, and channels/. Everything else inside src/ can be organized according to the needs of the application. That separation is important because it lets teams keep domain code, API clients, shared tools, prompt fragments, and test helpers near the resources that use them without making every file a route or runtime resource. In other words, Flue discovery is convention-based, but it is intentionally narrow.
Sources: apps/docs/src/content/docs/guide/project-layout.md
Relevant Source Files
apps/docs/src/content/docs/guide/project-layout.md- First-party documentation for Flue project discovery, example tree structure, important files and directories, and the behavior ofapp.ts,db.ts,cloudflare.ts,agents/,workflows/, andchannels/.
Example Project Tree
A typical project keeps package metadata and Flue configuration at the repository root, application source under src/, and generated build output under dist/. The documented example includes optional entrypoints for HTTP composition, persistence, and Cloudflare deployment, plus resource directories for agents, workflows, and channels. You do not need every file on day one. Start with the resource you are building, then add the optional entrypoints when the application needs routing composition, durable Node persistence, or Cloudflare-specific exports.
my-project/
├─ package.json
├─ flue.config.ts
├─ src/
│ ├─ app.ts
│ ├─ db.ts
│ ├─ cloudflare.ts
│ ├─ agents/
│ │ └─ support-assistant.ts
│ ├─ workflows/
│ │ └─ summarize-ticket.ts
│ └─ channels/
│ └─ github.ts
└─ dist/Sources: apps/docs/src/content/docs/guide/project-layout.md
The root flue.config.ts belongs beside package.json because it describes project-level configuration, while src/ contains the code Flue builds. The documented dist/ directory represents generated output rather than source that users should edit directly. This distinction helps when reviewing changes: files under src/ define application behavior, root configuration affects discovery and build settings, and generated output is a deployment artifact. Keeping these responsibilities separate makes it easier to reason about what changed when an agent, workflow, or channel starts behaving differently.
Discovered Entrypoints
app.ts is the optional custom application entrypoint for composing Flue with other HTTP behavior. Add it when your server needs authentication, webhooks that are not Flue channels, health endpoints, middleware, or a route prefix. If the project does not provide app.ts, Flue uses its generated application directly. That default is useful for small projects because an agent or workflow can be exposed without first building a web framework wrapper, while larger applications can opt into composition only when they need it.
Sources: apps/docs/src/content/docs/guide/project-layout.md
db.ts is the optional Node.js persistence entrypoint. Its default export configures the PersistenceAdapter used for canonical agent conversations, attachments, accepted submissions, and workflow-run records. The guide calls out a critical runtime distinction: without db.ts, Node.js uses in-memory SQLite and loses this state when the process exits, while Cloudflare provides Durable Object SQLite automatically and rejects db.ts. Treat db.ts as the place where a Node target chooses durable storage, not as a general database helper module.
Sources: apps/docs/src/content/docs/guide/project-layout.md
cloudflare.ts is a Cloudflare-only deployment module. Its named exports become top-level Worker exports, and its optional default export adds non-HTTP Worker handlers. Use it for Cloudflare-native additions such as same-Worker Durable Object classes, explicit Cloudflare Sandbox aliases, queue consumers, and scheduled handlers. The guide also draws a boundary: custom HTTP handling remains in app.ts. That boundary keeps Worker-specific runtime exports from becoming a second, competing place to define the HTTP application.
Sources: apps/docs/src/content/docs/guide/project-layout.md
Resource Directories and Naming Conventions
The agents/ directory contains addressable agents. Each immediate file defines one discovered agent, and the filename becomes the agent name. For example, src/agents/support-assistant.ts is discovered as support-assistant. The guide recommends keeping agent files flat inside agents/, because nested files are not discovered as additional agents. This means subfolders can still be useful for ordinary supporting code elsewhere, but discovered agent modules themselves should remain direct children with clear lower-kebab-case names that map cleanly to routes and manifests.
Sources: apps/docs/src/content/docs/guide/project-layout.md
Agents are the continuing interaction primitive in this layout. The building-agents guide describes a file in src/agents/ whose default export is created with defineAgent(...), with optional description and route exports. The project-layout convention supplies the addressable name, while the agent module supplies behavior such as model selection, instructions, tools, skills, and sandbox configuration. When designing the tree, keep the discovered agent file focused on the harness definition and import reusable capabilities from nearby shared modules when the implementation grows.
Workflows live under workflows/ and represent finite operations that receive input and return a result. They are a better fit than agents when the application needs a structured operation rather than a continuing conversational resource. The layout page groups workflows beside agents because both are build-time application surfaces, but their runtime shape is different: an agent continues over time, while a workflow completes a defined unit of work. Use naming that describes the operation, such as summarize-ticket.ts, so CLI commands, manifests, logs, and route references remain understandable.
Sources: apps/docs/src/content/docs/guide/project-layout.md
Channels live under channels/ and represent verified provider HTTP ingress discovered by filename. The channels guide defines a channel as a module that verifies the provider request, parses it into typed provider-native data, and calls your application handler. In layout terms, src/channels/github.ts creates a named inbound surface for provider events, not a universal GitHub client. Outbound calls should still use the provider SDK or application-owned helper code, which can be exported from the same module or imported from supporting files as needed.
Sources: apps/docs/src/content/docs/guide/project-layout.md
System-to-Code Mapping
| Project path | Discovered role | When to add it | Important boundary |
|---|---|---|---|
src/app.ts | Custom application entrypoint | Add for HTTP composition, auth, middleware, health checks, route prefixes, or extra webhooks. | A project without it uses the generated Flue application directly. |
src/db.ts | Node persistence entrypoint | Add when Node deployments need durable conversations, attachments, submissions, and workflow runs. | Cloudflare rejects it because Durable Object SQLite is provided automatically. |
src/cloudflare.ts | Cloudflare deployment module | Add for Worker exports, Durable Object classes, sandbox aliases, queues, scheduled handlers, or non-HTTP handlers. | Keep custom HTTP handling in app.ts. |
src/agents/ | Addressable continuing agents | Add one immediate file per agent. | Filename becomes the agent name; nested files are not additional agents. |
src/workflows/ | Finite workflow operations | Add modules for structured input-to-result processes. | Prefer workflows over agents for single-use or background work. |
src/channels/ | Verified provider ingress | Add one provider module per inbound HTTP integration. | Channels verify inbound events; provider SDKs handle outbound API calls. |
Sources: apps/docs/src/content/docs/guide/project-layout.md
Authoring Guidance
When adding a new capability, decide first whether it is a discovered Flue resource or ordinary application code. A discovered resource should live in one of the conventional locations and have a name you are comfortable exposing in URLs, manifests, CLI output, and operational logs. Ordinary code can live anywhere under src/: shared/, lib/, tools/, skills/, provider-client modules, or domain-specific folders are all reasonable patterns. The documented layout explicitly allows supporting application code to be organized however you prefer inside src/.
Sources: apps/docs/src/content/docs/guide/project-layout.md
A useful pattern is to keep each discovered file thin and import substantial implementation details. For an agent, the immediate file can export description, an optional route handler, and the default defineAgent(...) call, while imported modules provide reusable tools, actions, skills, and provider clients. For a channel, the discovered module can define verification and handler wiring while imported code performs business logic or outbound API calls. This keeps discovery predictable and makes it easier to test the application logic without needing to boot the full runtime.
Target-specific files should also stay target-specific. Put Node persistence in db.ts only for Node-target projects that need durable storage beyond in-memory SQLite. Put Cloudflare Worker exports and non-HTTP Worker handlers in cloudflare.ts, but do not move general HTTP routes there. If a project deploys to more than one target, this separation prevents accidental coupling between local development, Node deployment, and Cloudflare deployment. The layout conventions act as a compatibility contract between your source tree and Flue build behavior.
Next Steps
After the tree is in place, build outward from the resource you need most. If the application needs a continuing autonomous worker, create a file under src/agents/ and read the Building Agents guide for defineAgent(...), models, tools, skills, and sandboxes. If it needs a bounded automation, add a workflow under src/workflows/. If outside systems need to call in, create a channel under src/channels/ and follow the provider-specific channel setup. Add app.ts, db.ts, or cloudflare.ts only when the runtime behavior described above becomes necessary.
Sources: apps/docs/src/content/docs/guide/project-layout.md