Skip to content

Latest commit

 

History

History
114 lines (84 loc) · 4.82 KB

File metadata and controls

114 lines (84 loc) · 4.82 KB

LlamaIndex Workflows - Claude Development Guide

Project Overview

This is the LlamaIndex Workflows library - an event-driven, async-first framework for orchestrating complex AI applications and multi-step processes.

Key Technologies

  • Python 3.9+
  • AsyncIO (async/await)
  • Pydantic for data models
  • Starlette for web server
  • Uvicorn for ASGI serving

Development Commands

Testing

Use the dev CLI to run tests:

# Run all package tests
uv run dev

# Filter by substring match
uv run dev -p workflows
uv run dev -p server -p client

# Pass pytest args after --
uv run dev -- -k test_name

For more advanced scenarios, you can always cd packages/some-package and use pytest directly. The dev tool just provides additional package level test parallelism, and more curated cross package test output to avoid context bloat.

Several packages have Docker integration tests (requires Docker running) marked with @pytest.mark.docker. Run them with:

cd packages/<package> && uv run pytest -m docker -s -n0

Linting & Formatting

uv run pre-commit run -a

Project Structure

  • packages/llama-index-workflows/src/workflows/ - Main library code
  • packages/llama-index-workflows/src/workflows/server/ - Web server implementation
  • packages/llama-index-workflows/tests/ - Test suite
  • examples/ - Usage examples

Architecture

See architecture-docs/ for high-level architectural overviews:

The DBOS package has its own architecture doc explaining the distributed model (process boundaries, adapter rules, idle release):

Key Components

  • Workflow - Main orchestration class
  • Context - State management across workflow steps
  • Events - Event-driven communication between steps
  • WorkflowServer - HTTP server for serving workflows as web services

Notes for Claude

  • Always run tests after making changes: uv run dev
  • Never use classes for tests, only use pytest functions
  • Always annotate with types function arguments and return values
  • The project uses async/await extensively
  • Context serialization requires specific JSON format for globals

Autonomous Operation

The following rules apply if you are running in an isolated sandbox environment and have tools to commit and push changes to git

Make sure to install uv as the package manager. Development commands rely on it.

curl -fsSL https://astral.sh/uv/install.sh | sh

Always run tests and pre-commit before committing:

uv run dev
uv run pre-commit run -a

Testing Patterns

We use pytest with idiomatic pytest patterns. Follow these guidelines:

  • No Test Classes: Do not use test classes to organize tests. Write tests as standalone functions. Achieve organization through descriptive function names (e.g., test_create_job_with_invalid_input_raises_error) or by splitting into separate test files.
  • Pytest Fixtures: Use fixtures for setup/teardown and shared test dependencies. Prefer fixtures over manual setup code repeated across tests.
  • Prefer Real Objects Over Mocks: Use simple dataclasses and real objects directly when available rather than mocking them. Only mock external dependencies or things that are truly difficult to instantiate.
  • DRY Test Setup: Do not repeat patches or setup code. Create reusable abstractions—fixtures, helper functions, or module-level constants—that can be shared across tests. Tests can easily be overwhelmed with setup; start from a rich suite of testing utilities to enable many small, expressive tests.
  • Simple Testing Utilities: Testing utilities should be basic—just functions, fixtures, and global variables. Avoid over-engineering test infrastructure.

Coding Style

  • Always use from __future__ import annotations at the top of each test file. Never use string annotations.
  • Include the standard SPDX license header at the top of each file:
    # SPDX-License-Identifier: MIT
    # Copyright (c) 2026 LlamaIndex Inc.
  • Comments are useful, but avoid fluff.
  • Import etiquette
    • Never use inline imports
    • Never use if TYPE_CHECKING imports
    • Exceptions to these rules are made only when there are A) Acceptable circular imports or B) real startup performance issues
  • Only add __init__.py __all__ exports when a file is legitimately needed for public library consumption. Module level imports should not be used internally. For the most part you should never do this unless explicitly requested to do so