Metadata-Version: 2.4
Name: mashpy
Version: 0.21.0
Summary: Self-hosted durable runtime for code-authored agents and workflows.
Author: imsid
License: Apache-2.0
Project-URL: Homepage, https://github.com/imsid/mashpy
Project-URL: Documentation, https://github.com/imsid/mashpy#readme
Project-URL: Repository, https://github.com/imsid/mashpy
Project-URL: Issues, https://github.com/imsid/mashpy/issues
Project-URL: Changelog, https://github.com/imsid/mashpy/blob/main/CHANGELOG.md
Keywords: agents,cli,mcp,llm
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
License-File: NOTICE
Requires-Dist: aiosqlite>=0.20.0
Requires-Dist: anthropic>=0.39.0
Requires-Dist: dbos>=2.19.0
Requires-Dist: fastapi>=0.115.0
Requires-Dist: google-genai>=0.1.0
Requires-Dist: httpx>=0.28.0
Requires-Dist: mcp>=0.1.0
Requires-Dist: openai>=1.57.4
Requires-Dist: pydantic>=2.0
Requires-Dist: psycopg[binary]>=3.2.0
Requires-Dist: psycopg_pool>=3.2.0
Requires-Dist: prompt_toolkit>=3.0.36
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: PyYAML>=6.0.2
Requires-Dist: requests>=2.31.0
Requires-Dist: rich>=13.7.1
Requires-Dist: starlette>=0.52.0
Requires-Dist: tomli>=2.0.1; python_version < "3.11"
Requires-Dist: uvicorn>=0.30.0
Provides-Extra: dev
Requires-Dist: build>=1.2.2; extra == "dev"
Requires-Dist: pyinstaller>=6.0; extra == "dev"
Requires-Dist: pytest>=8.3.0; extra == "dev"
Requires-Dist: twine>=6.1.0; extra == "dev"
Dynamic: license-file

# Mash

[![CI](https://github.com/imsid/mashpy/actions/workflows/ci.yml/badge.svg)](https://github.com/imsid/mashpy/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/mashpy.svg)](https://pypi.org/project/mashpy/)
[![Python versions](https://img.shields.io/pypi/pyversions/mashpy.svg)](https://pypi.org/project/mashpy/)
[![License: Apache-2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)

Mash is a self-hosted durable runtime for code-authored automations using workflows with agents. A workflow is an
ordered pipeline of typed steps, a step is deterministic Python or one run of a
harnessed agent, and control flow stays in code.

Mash gives you a Python `AgentSpec` contract for defining agents, a
`WorkflowSpec` for authoring step pipelines, a `HostBuilder` that composes both
into a deployable pool, a FastAPI server for deployment, and a CLI/API for
interacting with a running host.

It's designed around [Host-to-Agent Protocol (H2A)](rfcs/host-to-agent-protocol.md) that 
standardizes interactions between user applications and agents. 

## What Mash Provides

- **Workflows**: ordered pipelines of typed steps, durable and observable.
  A step is deterministic Python or one agent run; each step's output threads
  into the next step's input with schema checks at every edge. The pipeline is
  code you can read, diff, test, and replay.
- **Agent harness**: the agent loop runs inside a durable request engine with
  tools, skills, memory, and structured output. Requests are recorded as
  replayable runtime events; retries, restarts, and long-running work just
  work.
- **Frontier and open-source models**: built-in adapters for Anthropic, OpenAI,
  and Gemini, and any open-source model served over a Chat Completions endpoint,
  self-hosted with vLLM or Ollama or hosted on OpenRouter. Each agent picks its
  model in one line of `build_llm()`.
- **Self-hosted interfaces**: HTTP API with streaming, CLI, and interactive REPL,
  all on one Postgres. Deploy locally, in Docker, or on any cloud.
- **Multi-agent composition**: define a primary agent, add specialized subagents,
  and compose workflows behind a single host. Agents delegate to each other
  without a separate coordination layer.
- **Human-in-the-loop**: agents can pause for approval or ask users questions
  mid-execution. Interactions survive host restarts.
- **Observability**: span trees, trace analysis, telemetry API, built-in
  dashboard, and CLI trace inspection. No external APM needed.
- **Synthetic evals**: generate a test dataset and scoring rubric from a
  host's declared capabilities, run experiments that snapshot the live host,
  and compare quality and cost across runs before the first user message.
  Datasets, rubrics, and experiment results live in the built-in dashboard.

```
                  ┌─────────────────────────────────────────┐
                  │          Durable Request                │
                  │                                         │
                  │   ┌─ context ─── memory ──┐             │
                  │   │                       │             │
request ────────► │   │     Agent Loop        │ ──► signals │
(cli/api)         │   │ think → act → observe │      │      │
                  │   │                       │      ▼      │
                  │   └─ tools ───── skills ──┘  structured │
workflow step ──► │        ▲                      output    │
(api/cli)         │        │ user interaction               │
                  │        ▼ (approval / ask-user)          │
                  │                                         │
                  │       resumable · replayable            │
                  └─────────────────────────────────────────┘
```

A request from a user and a step in a workflow ride the same durable loop.

See [Mash under the hood](docs/posts/mash-under-the-hood.md) for a deeper look
at each capability, and the [product brief](docs/posts/product-brief.md) for
the pitch.

## Quick Start

**Install:**

```bash
# install the library
uv add mashpy

# install the `mash` CLI on your PATH
uv tool install mashpy 
```

**Define your agents:**

Each agent is an `AgentSpec` subclass. It names itself, picks an LLM, and
declares a system prompt, tools, skills and agent config.

```python
## my_app/agents.py

from mash import AgentSpec
from mash.core.config import AgentConfig
from mash.core.llm import AnthropicProvider
from mash.skills import SkillRegistry
from mash.tools import ToolRegistry


class ConciergeAgent(AgentSpec):
    def get_agent_id(self):
        return "concierge"

    def build_tools(self):
        return ToolRegistry()

    def build_skills(self):
        return SkillRegistry()

    def build_llm(self):
        return AnthropicProvider(app_id="concierge")

    def build_agent_config(self):
        return AgentConfig(
            app_id="concierge",
            system_prompt=(
                "You are the concierge. Answer the user directly, and "
                "delegate research-heavy questions to the research subagent."
            ),
        )


class ResearchAgent(AgentSpec):
    def get_agent_id(self):
        return "research"

    def build_tools(self):
        return ToolRegistry()

    def build_skills(self):
        return SkillRegistry()

    def build_llm(self):
        return AnthropicProvider(app_id="research")

    def build_agent_config(self):
        return AgentConfig(
            app_id="research",
            system_prompt="You handle research-heavy questions in depth.",
        )
```

**Author the workflow:**

The workflow is the automation: an ordered pipeline of typed steps that code
owns end to end. Use a `CodeStep` for deterministic Python and an `AgentStep`
when the work needs an agent.

```python
## my_app/workflows.py

from pydantic import BaseModel

from mash import AgentStep, CodeStep, StepContext, WorkflowSpec


class ResearchRequest(BaseModel):
    topic: str


class ResearchPlan(BaseModel):
    topic: str
    questions: list[str]


class ResearchBrief(BaseModel):
    summary: str
    sources: list[str]


def plan_research(
    request: ResearchRequest,
    _context: StepContext,
) -> ResearchPlan:
    return ResearchPlan(
        topic=request.topic,
        questions=[
            f"What are the key facts about {request.topic}?",
            f"What should a reader understand about {request.topic}?",
        ],
    )


RESEARCH_BRIEF = WorkflowSpec(
    workflow_id="research-brief",
    input_model=ResearchRequest,
    steps=[
        CodeStep(
            step_id="plan",
            run=plan_research,
            input=ResearchRequest,
            output=ResearchPlan,
        ),
        AgentStep(
            step_id="research",
            agent_id="research",
            input=ResearchPlan,
            output=ResearchBrief,
        ),
    ],
)
```

The `CodeStep` output becomes the `AgentStep` input. Mash validates both edges,
runs each step durably, and uses the last step's output as the workflow result.

**Build the pool:**

The pool is the unit of deploy: agents and workflows registered together.

```python
## my_app/host.py

from mash import AgentMetadata, HostBuilder

from .agents import ConciergeAgent, ResearchAgent
from .workflows import RESEARCH_BRIEF


def build_pool():
    pool = (
        HostBuilder()
        .agent(
            ConciergeAgent(),
            metadata=AgentMetadata(
                display_name="Concierge",
                description="Front-door agent that answers users and delegates.",
                capabilities=["conversation", "delegation"],
                usage_guidance="Default entry point for user requests.",
            ),
        )
        .agent(
            ResearchAgent(),
            metadata=AgentMetadata(
                display_name="Research",
                description="Handles research-heavy questions in depth.",
                capabilities=["research", "analysis"],
                usage_guidance="Use for questions that need digging.",
            ),
        )
        .workflow(RESEARCH_BRIEF)
        .build()
    )
    return pool
```

A pool can also be workflows alone. A workflow of pure `CodeStep`s references
no agents, and the resulting pool serves only workflow runs:

```python
def build_pool():
    # EXPORT_METRICS is a WorkflowSpec of pure CodeSteps; no agents needed.
    return HostBuilder().workflow(EXPORT_METRICS).build()
```

**Configure the environment:**

The host needs an LLM key and a Postgres URL for its durable runtime. Put
them in a `.env` file the host loads on start:

```bash
# .env
ANTHROPIC_API_KEY=sk-ant-...
MASH_DATABASE_URL=postgresql://user:pass@localhost:5432/mash
```

**Start the host:**

```bash
mash host serve --host-app my_app.host:build_pool --host 127.0.0.1 --port 8000
```

**Browse available agents:**
```bash
mash browse
```

**Compose an assistant host with primary and subagents:**
```bash
mash compose --host assistant --primary concierge --subagents research \
  --workflows research-brief
```

**Talk to the host or execute `/` commands using Mash repl:**
```bash
mash repl --host assistant
```

## Key Concepts

| Concept | What it is |
|---|---|
| **AgentSpec** | Abstract contract defining one agent (id, tools, skills, LLM, config) |
| **HostBuilder** | Fluent builder that composes agents, workflows, and hosts into a Pool |
| **Pool** | The deployed pool of role-less agents the API server runs |
| **Host** | A composition over the pool (primary + subagents + workflows), defined in code or dynamically over the API |
| **ToolRegistry** | Register callable tools; built-ins include Bash, AskUser, InvokeSubagent |
| **SkillRegistry** | Markdown instruction bundles loaded on demand via a meta-tool |
| **LLMProvider** | Adapters for Anthropic, OpenAI, and Gemini |
| **OSSCompatibleProvider** | Runs open-source models (Gemma, Qwen, DeepSeek) over any Chat Completions endpoint, self-hosted (vLLM, Ollama) or hosted (OpenRouter); chosen in `build_llm()` like any provider |
| **WorkflowSpec** | Ordered pipeline of typed steps (`CodeStep` / `AgentStep`); runs are durable and observable |
| **Eval / Experiment** | A generated dataset and rubric bound to a host; an experiment runs the dataset against the host, snapshots its composition, and scores results with an LLM judge |

## Mash Pilot

Pilot is a command-line guide to the Mash codebase, built on the Mash SDK and
shipped in this repo at [`src/pilot/`](src/pilot/). Its agents specialize in
Mash's own modules — so instead of reading docs or grepping the source, you ask
Pilot and it answers from the actual source tree. It also ships the
`pilot-changelog` workflow and the `build-mash-agent`/`build-mash-workflow`/
`build-mash-host` scaffolding skills.

```bash
docker run -d --name pilot -p 8000:8000 \
  -e GEMINI_API_KEY=... -e OPENROUTER_API_KEY=sk-or-... \
  -v pilot-data:/var/lib/pilot ghcr.io/imsid/mashpy-pilot:latest

curl -fsSL https://raw.githubusercontent.com/imsid/mashpy/main/install.sh | sh
pilot repl --host guide
```

See [`src/pilot/README.md`](src/pilot/README.md) for the guide team, the
required keys and model overrides, the shipped workflow, and scaffolding your
own app.

## Build with a Coding Agent

This repo includes [`CLAUDE.md`](CLAUDE.md) so coding agents like Claude Code,
Codex, and Cursor can scaffold a Mash-powered agent from a natural language
prompt. Copy it into your project or point your agent at this repo to get
started. The Pilot guide (above) also carries the `build-mash-agent`,
`build-mash-workflow`, and `build-mash-host` skills for interactive
scaffolding from the REPL.

## Documentation

- [Product brief](docs/posts/product-brief.md) — the pitch: why the application-to-agent seam needs a standard
- [Mash under the hood](docs/posts/mash-under-the-hood.md) — what Mash offers and where it fits
- [Synthetic evals](docs/posts/synthetic-evals.md) — datasets, rubrics, experiments, and scoring for the cold-start problem
- [Deployment guide](docs/posts/how-to-deploy.md) — Docker, cloud, horizontal scaling
- [Building agent CLIs](docs/posts/building-agent-clis.md) — custom CLI development
- [CLAUDE.md](CLAUDE.md) — full SDK reference for coding agents
- [Package overview](src/mash/README.md) — subsystem boundaries and module guides
- [Contributing](CONTRIBUTING.md) — development setup, tests, repo structure

## Contributing

Contributions are welcome. See [CONTRIBUTING.md](CONTRIBUTING.md) for setup,
tests, and the pull request flow, and [SECURITY.md](SECURITY.md) for reporting
vulnerabilities. Release notes live in [CHANGELOG.md](CHANGELOG.md).

## License

Mash is licensed under the [Apache License 2.0](LICENSE).
