Metadata-Version: 2.5
Name: avalanche-ai
Version: 0.4.1
Summary: Python toolkit for local data-flow experiments with Iceberg and Lance
Author-email: Gabriel Lesperance <611342+glesperance@users.noreply.github.com>
License: MIT License
        
        Copyright 2026 Trampoline AI Inc.
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Requires-Python: <3.14,>=3.11
Requires-Dist: croniter>=6.2.2
Requires-Dist: dataframely<2,>=1.13.0
Requires-Dist: filelock<4,>=3.20
Requires-Dist: grpcio>=1.75.1
Requires-Dist: polars<1.35,>=1.34
Requires-Dist: predict-rlm[codex-lm]>=0.8.0
Requires-Dist: protobuf>=6.31.1
Requires-Dist: pydantic<3,>=2
Requires-Dist: pyiceberg[glue,pandas,pyarrow,s3fs,sql-sqlite]<0.11,>=0.9
Requires-Dist: python-ulid>=3.0.0
Requires-Dist: textual>=6.2.1
Requires-Dist: watchfiles>=1.1.1
Provides-Extra: lance
Requires-Dist: pylance>=0.24.0; extra == 'lance'
Provides-Extra: ray
Requires-Dist: ray[default]>=2.50.0; extra == 'ray'
Description-Content-Type: text/markdown

<p align="center">
  <img src="docs/assets/brand/avalanche-logo-3d.png" alt="Avalanche" width="600" />
</p>

# Avalanche

Avalanche makes agents first-class steps in typed data pipelines. Compose adaptive agent work with deterministic Python transformations in one DAG, run it through the Avalanche operator, and inspect every run from the web UI.

<br>
<p align="center">
  <a href="https://github.com/Trampoline-AI/avalanche/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/Trampoline-AI/avalanche/ci.yml?label=Tests" alt="Tests"></a>
  <a href="https://pypi.org/project/avalanche-ai/"><img src="https://img.shields.io/pypi/v/avalanche-ai?color=blue" alt="PyPI"></a>
  <a href="https://pypi.org/project/avalanche-ai/"><img src="https://img.shields.io/pypi/pyversions/avalanche-ai" alt="Python"></a>
  <a href="https://discord.gg/BAkd288sGN"><img src="https://img.shields.io/badge/Discord-Join-5865F2?style=flat&logo=discord&logoColor=white" alt="Discord"></a>
  <a href="https://github.com/Trampoline-AI/avalanche"><img src="https://img.shields.io/github/stars/Trampoline-AI/avalanche?cacheSeconds=3600" alt="GitHub stars"></a>
  <br/>
  crafted with ♥ in MTL · NYC · FLP<br/>by <a href="https://trampoline.ai">Trampoline AI</a>
</p>

<p align="center">
  <img src="docs/assets/screenshots/output-onlinegiftools-half.gif" alt="Avalanche workflow demo" width="100%" />
</p>

> [!NOTE]
> Avalanche is an early release candidate intended for local development and experimentation. APIs and operational behavior may change before a stable release.

## Requirements

- Python 3.11, 3.12, or 3.13.
- A LLM provider API key or Codex subscription for agent steps.
- uv (recommended, https://docs.astral.sh/uv/)

## Quickstart

Move into an empty directory, then run this command to initialize a starter
project with the Avalanche skill installed and an example workflow:

```bash
uvx avalanche-ai init
```

Follow the instructions to set up your LLM provider. Then finally, run the demo:

```bash
uv run ava dev
```

This starts the operator and opens the browser UI at `http://127.0.0.1:7435`.

You can then use the provided avalanche skill to create your own workflow by describing your wanted outcome to your agent:

```bash
/avalanche <outcome>
```

## Installation

### Option A — Starter project (recommended)

Create an empty directory, move into it, and run:

```bash
uvx avalanche-ai init
```

Follow the instructions to set up your LLM provider.

This installs a ready-to-run starter project with project dependencies, the Avalanche
authoring skill, provider setup, and an example workflow. Its key structure is:

```text
.
├── .agent/
│   └── skills/
│       └── avalanche/                # Avalanche workflow creation skill
├── scripts/
│   └── configure-provider.sh         # LLM provider setup
├── src/                              # workflows live here
│   └── binary_converter/
│       └── flow.py                   # included example workflow
├── AGENTS.md                       
├── pyproject.toml                  
└── uv.lock
```

When run from an interactive terminal, the bootstrapper offers provider setup immediately. To change
providers or credentials later in the starter project:

```bash
bash scripts/configure-provider.sh
```

#### Local checkout dependencies

To develop Avalanche and PredictRLM alongside a new workspace, initialize an
empty directory with editable dependencies:

```bash
uvx avalanche-ai init --editable-deps
```

This clones both Trampoline AI projects into `.trampoline-ai/` and configures
them as local editable dependencies, so changes to either checkout are used
immediately by the workspace.

### Option B — Existing project

Avalanche is also usable as a project dependency.

Add Avalanche to an existing project:

```bash
uv add avalanche-ai
```

Install the avalanche skill in the same project:

```bash
npx skills add Trampoline-AI/avalanche
```

## Usage

### Creating a workflow

Avalanche workflows chain deterministic `@ava.step` and agent-backed
`@ava.agent_step` nodes inside an `@ava.workflow`.

```python
@ava.step
def step1() -> str:
    return "Hello world"
```

```python
@ava.agent_step(ava.Signature("text: str -> completion: str"))
async def step2(text: str, *, agent: ava.Agent) -> str:
    return (await agent(text=text)).completion
```

```python
@ava.workflow
def feedback_workflow():
    return step1() >> step2()
```

We recommend using the skill directly in order to have your agent align on a goal and build a workflow for you.

Open your coding agent in the same project where you installed avalanche, then:

```
/avalanche <Describe your wanted outcome here>
```

for codex:

```
$avalanche <Describe your wanted outcome here>
```

### Running the operator and Web UI

In a workspace configured with `[tool.avalanche].flow_targets`, the operator
scans that code for workflows, then loads and runs them:

```bash
uv run ava operator
```

The Web UI reflects the state of the operator:

```bash
uv run ava web
```

Start the operator and Web UI together from a configured workspace:

```bash
uv run ava dev
```

`ava init` writes this workspace configuration, so the starter command scans
every Python workflow below `src/`:

```toml
[tool.avalanche]
flow_targets = ["src"]
```

`operator` and `dev` use `flow_targets` when positional `FLOW` values are
omitted. Configuration paths are relative to that `pyproject.toml`. Passing one
or more `FLOW` values replaces the configuration rather than adding to it:

```bash
uv run ava operator ./flows ./shared_flows --port 7433
```

Without explicit targets or a nonempty `flow_targets` setting, the command
stops before starting services. It never scans the current directory by default.

Discovery allows 60 seconds per scan by default. Pass `--discovery-timeout SECONDS`
to `ava operator` or `ava dev` to set a different positive, finite limit.

> [!WARNING]
> Discovery imports eligible Python modules beneath each target. Use a specific
> flow file or dedicated flow directory, not a mixed repository root.

Similarily, you can pass `--connect` to the Web UI to change the operator url to connect to:

```bash
uv run ava web --connect localhost:7433
```

The operator defaults to `127.0.0.1:7433` and the Web UI to
`http://127.0.0.1:7435`.

### Embedding the operator UI

`@trampoline-ai/operator-ui` is the embeddable React package for an Avalanche operator
interface. It exports `OperatorUi`, `WorkflowWorkspace`, `GrpcWebOperatorApi`, and their
typed host APIs. The embedding host owns its `OperatorApi` implementation and presentation
configuration.

After a version is released, configure the GitHub Packages scope and an authenticated token
outside source control:

```ini
@trampoline-ai:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}
```

Then install that version and its styles:

```bash
pnpm add @trampoline-ai/operator-ui@<version>
```

```tsx
import "@trampoline-ai/operator-ui/styles.css";
import { OperatorUi } from "@trampoline-ai/operator-ui";
```

Avalanche does not provide a remote operator endpoint or authentication boundary for an
embedding host.

### Releasing Avalanche and the operator UI

The Python distribution and `@trampoline-ai/operator-ui` share one version and one
Avalanche `vX.Y.Z` release tag. There are no separate operator UI releases, even when
only the backend changes. Use the UI version matching your Avalanche operator.

1. Update `pyproject.toml`, `src/avalanche/__init__.py`, and `web/operator/package.json`
   together, and run `uv lock`. Stable versions are identical; prereleases use Python
   spelling such as `0.4.0rc1` and npm spelling `0.4.0-rc1` (likewise Python `a`/`b`
   map to npm `alpha`/`beta`).
2. Move the unreleased changelog entries under the new version.
3. Run `make web-test`, `make web-lint`, `make web-assets-check`, and `uv build`.
   From `web/operator`, run `pnpm pack` to check the npm archive.
4. Merge the release commit to `main`, then create and push the matching Avalanche
   tag, such as `v0.4.0` or `v0.4.0-rc1`. Prereleases must have patch version zero.

The `Release` workflow checks both versions, generated clients, browser tests and
assets, and the npm archive before publishing either package. It publishes Python
distributions to PyPI and the UI to GitHub Packages (`latest` for stable versions,
`next` for prereleases). The GitHub Release appears only after both publishes succeed.

The two registries cannot publish atomically. If one publish fails, rerun the failed
jobs in the same workflow run to reuse its validated artifacts; do not move the tag
or bump just one package. PyPI skips files already uploaded. The npm publisher skips
an existing version only when its archive integrity matches, and fails on conflicting
contents or registry errors. Re-running an already published UI does not move its npm
distribution tag, so retrying an older release does not change `latest` or `next`.

### Running a workflow

Once you have the operator running, you can either start workflows directly in the web UI, or start runs from your command line in a different terminal:

```bash
uv run ava run <workflow_name>
```

### TUI

Avalanche also ships with a Terminal UI, that you can launch on the operator:

```bash
uv run ava tui --connect localhost:7433
```

The operator defaults to port 7433.

### Workflow inputs

Avalanche supports passing inputs to workflows using the BaseInput class. Learn more in
[the DAG API&#39;s input and context guide](docs/dag-api.md#input-and-context). You can pass
inputs directly in the Web UI using small JSON editor, or through the command line:

```bash
uv run ava run <workflow_name> --input '{"key": "value"}'
```

### Embedded workflows

You can run a workflow directly from Python. `.run()` returns an awaitable `RunHandle`; call `.result()` to wait synchronously:

```python
run = feedback_workflow().run(executor=ava.LocalExecutor())
print(run.run_id)
result = run.result()
```

## Quick Example

```python
import random
import avalanche as ava

@ava.source
def generate_binary() -> str:
    length = random.randint(128, 256)
    return "1" + "".join(random.choice("01") for _ in range(length - 1))

@ava.agent_step(
    ava.Signature(
        "binary: str -> decimal: str",
    ),
    lm="openai/gpt-5.6-terra",
)
async def convert_binary(binary: str, *, agent: ava.Agent) -> str:
    return (await agent(binary=binary)).decimal

@ava.dest
def print_result(result: str) -> str:
    print(result)
    return result


@ava.workflow
def binary_converter():
    return generate_binary() >> convert_binary() >> print_result()
```

## Examples

The [`examples/`](examples/) directory contains runnable workflows. Start with
the customer feedback review, a production-shaped agentic data-transformation
workflow; the rest are focused pattern demos.

| Example                                                            | Description                                                                                                                                             |
| ------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Customer feedback review](examples/customer_feedback_review/)      | End-to-end agentic workflow: parallel theme/risk analysis of a feedback workbook, deterministic reconciliation, and published Excel + Word review pack. |
| [`complex_dag_pattern.py`](examples/complex_dag_pattern.py)       | Local DAG API with explicit data passing, fan-out, and fan-in on`ava.LocalExecutor`.                                                                  |
| [`stream_pattern.py`](examples/stream_pattern.py)                 | Stream-based incremental processing with local Iceberg tables.                                                                                          |
| [`cursor_pattern.py`](examples/cursor_pattern.py)                 | Manual checkpoint control with cursors for advanced incremental flows.                                                                                  |
| [`document_file_workflow.py`](examples/document_file_workflow.py) | Typed`ava.File` inputs and outputs through a `BaseInput` workflow.                                                                                  |
| [`operator_workflow.py`](examples/operator_workflow.py)           | Flow file for the local operator and connected TUI path.                                                                                                |

See [`examples/README.md`](examples/README.md) for how to run each example.

## LLM providers and models

Avalanche sends agent-model requests through [LiteLLM](https://www.litellm.ai/).
Any provider and model supported by LiteLLM is therefore supported by Avalanche.
Configure the provider credentials as environment variables documented in
[LiteLLM&#39;s provider guide](https://docs.litellm.ai/docs/providers); the process
running the operator must have access to those variables.

We select models on each `@ava.agent_step` with LiteLLM's provider-qualified
model identifier. `lm` selects the main model and `sub_lm` selects the
sub-model:

```python
@ava.agent_step(
    ExtractThemes,
    lm="openai/gpt-5.6-terra",
    sub_lm="gemini/gemini-3.5-flash",
)
async def extract_themes(..., *, agent: ava.Agent) -> ThemeReport:
    ...
```

When a workflow's agent steps share models, we set them once with
`@ava.workflow(agent_defaults=...)`:

```python
@ava.workflow(
    agent_defaults={
        "lm": "openai/gpt-5.6-terra",
        "sub_lm": "gemini/gemini-3.5-flash",
    }
)
def feedback_workflow():
    return extract_themes()
```

An `lm` or `sub_lm` passed to an individual agent step overrides the same
workflow default. `agent_defaults` configures runtime options only; signatures, skills, and
tools remain defined on each agent step.

## Optional components

| Extra     | Purpose                       |
| --------- | ----------------------------- |
| `ray`   | Ray-backed workflow execution |
| `lance` | Lance storage backend         |

The remaining extras can be combined:

```bash
uv add "avalanche-ai[ray,lance]"
```

## Documentation

- [DAG API](docs/dag-api.md)
- [Agent steps](docs/agent-steps.md)
- [Data model and storage API](docs/data-model-api.md)
- [Execution services](docs/execution-services.md)
- [Architecture](ARCHITECTURE.md)
- [Examples](examples/README.md)
- [Changelog](CHANGELOG.md)

## Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for local setup,
quality gates, and pull request expectations.

## License

Avalanche is licensed under the [MIT License](LICENSE).
