Metadata-Version: 2.4
Name: andon-ai
Version: 0.1.0
Summary: Andon SDK and CLI for authoring, deploying, and running workflows
Requires-Python: >=3.13
Requires-Dist: httpx>=0.28
Requires-Dist: packaging>=24.0
Requires-Dist: pydantic>=2.0
Requires-Dist: typing-extensions>=4.15
Description-Content-Type: text/markdown

# Andon SDK and CLI (`andon-ai`)

Andon is a Python SDK for building durable, document-centric workflows with
typed steps, LLM agents, human review, and integrations. Authors define the
workflow; the Andon platform handles execution, checkpointing, files, and
operations.

Installing `andon-ai` provides the `andon` command and the `andon_dsl` Python
package. Python 3.13 or newer and [uv](https://docs.astral.sh/uv/) are required.

## Create a workspace

Start in an empty directory:

```bash
mkdir claims-workflow
cd claims-workflow
uvx andon-ai init
uv sync
```

`andon init` creates `andon.toml`, a deployable `andon/` package, a sample
workflow and test, and local project configuration. It preserves files that
already exist, so an empty directory is the supported starting point.

The generated `AGENTS.md` routes coding agents to the authoring contract and
tool catalog that match the installed SDK.

## Build an email workflow

This workflow reads unread Gmail messages, summarizes them with an agent, and
emails the digest. Save it as `andon/workflows/inbox.py`:

```python
from dataclasses import dataclass

from andon_dsl.agents import Agent, StepContext
from andon_dsl.integrations import EmailFilter, EmailMessage, Gmail
from andon_dsl.workflows import map, step, workflow


@dataclass
class InboxInput:
    recipient: str
    limit: int = 10


@dataclass
class EmailSummary:
    sender: str
    subject: str
    summary: str


summarizer = Agent(
    model_family="small",
    input_type=EmailMessage,
    output_type=EmailSummary,
    system_instructions="Summarize inbound email clearly and concisely.",
)


@step(connections=["gmail"])
async def read_inbox(ctx: StepContext, input: InboxInput) -> list[EmailMessage]:
    gmail = await ctx.connect(Gmail, "gmail")
    return await gmail.list_messages(
        filter=EmailFilter(is_unread=True),
        limit=input.limit,
    )


@step
async def summarize(message: EmailMessage) -> EmailSummary:
    return await summarizer(
        "Summarize this email from {{sender}}.\n"
        "Subject: {{subject}}\n\n"
        "{{body_text}}",
        inputs=message,
    )


@step(connections=["gmail"])
async def send_digest(
    ctx: StepContext,
    recipient: str,
    summaries: list[EmailSummary],
) -> str:
    gmail = await ctx.connect(Gmail, "gmail")
    body = "\n\n".join(
        f"{item.subject} — {item.sender}\n{item.summary}" for item in summaries
    )
    return await gmail.send(
        to=[recipient],
        subject="Andon inbox digest",
        body=body or "No unread messages.",
    )


@workflow()
def process_inbox(input: InboxInput) -> str:
    messages = read_inbox(input)
    summaries = map(summarize, messages)
    return send_digest(input.recipient, summaries)
```

Declare the workflow in `andon.toml`:

```toml
[[workflows]]
name = "process_inbox"
path = "andon/workflows/inbox.py"
```

The connection name passed to `ctx.connect()` refers to Gmail credentials
configured for the current Andon organization. The same name must appear in
the step's `connections=[...]` allow-list.

## Core concepts

- **Workflows** are declarative graphs of steps and control-flow primitives.
  Their bodies are traced during deployment and do not run as ordinary Python
  during workflow execution.
- **Steps** are typed Python functions and the durability boundary. Successful
  results are checkpointed; external side effects should be safe to repeat if
  an interrupted attempt runs again.
- **Agents** are typed LLM-powered components declared at module scope and
  awaited inside steps. Runtime prompts are Handlebars templates over the
  agent's typed inputs.
- **Tools and toolsets** give agents explicitly selected capabilities. Andon
  provides platform tools and curated toolsets, and authors can define their
  own model-callable functions with `@tool`.
- **Connections** provide typed access to organization-configured email through
  the Gmail protocol without exposing credentials to workflow code.
- **FileRef** values represent uploaded files and generated artifacts. Keep
  documents and large intermediate outputs behind `FileRef` rather than
  passing their bytes or full text through step results.

Workflow bodies use primitives such as `map`, `parallel`, `branch`, `loop`,
`wait_for_event`, `wait_for_review`, `sleep`, and `run_workflow`. Put ordinary
Python branching, iteration, parsing, and integration glue inside steps.

## Tools and toolsets

Platform tools and curated toolsets are imported from `andon_dsl.tools` and
opted into an agent through `tools=[...]`. Authors can combine them with their
own `@tool` functions:

```python
from andon_dsl.agents import Agent
from andon_dsl.tools import tool
from andon_dsl.tools.toolsets import document_analysis


@tool
def normalize_vendor_name(name: str) -> str:
    """Return a normalized vendor name for matching."""
    return " ".join(name.lower().split())


analyst = Agent(
    tools=[*document_analysis.tools, normalize_vendor_name],
)
```

The installed SDK is the source of truth for platform capabilities:

```bash
uv run andon tools         # print tools, toolsets, signatures, and descriptions
uv run andon tools --json  # emit the same catalog as structured JSON
```

## Validate, deploy, and run

An organization admin creates API keys in the console's
[Settings page](https://app.andonai.com/settings). Keys carry a role:
`admin` keys can deploy and activate; `operator` keys can start and watch
runs. Expose the key to the CLI:

```bash
export ANDON_API_KEY="ak-..."
```

The CLI uses `https://app.andonai.com/` by default. Set `ANDON_API_URL` only
when targeting a different Andon environment.

```bash
uv run andon validate
uv run pytest
uv run andon deploy --no-activate
uv run andon run process_inbox \
  --deployment-id <deployment-id> \
  --input-json '{"recipient":"ops@example.com","limit":10}'
uv run andon runs watch <run-id>
```

`andon validate` performs local manifest and static source validation.
`andon deploy` publishes the full local `andon.toml` plus `andon/` snapshot,
compiles and type-checks its workflows, and activates the deployment unless
`--no-activate` is passed. Publishing replaces the remote workspace snapshot,
so remote files absent from the local tree are deleted.

`andon run` starts a deployed workflow. Local paths supplied at typed
`FileRef` input positions are uploaded before run creation.

## Authoring reference

Use the references bundled with the installed SDK before editing a workspace:

```bash
uv run andon docs
uv run andon tools
```

Here `uv run` executes a command in the workspace environment, while
`andon docs` prints the complete, version-matched authoring contract to the
terminal. It is separate from `andon run <workflow>`, which starts a workflow
run.

The authoring contract covers workflow restrictions, primitives, durable
identity, retries, agent settings, files, reference data, testing, and other
sharp edges. The generated `andon/AGENTS.md` points coding agents to this
contract and the installed tool catalog.

## Public imports

| Package | Purpose |
|---|---|
| `andon_dsl.workflows` | Workflow and step decorators plus control-flow primitives. |
| `andon_dsl.agents` | Agent declarations, prompt content, contexts, model settings, and usage limits. |
| `andon_dsl.tools` | User-authored tools and platform tool stubs; curated bundles live in `andon_dsl.tools.toolsets`. |
| `andon_dsl.resources` | `FileRef`, document result types, reference data helpers, and schema extensions. |
| `andon_dsl.integrations` | The Gmail connection protocol and shared email types for `ctx.connect()`. |
| `andon_dsl.errors` | Public authoring and execution error types. |
