Metadata-Version: 2.5
Name: gravity-schema
Version: 0.12.2
Summary: Gravity agent manifest contract — models, validation, and JSON Schema export
License-Expression: Apache-2.0
License-File: LICENSE
License-File: NOTICE
Requires-Python: >=3.11
Requires-Dist: pydantic>=2.10
Requires-Dist: pyyaml>=6.0
Description-Content-Type: text/markdown

# gravity-schema

The Gravity agent manifest contract: its models, validation, the capability vocabulary and JSON Schema export.
It is the one definition the [gravity CLI](https://pypi.org/project/gravity-cli/), the agent runner and Gravity's
platform share, so a manifest that passes here passes everywhere. If you build agents, use `gravity-cli`: it
depends on this package, in the same version.

```bash
pip install gravity-schema
```

## Two contracts

The manifest's `contract` picks one, and Gravity runs both side by side.

- **v1** (`Manifest`): the agent names the **tools** it calls, such as `gmail.send`. A manifest without
  `contract` is v1.
- **v2** (`ManifestV2`): the agent names **capabilities**, such as `message.list` or `issue.create`. What it reads
  goes under `sources` and what it changes under `writes`, and the person picks the app (Gmail or Outlook, Linear
  or Jira) when they set it up. That setup is an `Instance`.

## Load and validate a manifest

```python
from gravity_schema import load_manifest_text

manifest = load_manifest_text("""
contract: v2
name: inbox-digest
version: 1.0.0
description: "A morning digest of my inbox"
runtime: {framework: langgraph, python: "3.12", entrypoint: src/agent.py:graph}
dependencies: {lockfile: requirements.lock}
sources:
  inbox: {capability: message.list, label: "Which inbox?", window: 1d}
writes:
  digest: {capability: message.send, label: "Where should the digest go?"}
approvals: {required_for: [message.send]}
""")
manifest.contract               # 'v2'
manifest.capabilities           # frozenset({'message.list', 'message.send'})
```

`load_manifest_file(path)` reads a file instead. Both return whichever contract the manifest declares, and raise
`ManifestValidationError` with its `ManifestIssue`s (each a code, location, message and remediation) when it
doesn't fit. Unknown fields are rejected, so a typo is reported rather than ignored.

## The capability vocabulary (v2)

`VOCABULARY` holds every capability and which apps serve it.

```python
from gravity_schema import VOCABULARY

VOCABULARY.apps_for("message.list")     # ('gmail', 'instagram', 'microsoft_teams', 'outlook', ...)
```

## A consumer's setup and a run's grant (v2)

```python
from datetime import UTC, datetime
from gravity_schema import Instance, check_instance, grant, run_token_body

setup = Instance.model_validate({
    "agent": "inbox-digest", "version": "1.0.0",
    "sources": {"inbox": {"app": "gmail"}},
    "writes": {"digest": {"app": "gmail"}},
})
check_instance(manifest, setup)          # []: the setup fits (otherwise, what doesn't)
grant(manifest, setup).as_dict()         # exactly what one run may call, and what waits for approval
run_token_body(manifest, setup, now=datetime.now(UTC))   # {'bindings', 'grant', 'approvals'} for a run token
```

## Explain an agent to its users (v2)

These write plain text from the manifest and the setup, with no model involved.

```python
from gravity_schema import capabilities_summary, permissions

capabilities_summary(manifest)
# {'can': ['Read your messages', 'Send a message'], 'cant': [...], 'also': [...]}
permissions(manifest, setup)
# per app: what it reads, what it changes, what asks first, and what it never does
```

`setup_plan` lists what a consumer has to pick, and `live` describes a running setup.

## JSON Schema

```python
from gravity_schema import manifest_json_schema

schema = manifest_json_schema()          # one schema covering v1 and v2
```

Or from the command line, `python -m gravity_schema --out manifest.schema.json`. Add `--check` to exit 1 when
that file is out of date.

## Versions

gravity-schema and gravity-cli are released together, always in the same version. The changes are in the CLI's
changelog (`gravity changelog`).
