Skip to content

First Steps

Scaffold a Project

Use the hbia init command to create a new project:

hbia init my_project
cd my_project

This creates the following structure:

my_project/
├── flows/
│   └── example_flow.yaml      # Sample flow definition
├── vertices/
│   ├── __init__.py
│   └── greetings.py            # Sample vertex handlers
├── tests/
│   ├── __init__.py
│   └── test_flow_example.py    # Sample test
├── AGENTS.md                   # AI context file
├── conftest.py                 # Pytest configuration
├── manage.py                   # Entry point — run your flows
├── settings.py                 # HBIA settings
├── hbia.yaml                   # Project configuration
└── README.md                   # Project documentation

What Each File Does

flows/ — Contains your YAML flow definitions. Each file defines a directed acyclic graph of operations.

vertices/ — Contains your Python handler functions. Each vertex in a flow maps to a function here. The scaffolded project includes greetings.py with two sample handlers (hello and shout).

manage.py — Project entry point. Run python manage.py to execute the default flow, or python manage.py --flow greet to run a specific one.

tests/ — Contains your test files using HBIA's testing framework.

AGENTS.md — Auto-generated documentation that AI agents read to understand your project. Regenerate it with hbia context --write.

settings.py — HBIA configuration. Controls caching, parallelism, async execution, and other runtime behavior.

hbia.yaml — Project-level configuration declaring where flows and handlers live.

Understanding the Settings

Open settings.py to see the default configuration:

SETTINGS = {
    "GRAPH_FILE": "flows/example_flow.yaml",
    "HANDLER_MODULES": ["vertices"],
    "CACHE_ENABLED": False,
    "PARALLEL_ENABLED": False,
    "ASYNC_ENABLED": False,
    "MAX_WORKERS": 4,
}

Every setting can also be controlled via environment variables prefixed with HBIA_:

export HBIA_CACHE_ENABLED=true
export HBIA_PARALLEL_ENABLED=true
export HBIA_MAX_WORKERS=8

Your First Vertex

A vertex is just a Python function. Create a file vertices/greet.py:

def normalize_name(name: str) -> dict:
    """Normalize a user's name to title case."""
    return {"name": name.strip().title()}


def greet_user(name: str) -> dict:
    """Generate a greeting for the user."""
    return {"greeting": f"Hello, {name}!"}

Each function:

  • Receives keyword arguments matching its declared inputs.
  • Returns a dictionary with keys matching its declared outputs.

That's it. No base classes, no decorators required, no framework boilerplate.

Your First Flow

Create a file flows/greet.yaml:

flow:
  greet:
    normalize_name:
      handler: vertices.greet.normalize_name
      effect: pure
      version: "1"
      inputs:
        name: str
      outputs:
        name: str
      next:
        - greet_user

    greet_user:
      handler: vertices.greet.greet_user
      effect: pure
      version: "1"
      inputs:
        name: normalize_name.name
      outputs:
        greeting: str

Let's break this down:

  • flow: greet: — Declares a flow named greet.
  • normalize_name: — Defines a vertex. The key is the vertex name.
  • handler: — Dotted path to the Python function.
  • effect: pure — This vertex has no side effects. It can be cached, retried, and parallelized safely.
  • version: "1" — Version tracking. When you change a vertex, bump the version.
  • inputs: — What this vertex receives. name: str means it expects a name parameter of type str.
  • outputs: — What this vertex produces.
  • next: — Which vertices execute after this one. This creates the edges in the DAG.

In greet_user, the input name: normalize_name.name is a data binding: it reads the name output from the normalize_name vertex. Any input value containing a . is treated as a reference to another vertex's output.

Entry Points

HBIA automatically detects the entry point of each flow. The entry point is the vertex that is not listed in any next field — it has no incoming edges. In the example above, normalize_name is the entry point because no other vertex lists it in next.

Run the Flow

hbia run flows/greet.yaml --handlers vertices

Validate the Flow

Before running, you can validate the YAML structure:

# Check YAML syntax and DSL structure
hbia validate flows/greet.yaml

# Check graph structure (cycles, missing edges, etc.)
hbia graph-validate flows/greet.yaml

Inspect the Topology

See how HBIA will execute the flow:

hbia inspect flows/greet.yaml

This shows:

  • All vertices and their properties
  • Execution stages (which vertices run in parallel)
  • Source and sink vertices
  • Edge connections

Add --json for machine-readable output:

hbia inspect flows/greet.yaml --json

Visualize the DAG

# ASCII art (no extra dependencies)
hbia viz flows/greet.yaml --ascii

# Graphviz (requires graphviz extra)
hbia viz flows/greet.yaml

What's Next?

Now that you understand the basics, let's dive deeper into flow definitions:

Defining Flows