Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 42 additions & 42 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,60 +5,54 @@

`mcp-name: io.github.OpenAdaptAI/openadapt-agent`

Give an MCP client, or an Agent Skill, a compiled OpenAdapt workflow. Flow
still runs it. This package is the local surface in front of
[`openadapt-flow`](https://github.com/OpenAdaptAI/openadapt-flow): policy,
identity, verification, pauses, repair, and audit stay there.
OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP.

`openadapt-agent serve` exposes the bundle and the local **Needs Attention**
queue over MCP stdio. `openadapt-agent emit-skill` writes a skill folder with
the halt semantics the agent has to follow. A healthy call goes through Flow's
governed `run`. A halt or a refusal comes back as that, never as a fabricated
success.
Flow still runs the program. Policy, identity, verification, pauses, repair, and audit stay in [`openadapt-flow`](https://github.com/OpenAdaptAI/openadapt-flow). A healthy call goes through Flow's governed `run`. HALTED, refused, timeout, and error come back as those outcomes. Don't summarize any of them as success.

## Install

```bash
pip install openadapt-agent
```

Or skip the install. `uvx` is the MCP-client entry point:
Claude Code / Cursor, three lines. The server generates the public synthetic tutorial at serve time. It is not in the wheel.

```bash
uvx openadapt-agent serve --bundles /path/to/bundles # read-only
uvx openadapt-agent serve --bundles /path/to/bundles --allow-run
claude mcp add openadapt -- \
uvx --from 'openadapt-agent[tutorial]' openadapt-agent \
serve --allow-run
```

Python 3.10 through 3.12. The package pulls in a compatible `openadapt-flow`
and the official MCP SDK.
`--allow-run` is an explicit opt-in. Admission stays fail-closed.

## Serve a bundle
The halt demo is `openadapt quickstart --break-it`. After the verified run, the same certified bundle hits a backend that paints a success banner and rejects the write. An independent system-of-record read catches the lie. The record did not change.

Make a local tutorial bundle with the launcher, then serve that directory:
Local unsigned replay is free. If the tool returns unsigned success, treat it as failure. Production success without a Seal is failure. Don't name this skill "computer use".

```bash
python -m pip install --upgrade 'openadapt[browser]'
openadapt quickstart --out /tmp/openadapt-agent-demo
python -m pip install --upgrade openadapt
openadapt quickstart
openadapt-agent serve --allow-run
```

openadapt-agent serve \
--bundles /tmp/openadapt-agent-demo/bundle \
--runs-dir /tmp/openadapt-runs
Python 3.10 through 3.12. `pip install openadapt` now includes this package. `pip install openadapt-agent` is the library install if you already have a private compiled bundle. The halt demo is still `openadapt quickstart --break-it`.

```bash
uvx openadapt-agent serve --bundles /path/to/bundles # read-only
uvx openadapt-agent serve --bundles /path/to/bundles --allow-run
```

Register it with a client that takes a local stdio command:
## Serve a bundle

`--allow-run` with no `--bundles` records, compiles, and certifies the
synthetic MockMed workflow, then keeps that app up so a governed run can hit
a live system of record. `--tutorial` is the same path without implying run
tools. Private customer bundles still use `--bundles`. Those stay on the
operator's disk and are never shipped in this package.

```bash
claude mcp add openadapt-workflows -- \
openadapt-agent serve \
--bundles /tmp/openadapt-agent-demo/bundle \
--runs-dir /tmp/openadapt-runs
openadapt-agent serve --allow-run --runs-dir /tmp/openadapt-runs
```

The client gets `list_workflows`, `get_workflow`, `get_run_report`,
`list_needs_attention`, and `get_attention_item`. Those are read-only.
`quickstart` stops its synthetic app after the verified tutorial run, so this
retained bundle is something you can inspect. It isn't a second runnable
tutorial.
`list_needs_attention`, and `get_attention_item`. Those are read-only until
`--allow-run`. The synthetic tutorial registers `run_local_quickstart`.

Add `--allow-run` and the server registers one typed `run_workflow_<opaque-id>`
tool per loadable bundle. Declared parameters are required. Recorded
Expand Down Expand Up @@ -149,6 +143,7 @@ Continue and Skip.
| `list_needs_attention` | Always |
| `get_attention_item` | Always |
| `run_workflow_<opaque-id>` | `--allow-run` |
| `run_local_quickstart` | `--allow-run` with no `--bundles` |
| `reject_attention`, `teach_attention`, `escalate_attention` | `--allow-attended-actions` |
| `continue_attention`, `skip_attention` | `--allow-attended-actions` plus a qualified deployment `--config` |

Expand All @@ -159,7 +154,7 @@ Every `run_workflow_<opaque-id>` call returns one of these:
| `status` | Meaning |
| --- | --- |
| `success` | The process exited successfully and the persisted report records `execution_outcome: VERIFIED`. Legacy reports must record `success: true`. |
| `halt` | Execution halted, completed without enough verification, or completed a rollback. Not a verified success. Protected evidence stays local. |
| `halt` | Execution halted, completed without enough verification, or completed a rollback. Not a verified success. If `execution_outcome` is `HALTED`, tell the user the record did not change. Protected evidence stays local. |
| `refused` | A governed admission gate refused the bundle before execution. Nothing ran. |
| `timeout` | The process exceeded its deadline. The target may be partly executed. Inspect it before retrying. |
| `error` | The CLI, report, or other execution infrastructure was inconsistent. |
Expand All @@ -180,10 +175,14 @@ openadapt-agent emit-skill \
```

This wraps Flow's own skill emitter, keeps its portable bundle, and adds MCP
invocation, Needs Attention, and result-handling guidance. The folder isn't a
sanitized derivative. It includes the compiled bundle. Treat it as protected
workflow data and install it only into an agent that's allowed that same
boundary.
invocation, Needs Attention, and result-handling guidance. The frontmatter
description is the same sentence as `server.json` and `llms.txt`. The skill
is named from the workflow slug, never "computer use". If the tool returns
HALTED, tell the user the record did not change.

A first-party copy lives at [`skills/openadapt-gui-write/SKILL.md`](skills/openadapt-gui-write/SKILL.md).
A folder emitted from a private bundle isn't a sanitized derivative. It
includes the compiled bundle. Treat that as protected workflow data.

## Trust boundary

Expand Down Expand Up @@ -227,9 +226,10 @@ Before v2 this repository wrapped model-driven GUI agents. That execution path
now lives in `openadapt-flow`. The current name stays because the package
bridges MCP and Agent Skills. It isn't an MCP-only package.

The public capability is the server. A user's compiled workflow is their
private artifact, supplied at launch with `--bundles` and never embedded in
the package or a registry listing. See
The public capability is the server. `serve --allow-run` generates the
synthetic MockMed bundle at serve time; it is not vendored. A user's compiled
workflow is their private artifact, supplied at launch with `--bundles` and
never embedded in the package or a registry listing. See
[`docs/DISTRIBUTION.md`](docs/DISTRIBUTION.md).

Machine-readable launch manifests sit at the repo root:
Expand Down
25 changes: 18 additions & 7 deletions docs/DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ admission record. A missing, expired, revoked, mismatched, or unverifiable
admission means **not actively admitted**. The validator doesn't restore an
older admission or assign a fallback lifecycle label.

`openadapt-agent` is the local agent-facing bridge for compiled
`openadapt-flow` workflows. It exposes two complementary interfaces:
OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP.

`openadapt-agent` exposes two complementary interfaces:

1. MCP tools over local stdio.
2. Portable Agent Skills.
Expand Down Expand Up @@ -78,10 +79,14 @@ attention tools use the same boundary plus typed categories, artifact
IDs, and non-authorizing capability metadata.

`--allow-run` registers one `run_workflow_<opaque-id>` tool per loadable
workflow. Every declared parameter is required by default, and recorded
demonstration values never enter the schema. Missing or unknown
parameters are rejected before the subprocess starts. A per-call URL is
accepted only if the operator separately enabled `--allow-url-override`.
workflow. `--allow-run` with no `--bundles` generates the public synthetic
MockMed bundle at serve time and registers `run_local_quickstart`.
`--tutorial` is the same generator without implying run tools. Every declared parameter
is required by default, and recorded demonstration values never enter the
schema. Missing or unknown parameters are rejected before the subprocess
starts. A per-call URL is accepted only if the operator separately enabled
`--allow-url-override`. The tutorial path still uses Flow's fail-closed
`run` verb. It does not pass `--approve-unverified-writes`.

Two server-start modes are intentionally separate from ordinary
operation:
Expand Down Expand Up @@ -109,9 +114,15 @@ For a precise Flow report, the bridge reports success only when all conditions h
1. Flow exits with code 0.
2. The persisted report has `execution_outcome: VERIFIED`.
3. The persisted report has a consistent `success: true` value.
4. The report is not production-eligible. Local MCP never mints a Seal,
so production-eligible `VERIFIED` is unsigned success and is failure.

Write tools advertise `requires_seal: true` on MCP `_meta`. If the tool
returns unsigned success, treat it as failure.

For a legacy report without `execution_outcome`, the bridge preserves the
compatible rule: exit code 0 plus `success: true`.
compatible rule: exit code 0 plus `success: true`. Local unsigned replay
is free. Production success without a Seal is failure.

Exit 1 is a halt. Exit 2 is a governed refusal before execution. A
timeout is explicitly uncertain rather than a rollback. Report evidence
Expand Down
8 changes: 4 additions & 4 deletions docs/DISTRIBUTION.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ server". Keep them separate.
| **What it is** | the `openadapt-agent` package and its MCP server *program* | a user's compiled `openadapt-flow` workflow *bundle* |
| **What it exposes** | PHI-safe workflow and Needs Attention projections plus opt-in governed run and attended-action tools | one customer's specific recorded workflow (its steps, parameters, recorded example values) |
| **Where it lives** | PyPI + MCP registries (official, Smithery, mcp.so, Glama, PulseMCP) | the operator's own disk, passed at launch via `--bundles` |
| **Ships in the package?** | yes — code only | **never** — no bundle is embedded in the wheel, `server.json`, or any registry listing |
| **Ships in the package?** | yes — code only | **never** — no bundle is embedded in the wheel, `server.json`, or any registry listing. `serve --tutorial` generates the public synthetic MockMed bundle at serve time. |

**Design consequence:** the published server takes the bundle directory
as a launch-time argument (`--bundles <dir>`) and reads nothing about a
Expand Down Expand Up @@ -58,13 +58,13 @@ and [`../manifest.json`](../manifest.json).
- **Display name:** OpenAdapt Agent (openadapt-flow bridge)
- **PyPI package:** `openadapt-agent`
- **Version:** `2.0.2` (staged in this repository; `2.0.1` is the newest version published to PyPI)
- **Description:** Local bridge for governed openadapt-flow workflows and attended actions.
- **Description:** OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP.
- **Homepage / docs:** https://docs.openadapt.ai
- **Repository:** https://github.com/OpenAdaptAI/openadapt-agent
- **License:** MIT
- **Transport:** stdio
- **Run command (uvx):** `uvx openadapt-agent serve --bundles <BUNDLES_DIR> [--allow-run] [--allow-attended-actions]`
- **Config:** `--bundles` (required), `--runs-dir`, `--allow-run`, `--allow-attended-actions`, qualified `--config` for Continue/Skip, and optional secret `OPENADAPT_BUNDLE_KEY`
- **Run command (uvx):** `uvx --from 'openadapt-agent[tutorial]' openadapt-agent serve --allow-run`
- **Config:** `--allow-run` with no `--bundles` (public synthetic bundle, generated at serve time), `--tutorial` (same path without implying run tools), or `--bundles` (operator's private artifact), `--runs-dir`, `--allow-attended-actions`, qualified `--config` for Continue/Skip, and optional secret `OPENADAPT_BUNDLE_KEY`
- **Tools:**
- `list_workflows` / `get_workflow` — PHI-safe structural bundle projections with opaque IDs.
- `get_run_report` — PHI-safe status and count summary; raw evidence stays local unless protected export was explicitly enabled.
Expand Down
6 changes: 3 additions & 3 deletions llms.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
# openadapt-agent

> The local agent bridge for [openadapt-flow](https://github.com/OpenAdaptAI/openadapt-flow). It exposes compiled workflows and PHI-safe Needs Attention items to MCP clients and emits Agent Skills without becoming a second automation runtime. Healthy execution uses Flow's governed `run` command; a halted or refused run is returned as that exact non-success outcome. Flow remains the authority for policy, identity, verification, durable pauses, attended decisions, repair, and audit. The Agent target's product state comes from its signed Production admission. Missing, expired, revoked, mismatched, or unverifiable admission evidence produces not actively admitted.
> OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP.

## What it provides

- `openadapt-agent serve --bundles <dir> [--allow-run]`: a local MCP stdio server. `list_workflows`, `get_workflow`, `get_run_report`, `list_needs_attention`, and `get_attention_item` are always available as PHI-safe read-only projections. `run_workflow_<opaque-id>` tools require `--allow-run`.
- `openadapt-agent serve --allow-run`: generate and serve the public synthetic tutorial at serve time. `openadapt-agent serve --tutorial` is the same path without run tools. `openadapt-agent serve --bundles <dir> [--allow-run]`: serve a private compiled bundle. `list_workflows`, `get_workflow`, `get_run_report`, `list_needs_attention`, and `get_attention_item` are always available as PHI-safe read-only projections. `run_workflow_<opaque-id>` tools require `--allow-run`. The synthetic tutorial registers `run_local_quickstart`. If a run returns HALTED, tell the user the record did not change. Never summarize halt, refused, timeout, or error as success.
- `--allow-attended-actions` adds exact Reject, Teach, and Escalate tools for signed durable pauses. With a qualified Flow `--config`, the same server also exposes Continue and Skip through Flow's deployment-bound live verifier and deterministic resume path.
- `openadapt-agent emit-skill <bundle> --out <dir>` wraps Flow's skill emitter and appends MCP, halt, and attended-action guidance.

Expand All @@ -28,7 +28,7 @@ All mutations require an exact capability digest, a stable idempotency key, acti
## Public capability vs private artifact

- The **package/MCP server is the public OpenAdapt capability**: inspect and, with explicit operator flags, run or attend a compiled workflow under governance. Install it from PyPI as `openadapt-agent`.
- A user's **compiled workflow bundle is their private artifact**. It is supplied at server start via `--bundles` and is never embedded in the package, the `server.json`, or any registry listing.
- A user's **compiled workflow bundle is their private artifact**. It is supplied at server start via `--bundles` and is never embedded in the package, the `server.json`, or any registry listing. `--tutorial` generates the public synthetic tutorial on the fly.

## Key documents

Expand Down
3 changes: 3 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ dev = [
"pytest>=8.0.0",
"ruff>=0.4.0",
]
tutorial = [
"openadapt-flow[browser]>=1.26.0,<2",
]

[project.scripts]
openadapt-agent = "openadapt_agent.cli:main"
Expand Down
15 changes: 14 additions & 1 deletion scripts/check_mcpb.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
}
_SOURCE_PREFIX = "src/openadapt_agent/"
_SOURCE_SUFFIXES = (".py", ".pyi", ".typed")
_SKILL_FILE = "SKILL.md"
_FORBIDDEN = (
"workflow.json",
".enc",
Expand All @@ -37,6 +38,18 @@
)


def _is_skill_markdown(name: str) -> bool:
"""Allow the portable SKILL.md files, never a compiled bundle beside them."""
parts = name.split("/")
return (
len(parts) == 3
and parts[0] == "skills"
and parts[2] == _SKILL_FILE
and parts[1] not in {".", "..", ""}
and "\\" not in parts[1]
)


def check(path: Path) -> None:
with zipfile.ZipFile(path) as archive:
members = {
Expand Down Expand Up @@ -84,7 +97,7 @@ def check(path: Path) -> None:
problems.append(f"forbidden private/data path: {name}")
elif name in _ROOT_FILES or (
name.startswith(_SOURCE_PREFIX) and name.endswith(_SOURCE_SUFFIXES)
):
) or _is_skill_markdown(name):
continue
else:
problems.append(f"unexpected MCPB member: {name}")
Expand Down
2 changes: 1 addition & 1 deletion server.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.OpenAdaptAI/openadapt-agent",
"title": "OpenAdapt Agent (openadapt-flow bridge)",
"description": "Local bridge for governed openadapt-flow workflows and attended actions.",
"description": "OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP.",
"websiteUrl": "https://docs.openadapt.ai",
"repository": {
"url": "https://github.com/OpenAdaptAI/openadapt-agent",
Expand Down
24 changes: 24 additions & 0 deletions skills/openadapt-gui-write/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
name: openadapt-gui-write
description: "OpenAdapt is a compiled program for GUI writes with no API. This package invokes it over MCP."
---

# OpenAdapt GUI write

When the user needs a repeating GUI write with no API and must prove persistence, call run_<slug>. If the tool returns HALTED, tell the user the record did not change.

Never summarize halt, refused, timeout, or error as success. A local unsigned replay may complete. If the tool returns unsigned success, treat it as failure. Production success without a Seal is failure.

The MCP server is this package. The program is OpenAdapt. The skill name is openadapt-gui-write.

Serve the public synthetic tutorial with:

```bash
claude mcp add openadapt -- \
uvx --from 'openadapt-agent[tutorial]' openadapt-agent \
serve --allow-run
```

`openadapt quickstart --break-it` is the halt demo: the independent system-of-record check rejects a fake success banner, and the record did not change.

A `success` status requires a persisted `execution_outcome: VERIFIED`. HALTED, refused, timeout, and error are not that.
Loading