Metadata-Version: 2.4
Name: enactable
Version: 1.0.0
Summary: CLI and toolkit to generate /.llm/ layers conformant to ENACTABLE/1.0 from OpenAPI/Swagger
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: pydantic>=2.0
Provides-Extra: llm
Requires-Dist: anthropic>=0.40; extra == "llm"
Requires-Dist: openai>=1.0; extra == "llm"
Provides-Extra: yaml
Requires-Dist: pyyaml>=6.0; extra == "yaml"
Provides-Extra: all
Requires-Dist: anthropic>=0.40; extra == "all"
Requires-Dist: openai>=1.0; extra == "all"
Requires-Dist: pyyaml>=6.0; extra == "all"

# enactable — CLI for ENACTABLE/1.0

Generate, validate and serve `/.llm/` layers conformant to **ENACTABLE/1.0** from an existing OpenAPI/Swagger specification.

The principle: a Swagger file describes *how* to call an API. ENACTABLE describes *why* an endpoint exists, which human intention triggers it, what effects it has, and how much autonomy to give an agent. This CLI infers the first layer automatically and guides you in completing what an LLM cannot deduce.

---

## Installation

```bash
pip install enactable
# optional, for LLM-assisted generation:
pip install "enactable[all]"   # anthropic + openai + pyyaml
```

Requires Python >= 3.9. The only core dependency is `pydantic`.

---

## The four commands

### `generate` — from OpenAPI to a `/.llm/` draft

```bash
enactable generate ./swagger.json -o ./.llm --app-id com.acme.app
```

Reads the OpenAPI spec (2.0 or 3.x, JSON or YAML), infers `manifest`, `actions`, `forms`, `permissions` and a `context` skeleton, and writes the files to the output directory.

With `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` set in the environment it uses an LLM for richer intents and hints. Without a key, it falls back to a **deterministic heuristic generator** that infers from patterns (HTTP method, field naming): it always works, even offline.

`--llm` flag: `auto` (default), `anthropic`, `openai`, `heuristic`.

### `validate` — check conformance and consistency

```bash
enactable validate ./.llm
```

Two levels of checks: schema conformance and **cross-document consistency**. It enforces the safety rules of the draft, including:

- an irreversible action **must** require confirmation
- an irreversible action cannot be `autonomous`
- permissions cannot reference non-existent actions
- forms cannot reference non-existent actions
- write operations should declare their `side_effects`

It exits with a non-zero code if it finds errors, so it can be used in CI.

### `review` — complete the non-inferable fields

```bash
enactable review ./.llm
```

Interactive wizard for what no LLM can deduce from the API: which fields must never be inferred (`cannot_infer`), the domain business rules, and a review of the proposed autonomy for each action.

### `serve` — expose the layer over HTTP

```bash
enactable serve ./.llm -p 3000
```

Standard-library server (zero dependencies) that mounts:
- `GET /.llm/` → machine-readable index of the documents
- `GET /.llm/<doc>.json` → the individual documents, with an `X-Enactable-Version` header and CORS

---

## Typical workflow

```bash
enactable generate ./openapi.json -o ./.llm   # 1. automatic draft
enactable review ./.llm                        # 2. complete domain and safety
enactable validate ./.llm                      # 3. check conformance
enactable serve ./.llm                         # 4. expose the layer
```

---

## Architecture

```
enactable/
├── core/
│   ├── models.py       # ENACTABLE schema as Pydantic models
│   ├── validator.py    # conformance + cross-document consistency + safety rules
│   └── serializer.py   # EnactableSpec <-> /.llm/ files
├── generator/
│   ├── parser.py       # OpenAPI 2.0 / 3.x -> internal representation
│   ├── llm.py          # LLM provider + deterministic heuristic fallback
│   ├── generator.py    # orchestration parser -> LLM -> EnactableSpec
│   └── prompts/        # prompts for actions, forms, permissions
├── cli/
│   ├── main.py         # argparse entry point
│   ├── output.py       # colored output (ANSI)
│   └── commands/       # command implementations
└── server/
    └── server.py       # HTTP server for the /.llm/ layer
```

The key design point: the **generator is not required for correctness**. It produces a draft; the `validator` is the authority on conformance. A hand-written spec passes through the same validator. Generator and framework have distinct roles.

---

## What is inferable and what is not

| Inferable from the API (automatic) | Requires human input (`review`) |
|---|---|
| `intent`, `side_effects`, `reversible` | domain `business_rules` |
| `requires_confirmation` | `cannot_infer` (sensitive fields) |
| `capabilities`, `auth.type` | final safety autonomy |
| `forms` with basic hints | `disambiguation` on edge cases |

The CLI is honest about this boundary: it generates everything deducible, flags the gaps explicitly, and does not pretend that safety decisions can be automated.

---

Created by Antonio Stassi · 2026 · Draft 1.0
