Skip to content

Project Structure

How to lay out a real latent project — agents, tools, guardrails, flows, and data — using the conventions the Latent team follows in production agents and that Agent Studio expects.

The go-to layout

The canonical structure is a uv workspace monorepo with an agents/ folder — one installable package per agent — served by an apps/backend that runs the Agent Studio runtime. This is what agents like stratus and docs use, and what Agent Studio's tooling (agent-studio link / push) is built around.

my-agents/                          # uv workspace monorepo root
├── pyproject.toml                  # [tool.uv.workspace] members + [tool.uv.sources] linking latent & agent-studio-*
├── devbox.json                     # env: LATENT_WORKSPACE_ROOT=$PWD, LATENT_FLOWS_DIR, provider keys
├── studio.config.yaml              # Agent Studio integration (points the CLI at your Convex backend)
├── agents/                         # ← one package per agent
│   ├── common/                     # shared agent code (optional)
│   └── support/
│       ├── pyproject.toml          # package name: latent-agents-support
│       ├── kb/                     # knowledge-base markdown (public/ internal/ playbooks/)
│       ├── tests/
│       └── src/latent_agents/support/      # the latent_agents.<name> namespace
│           ├── __init__.py         # re-exports the agent class + factories
│           ├── agent.py            # @agent("support") class SupportAgent(GuidedAgent | ReActAgent | …)
│           ├── prompt.py           # SYSTEM_PROMPT (or prompts/sections/ for composable fragments)
│           ├── tools.py            # build_tools() — or a tools/ package, one file per tool
│           ├── guardrails.py       # @guardrail mixin + custom scanners
│           ├── guidelines.py journey.py kb.py     # GuidedAgent behavior, retriever wiring
│           └── flows/<flow>/        # flow logic may live next to the agent
├── apps/
│   ├── backend/                    # FastAPI runtime that serves the agents (app.py, runtime.py, worker.py)
│   └── web/                        # Agent Studio UI (optional)
├── convex/                         # Agent Studio Convex backend (when running it locally)
├── flows/                          # flow-discovery dir (directory name = flow name)
│   ├── global.yaml                 # shared parameter defaults across flows
│   └── <flow>/
│       ├── flow.py  tasks.py
│       ├── parameters.yaml         # flow params + mlflow.experiment_name
│       └── catalog.yaml            # datasets (type / path / schema)
└── data/
    ├── stable/                     # versioned, shared artifacts: chroma_db/, glossary.json, …
    ├── ground_truth/               # curated eval sets
    └── <flow>/{input,output}/      # per-flow data; flows write to output/

How an agent fits in

  • One package per agent under agents/. Each is a uv workspace member named latent-agents-<name>, exposing the latent_agents.<name> namespace. (You can use your own package name/namespace — the agents/<name>/ folder and per-agent package are what matter.)
  • agent.py registers the agent with @agent("<name>", description=...) on a ReActAgent / GuidedAgent / PipelineAgent subclass. latent's @agent registry discovers it by name; __init__.py re-exports the class and any factories.
  • tools.py / tools/, guardrails.py, prompt.py, kb/ hold the agent's capabilities, safety rules, prompt fragments, and knowledge-base markdown — see the Agent Cookbook for the patterns.

How Agent Studio serves it

  • apps/backend runs the Agent Studio runtime and serves every @agent-registered agent (the backend factory closure-binds per-conversation context, e.g. a customer id).
  • studio.config.yaml points the agent-studio CLI at your Convex backend; agent-studio link wires the local packages and agent-studio push regenerates the Convex wrappers. See Agent Studio.
  • pyproject.toml uses [tool.uv.sources] to bring latent and the agent-studio-* packages in as workspace/editable deps.

Flows and data on disk

  • flows/<flow>/ — each flow lives in a directory whose name is the flow name (@flow("agent_inference")flows/agent_inference/), containing flow.py, parameters.yaml, usually catalog.yaml, and tasks.py. See Flow Building, Flow Parameters, and Data Catalog.
  • global.yaml supplies defaults merged under each flow's parameters.yaml (precedence: bundled < global.yaml < flow). See the layering model.
  • data/stable/ holds version-controlled shared artifacts (the Chroma index, glossaries) read via catalog.stable; data/<flow>/output/ is where outputs land (also MLflow artifacts).

Two flow-discovery conventions

  • Root flows/ (default) — keep flows at LATENT_WORKSPACE_ROOT/flows. Flow bodies may live next to their agent and be re-exported from a thin flows/<name>/flow.py shim that carries the parameters.yaml / catalog.yaml.
  • LATENT_FLOWS_DIR override — point LATENT_FLOWS_DIR at a dedicated pipelines package (e.g. apps/<app>/pipelines/src/pipelines) so flows live with the app and need no shims.

Configuration: env vars or TOML

Production repos configure entirely through environment variables in devbox.json (LATENT_WORKSPACE_ROOT, LATENT_FLOWS_DIR, LATENT_DATA_DIR, provider keys) rather than a latent.toml. Either works — env vars take precedence. See Workspace Configuration.

// devbox.json
{ "env": { "LATENT_WORKSPACE_ROOT": "$PWD", "LATENT_FLOWS_DIR": "$PWD/flows" } }

A single-agent variant

For one agent and a handful of flows you don't need the full monorepo — drop the agents/ and apps/ layers and keep a single package:

my-agent/
├── pyproject.toml                  # deps incl. "latent[eval]"
├── devbox.json
├── src/my_agent/                   # agent.py, tools/, guardrails/, prompt.py
├── flows/<flow>/{flow.py,parameters.yaml,catalog.yaml}
└── data/{stable,<flow>/output}/

Promote to the agents/-folder monorepo above once you add a second agent or wire up Agent Studio.

Development with Claude Code skills

The Latent team builds these projects with Claude Code using a set of skills shipped through the team's chezwork dotfiles (deployed to ~/.claude/skills/). They encode the conventions in these docs — load latent-best-practices plus the relevant domain skill when working in a latentsp repo.

Skill Use it for
latent-best-practices The foundation — cross-cutting team conventions: architecture (side-effects at the edges, factory pattern), error handling, testing, observability, tooling. Load alongside the others.
python-best-practices Python: FastAPI / Pydantic patterns, async conventions, uv / ruff, typing, error handling
llm-best-practices Agents & LLM features — LiteLLM calls, prompt management, RAG (retrieval, chunking, embedding, hybrid search)
ml-best-practices Eval flows — Prefect orchestration, MLflow experiment tracking, evaluation workflows
data-best-practices Datasets & the catalog — Pydantic validation, ETL, dataset management, SQL
testing-strategy Where tests live + the tooling/patterns to use
agent-studio Agent Studio cross-repo workflows — linking, pushing Convex wrappers, debugging naming mismatches
plan · architect · spec Plan → critique a design → write a spec, before building
review · code-review · build · implement The build-and-review loop (simplicity, deep modules, honest types)

Team tooling

These skills are part of the Latent team's Claude Code setup (managed in the chezwork dotfiles repo). They're conventions, not part of the latent package — but they map one-to-one onto the building blocks here: llm-best-practicesagents, ml-best-practicesflows, data-best-practices → the catalog, and latent-best-practices ties them together.

See Also