nutria-plugin 0.2.2__tar.gz → 0.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/CHANGELOG.md +12 -0
- nutria_plugin-0.2.3/PKG-INFO +135 -0
- nutria_plugin-0.2.3/README.md +116 -0
- nutria_plugin-0.2.3/docs/index.md +21 -0
- nutria_plugin-0.2.3/docs/manifest.md +84 -0
- nutria_plugin-0.2.3/docs/python-api.md +78 -0
- nutria_plugin-0.2.3/docs/quickstart.md +66 -0
- nutria_plugin-0.2.3/docs/reviewable-actions.md +90 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/pyproject.toml +1 -1
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/__init__.py +2 -4
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/capabilities.py +24 -29
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/manifest.py +26 -23
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/packaging.py +34 -2
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_bundle.py +33 -1
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_capability_contracts.py +38 -20
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_manifest.py +49 -8
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_reviewable_actions.py +66 -4
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_signing.py +1 -1
- nutria_plugin-0.2.2/PKG-INFO +0 -275
- nutria_plugin-0.2.2/README.md +0 -256
- nutria_plugin-0.2.2/docs/index.md +0 -60
- nutria_plugin-0.2.2/docs/manifest.md +0 -448
- nutria_plugin-0.2.2/docs/python-api.md +0 -435
- nutria_plugin-0.2.2/docs/quickstart.md +0 -224
- nutria_plugin-0.2.2/docs/reviewable-actions.md +0 -150
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/.github/workflows/publish.yml +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/.gitignore +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/admin-extensions.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/admin-flows.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/cli.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/connection-types.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/security.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/skill-format.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/README.md +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/hooks/hooks.json +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/plugin.json +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/settings.schema.json +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/bundle.py +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/cli.py +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/signing.py +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_cli.py +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_packaging.py +0 -0
- {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/uv.lock +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.2.3
|
|
4
|
+
|
|
5
|
+
- Make manifest schema 2.2 the only accepted plugin contract.
|
|
6
|
+
- Require every manifest to declare typed capabilities and world providers.
|
|
7
|
+
- Require explicit capability authority, audience, task-context, and exposure.
|
|
8
|
+
- Replace model-callability and compatibility metadata with strict exposure and
|
|
9
|
+
safe non-callability reasons.
|
|
10
|
+
- Require task context for task-owned resources and matching providers for all
|
|
11
|
+
connection-backed capabilities.
|
|
12
|
+
- Tighten reviewable external writes, immutable envelope mappings,
|
|
13
|
+
idempotency, and completion receipt validation.
|
|
14
|
+
|
|
3
15
|
## 0.2.2
|
|
4
16
|
|
|
5
17
|
- Add backward-compatible schema-2.1 capability exposure and safe non-callability metadata.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: nutria-plugin
|
|
3
|
+
Version: 0.2.3
|
|
4
|
+
Summary: SDK for building, validating, signing, and packaging Nutria plugins
|
|
5
|
+
Project-URL: Homepage, https://github.com/AlRos14/nutria-plugin-sdk
|
|
6
|
+
Project-URL: Repository, https://github.com/AlRos14/nutria-plugin-sdk
|
|
7
|
+
Project-URL: Changelog, https://github.com/AlRos14/nutria-plugin-sdk/blob/main/CHANGELOG.md
|
|
8
|
+
Author-email: Nutria <dev@nutria.ai>
|
|
9
|
+
License: MIT
|
|
10
|
+
Requires-Python: >=3.11
|
|
11
|
+
Requires-Dist: cryptography>=41.0
|
|
12
|
+
Requires-Dist: lxml>=4.9
|
|
13
|
+
Requires-Dist: pydantic>=2.0
|
|
14
|
+
Provides-Extra: dev
|
|
15
|
+
Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
|
|
16
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
17
|
+
Requires-Dist: ruff>=0.8; extra == 'dev'
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
|
|
20
|
+
# nutria-plugin SDK
|
|
21
|
+
|
|
22
|
+
SDK for building, validating, signing, and packaging Nutria plugins.
|
|
23
|
+
|
|
24
|
+
Release `0.2.3` is intentionally breaking. It accepts only manifest schema
|
|
25
|
+
`2.2`, requires typed capabilities and world providers, and makes authority,
|
|
26
|
+
audience, task-context requirements, and exposure explicit. There is no runtime
|
|
27
|
+
migration for schema 2.0/2.1 manifests and no compatibility/model-callability
|
|
28
|
+
field.
|
|
29
|
+
|
|
30
|
+
ChatBotNutralia owns task context, reviewable drafts, revisions, approval,
|
|
31
|
+
idempotency, and completion receipts. Plugins own authoritative provider reads
|
|
32
|
+
and exact delivery of an approved snapshot.
|
|
33
|
+
|
|
34
|
+
## Install
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
uv add nutria-plugin==0.2.3
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Scaffold and validate
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
nutria-plugin new my-workspace-plugin --name "My Workspace Plugin"
|
|
44
|
+
nutria-plugin validate my-workspace-plugin
|
|
45
|
+
nutria-plugin pack my-workspace-plugin --output my-workspace-plugin-0.1.0.zip
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The generated directory contains `plugin.json`, component directories for
|
|
49
|
+
connections, skills, context documents, specs and hooks, plus an optional
|
|
50
|
+
settings schema and assets.
|
|
51
|
+
|
|
52
|
+
## Minimal schema 2.2 manifest
|
|
53
|
+
|
|
54
|
+
```json
|
|
55
|
+
{
|
|
56
|
+
"schema_version": "2.2",
|
|
57
|
+
"id": "my-workspace-plugin",
|
|
58
|
+
"name": "My Workspace Plugin",
|
|
59
|
+
"version": "0.1.0",
|
|
60
|
+
"description": "Connects Nutria to an authoritative workspace.",
|
|
61
|
+
"author": "Your Name",
|
|
62
|
+
"runtime_types": ["declarative_api"],
|
|
63
|
+
"required_secrets": ["API_KEY"],
|
|
64
|
+
"remote_endpoints": ["https://api.myworkspace.com"],
|
|
65
|
+
"capabilities": [{
|
|
66
|
+
"id": "workspace.search",
|
|
67
|
+
"title": "Search workspace",
|
|
68
|
+
"description": "Read matching workspace resources.",
|
|
69
|
+
"effect": "read",
|
|
70
|
+
"tool": "search_workspace",
|
|
71
|
+
"connection_id": "workspace",
|
|
72
|
+
"requirements": {
|
|
73
|
+
"authority": "read",
|
|
74
|
+
"audience": ["team_internal"],
|
|
75
|
+
"task_context": "optional"
|
|
76
|
+
},
|
|
77
|
+
"exposure": "model"
|
|
78
|
+
}],
|
|
79
|
+
"world_providers": [{
|
|
80
|
+
"id": "workspace",
|
|
81
|
+
"title": "Workspace",
|
|
82
|
+
"description": "Authoritative workspace resources.",
|
|
83
|
+
"connection_id": "workspace",
|
|
84
|
+
"resource_types": [{
|
|
85
|
+
"id": "workspace.item",
|
|
86
|
+
"title": "Workspace item",
|
|
87
|
+
"description": "One stable workspace item.",
|
|
88
|
+
"identity_fields": ["id"],
|
|
89
|
+
"search_capability": "workspace.search"
|
|
90
|
+
}]
|
|
91
|
+
}]
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
Every capability must declare `requirements` and `exposure`. Host/admin-only
|
|
96
|
+
capabilities also require a safe `non_callable_reason`. Task-owned resources
|
|
97
|
+
(`task`, `artifact`, `prepared_action`) require `task_context: "required"`.
|
|
98
|
+
Every connection referenced by a capability must be represented by a matching
|
|
99
|
+
world provider.
|
|
100
|
+
|
|
101
|
+
For customer messages, use a host-owned `reviewable_actions` contract. Do not
|
|
102
|
+
create plugin draft tables or native saved-draft tools. See
|
|
103
|
+
[`docs/reviewable-actions.md`](docs/reviewable-actions.md).
|
|
104
|
+
|
|
105
|
+
## Python API
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from pathlib import Path
|
|
109
|
+
from nutria_plugin import PluginManifest, pack_plugin, validate_plugin_dir
|
|
110
|
+
|
|
111
|
+
manifest = PluginManifest.from_file(Path("plugin.json"))
|
|
112
|
+
errors = validate_plugin_dir(Path("."))
|
|
113
|
+
archive = pack_plugin(Path("."), Path("dist/plugin.zip"))
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The package exports the strict manifest, capability, provider, reviewable-action,
|
|
117
|
+
admin extension/flow, bundle, packaging, and signing models/functions documented
|
|
118
|
+
in [`docs/python-api.md`](docs/python-api.md).
|
|
119
|
+
|
|
120
|
+
## Bundle and security rules
|
|
121
|
+
|
|
122
|
+
- `plugin.json` is required at the ZIP root.
|
|
123
|
+
- Paths are relative; traversal, symlinks, hidden paths, and disallowed file
|
|
124
|
+
extensions are rejected.
|
|
125
|
+
- Maximum compressed bundle size is 20 MB and decompressed size is bounded.
|
|
126
|
+
- Secrets are configured after installation and never stored in the bundle.
|
|
127
|
+
- Remote endpoints are checked for unsafe local/private targets.
|
|
128
|
+
- Database-backed plugins bind user/model values as SQL parameters.
|
|
129
|
+
|
|
130
|
+
Supported runtime types are `remote_mcp`, `declarative_api`, `openapi_bridge`,
|
|
131
|
+
and `soap_bridge`.
|
|
132
|
+
|
|
133
|
+
## License
|
|
134
|
+
|
|
135
|
+
MIT
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# nutria-plugin SDK
|
|
2
|
+
|
|
3
|
+
SDK for building, validating, signing, and packaging Nutria plugins.
|
|
4
|
+
|
|
5
|
+
Release `0.2.3` is intentionally breaking. It accepts only manifest schema
|
|
6
|
+
`2.2`, requires typed capabilities and world providers, and makes authority,
|
|
7
|
+
audience, task-context requirements, and exposure explicit. There is no runtime
|
|
8
|
+
migration for schema 2.0/2.1 manifests and no compatibility/model-callability
|
|
9
|
+
field.
|
|
10
|
+
|
|
11
|
+
ChatBotNutralia owns task context, reviewable drafts, revisions, approval,
|
|
12
|
+
idempotency, and completion receipts. Plugins own authoritative provider reads
|
|
13
|
+
and exact delivery of an approved snapshot.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv add nutria-plugin==0.2.3
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Scaffold and validate
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
nutria-plugin new my-workspace-plugin --name "My Workspace Plugin"
|
|
25
|
+
nutria-plugin validate my-workspace-plugin
|
|
26
|
+
nutria-plugin pack my-workspace-plugin --output my-workspace-plugin-0.1.0.zip
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
The generated directory contains `plugin.json`, component directories for
|
|
30
|
+
connections, skills, context documents, specs and hooks, plus an optional
|
|
31
|
+
settings schema and assets.
|
|
32
|
+
|
|
33
|
+
## Minimal schema 2.2 manifest
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"schema_version": "2.2",
|
|
38
|
+
"id": "my-workspace-plugin",
|
|
39
|
+
"name": "My Workspace Plugin",
|
|
40
|
+
"version": "0.1.0",
|
|
41
|
+
"description": "Connects Nutria to an authoritative workspace.",
|
|
42
|
+
"author": "Your Name",
|
|
43
|
+
"runtime_types": ["declarative_api"],
|
|
44
|
+
"required_secrets": ["API_KEY"],
|
|
45
|
+
"remote_endpoints": ["https://api.myworkspace.com"],
|
|
46
|
+
"capabilities": [{
|
|
47
|
+
"id": "workspace.search",
|
|
48
|
+
"title": "Search workspace",
|
|
49
|
+
"description": "Read matching workspace resources.",
|
|
50
|
+
"effect": "read",
|
|
51
|
+
"tool": "search_workspace",
|
|
52
|
+
"connection_id": "workspace",
|
|
53
|
+
"requirements": {
|
|
54
|
+
"authority": "read",
|
|
55
|
+
"audience": ["team_internal"],
|
|
56
|
+
"task_context": "optional"
|
|
57
|
+
},
|
|
58
|
+
"exposure": "model"
|
|
59
|
+
}],
|
|
60
|
+
"world_providers": [{
|
|
61
|
+
"id": "workspace",
|
|
62
|
+
"title": "Workspace",
|
|
63
|
+
"description": "Authoritative workspace resources.",
|
|
64
|
+
"connection_id": "workspace",
|
|
65
|
+
"resource_types": [{
|
|
66
|
+
"id": "workspace.item",
|
|
67
|
+
"title": "Workspace item",
|
|
68
|
+
"description": "One stable workspace item.",
|
|
69
|
+
"identity_fields": ["id"],
|
|
70
|
+
"search_capability": "workspace.search"
|
|
71
|
+
}]
|
|
72
|
+
}]
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Every capability must declare `requirements` and `exposure`. Host/admin-only
|
|
77
|
+
capabilities also require a safe `non_callable_reason`. Task-owned resources
|
|
78
|
+
(`task`, `artifact`, `prepared_action`) require `task_context: "required"`.
|
|
79
|
+
Every connection referenced by a capability must be represented by a matching
|
|
80
|
+
world provider.
|
|
81
|
+
|
|
82
|
+
For customer messages, use a host-owned `reviewable_actions` contract. Do not
|
|
83
|
+
create plugin draft tables or native saved-draft tools. See
|
|
84
|
+
[`docs/reviewable-actions.md`](docs/reviewable-actions.md).
|
|
85
|
+
|
|
86
|
+
## Python API
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
from pathlib import Path
|
|
90
|
+
from nutria_plugin import PluginManifest, pack_plugin, validate_plugin_dir
|
|
91
|
+
|
|
92
|
+
manifest = PluginManifest.from_file(Path("plugin.json"))
|
|
93
|
+
errors = validate_plugin_dir(Path("."))
|
|
94
|
+
archive = pack_plugin(Path("."), Path("dist/plugin.zip"))
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
The package exports the strict manifest, capability, provider, reviewable-action,
|
|
98
|
+
admin extension/flow, bundle, packaging, and signing models/functions documented
|
|
99
|
+
in [`docs/python-api.md`](docs/python-api.md).
|
|
100
|
+
|
|
101
|
+
## Bundle and security rules
|
|
102
|
+
|
|
103
|
+
- `plugin.json` is required at the ZIP root.
|
|
104
|
+
- Paths are relative; traversal, symlinks, hidden paths, and disallowed file
|
|
105
|
+
extensions are rejected.
|
|
106
|
+
- Maximum compressed bundle size is 20 MB and decompressed size is bounded.
|
|
107
|
+
- Secrets are configured after installation and never stored in the bundle.
|
|
108
|
+
- Remote endpoints are checked for unsafe local/private targets.
|
|
109
|
+
- Database-backed plugins bind user/model values as SQL parameters.
|
|
110
|
+
|
|
111
|
+
Supported runtime types are `remote_mcp`, `declarative_api`, `openapi_bridge`,
|
|
112
|
+
and `soap_bridge`.
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# nutria-plugin SDK documentation
|
|
2
|
+
|
|
3
|
+
Developer reference for SDK `0.2.3` and manifest schema `2.2`.
|
|
4
|
+
|
|
5
|
+
| Document | Purpose |
|
|
6
|
+
|---|---|
|
|
7
|
+
| [quickstart.md](quickstart.md) | Build a strict schema 2.2 plugin |
|
|
8
|
+
| [manifest.md](manifest.md) | Manifest, capability, and provider contracts |
|
|
9
|
+
| [reviewable-actions.md](reviewable-actions.md) | Host-owned drafts and external delivery |
|
|
10
|
+
| [python-api.md](python-api.md) | Public Python API |
|
|
11
|
+
| [connection-types.md](connection-types.md) | Supported runtime/connection types |
|
|
12
|
+
| [skill-format.md](skill-format.md) | Skill frontmatter and authoring |
|
|
13
|
+
| [admin-extensions.md](admin-extensions.md) | Host-rendered admin views |
|
|
14
|
+
| [admin-flows.md](admin-flows.md) | Host-rendered operator flows |
|
|
15
|
+
| [security.md](security.md) | Signing, ZIP safety, endpoints, and secrets |
|
|
16
|
+
| [cli.md](cli.md) | CLI commands |
|
|
17
|
+
|
|
18
|
+
A plugin bundle can contain connections, skills, context documents, hooks,
|
|
19
|
+
settings, specs, and declarative admin assets. Its schema 2.2 manifest must also
|
|
20
|
+
declare at least one typed capability and world provider. Older schemas are not
|
|
21
|
+
loaded or migrated.
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# plugin.json manifest reference
|
|
2
|
+
|
|
3
|
+
`plugin.json` is the single source of truth for plugin identity, runtime,
|
|
4
|
+
capability authority, and provider topology. SDK 0.2.3 accepts exactly schema
|
|
5
|
+
`2.2`; older schemas and unknown fields fail validation.
|
|
6
|
+
|
|
7
|
+
## Required top-level fields
|
|
8
|
+
|
|
9
|
+
| Field | Contract |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `schema_version` | Literal `"2.2"` |
|
|
12
|
+
| `id` | Lowercase plugin slug |
|
|
13
|
+
| `name`, `description`, `author` | Non-empty display metadata |
|
|
14
|
+
| `version` | Semantic version |
|
|
15
|
+
| `runtime_types` | One or more supported runtime types |
|
|
16
|
+
| `capabilities` | At least one typed capability |
|
|
17
|
+
| `world_providers` | At least one typed provider |
|
|
18
|
+
|
|
19
|
+
Optional fields include `default_scope`, `paths`, `required_secrets`,
|
|
20
|
+
`optional_secrets`, `remote_endpoints`, `tags`, `reviewable_actions`,
|
|
21
|
+
`admin_extensions`, `admin_flows`, `mcp_server_entry`, `homepage`, `license`,
|
|
22
|
+
and `signature`. A `compatibility` field is not part of schema 2.2.
|
|
23
|
+
|
|
24
|
+
## Capability descriptor
|
|
25
|
+
|
|
26
|
+
Each capability declares:
|
|
27
|
+
|
|
28
|
+
- stable `id`, `title`, and `description`;
|
|
29
|
+
- `effect`: `read`, `prepare`, `write`, or `external_write`;
|
|
30
|
+
- concrete `tool` and optional `connection_id`;
|
|
31
|
+
- typed `inputs`, `consumes`, and `produces` bindings;
|
|
32
|
+
- required `requirements.authority`, `requirements.audience`, and
|
|
33
|
+
`requirements.task_context`;
|
|
34
|
+
- required `exposure`: `model`, `host`, or `admin`.
|
|
35
|
+
|
|
36
|
+
`host` and `admin` exposure require `non_callable_reason` with a stable code and
|
|
37
|
+
safe summary. `model` exposure must not declare it. Task-owned resource bindings
|
|
38
|
+
require `task_context: "required"`.
|
|
39
|
+
|
|
40
|
+
A model-exposed `external_write` must declare `prepared_action`, `idempotency`,
|
|
41
|
+
and `completion`. Reviewable delivery capabilities are instead host-only and
|
|
42
|
+
are linked through `reviewable_action_id`.
|
|
43
|
+
|
|
44
|
+
## World provider descriptor
|
|
45
|
+
|
|
46
|
+
Every provider declares a stable ID, title, description, optional connection
|
|
47
|
+
and health capability, and one or more resource types. Each resource type has:
|
|
48
|
+
|
|
49
|
+
- a stable built-in or plugin-namespaced `id`;
|
|
50
|
+
- one or more `identity_fields`;
|
|
51
|
+
- optional search/inspect capability references;
|
|
52
|
+
- optional version field, TTL, and named safe/authorized projections.
|
|
53
|
+
|
|
54
|
+
Capability connections must have a matching provider connection. Referenced
|
|
55
|
+
search, inspect, health, prepare, and execute capabilities must exist in the
|
|
56
|
+
same manifest.
|
|
57
|
+
|
|
58
|
+
## Reviewable actions
|
|
59
|
+
|
|
60
|
+
The host owns the encrypted draft and approval lifecycle. A reviewable action
|
|
61
|
+
maps stable semantic fields to one host-only external-write capability. Every
|
|
62
|
+
delivery maps `recipient`, `body`, and `idempotency_key`; required capability
|
|
63
|
+
inputs must be mapped. Preparation capabilities use `effect: "prepare"` and
|
|
64
|
+
must be pure/read-only. See [reviewable-actions.md](reviewable-actions.md).
|
|
65
|
+
|
|
66
|
+
## Paths and settings
|
|
67
|
+
|
|
68
|
+
All component paths are relative and cannot contain empty, `.` or `..`
|
|
69
|
+
segments. `settings.schema.json` may use the host extensions
|
|
70
|
+
`x-nutria-store-scoped` and `x-nutria-store-default-key` for values that truly
|
|
71
|
+
vary by store.
|
|
72
|
+
|
|
73
|
+
## Secrets and endpoints
|
|
74
|
+
|
|
75
|
+
Secret arrays contain names only. Remote endpoints must be absolute HTTP(S)
|
|
76
|
+
URLs and cannot target localhost, loopback, link-local, private, or reserved IP
|
|
77
|
+
ranges.
|
|
78
|
+
|
|
79
|
+
## Validation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
uv run nutria-plugin validate .
|
|
83
|
+
uv run nutria-plugin pack . --output dist/plugin.zip
|
|
84
|
+
```
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Python API reference
|
|
2
|
+
|
|
3
|
+
SDK 0.2.3 exposes the strict schema 2.2 API.
|
|
4
|
+
|
|
5
|
+
```python
|
|
6
|
+
from nutria_plugin import (
|
|
7
|
+
__version__,
|
|
8
|
+
PluginManifest, PluginPaths, PluginScope, PluginRuntimeType,
|
|
9
|
+
CapabilityDescriptor, CapabilityEffect, CapabilityExposure,
|
|
10
|
+
CapabilityRequirement, CapabilityInputBinding, CapabilityOutputBinding,
|
|
11
|
+
ResourceBinding, ResourceType, ResourceTypeDescriptor,
|
|
12
|
+
WorldProjectionDescriptor, WorldProviderDescriptor,
|
|
13
|
+
PreparedActionDescriptor, IdempotencyDescriptor, CompletionDescriptor,
|
|
14
|
+
NonCallableReason,
|
|
15
|
+
ReviewableActionContract, ReviewableActionField, ReviewableActionMode,
|
|
16
|
+
PreparationToolContract,
|
|
17
|
+
PluginAdminExtension, PluginAdminExtensionKind,
|
|
18
|
+
PluginAdminExtensionPlacement,
|
|
19
|
+
PluginAdminFlow, PluginAdminFlowKind, PluginAdminFlowPlacement,
|
|
20
|
+
PluginBundleError, load_plugin_bundle, extract_plugin_bundle, validate_zip,
|
|
21
|
+
PackagingError, scaffold_plugin, pack_plugin, validate_plugin_dir,
|
|
22
|
+
SignatureStatus, generate_keypair, sign_manifest, verify_manifest,
|
|
23
|
+
)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`PluginCompatibility` and `model_callable` are not part of this API.
|
|
27
|
+
Callability is represented by `CapabilityExposure`; host/admin exposure also
|
|
28
|
+
requires `NonCallableReason`.
|
|
29
|
+
|
|
30
|
+
## Manifest
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from nutria_plugin import PluginManifest
|
|
35
|
+
|
|
36
|
+
manifest = PluginManifest.from_file(Path("plugin.json"))
|
|
37
|
+
same = PluginManifest.from_json_bytes(Path("plugin.json").read_bytes())
|
|
38
|
+
manifest.to_file(Path("plugin.json"))
|
|
39
|
+
payload = manifest.model_dump(mode="json", exclude_none=True)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Validation is strict: schema version must be `2.2`, top-level extras are
|
|
43
|
+
rejected, and capability/provider/action references are checked together.
|
|
44
|
+
|
|
45
|
+
## Bundles and packaging
|
|
46
|
+
|
|
47
|
+
```python
|
|
48
|
+
from pathlib import Path
|
|
49
|
+
from nutria_plugin import (
|
|
50
|
+
load_plugin_bundle, extract_plugin_bundle, validate_zip,
|
|
51
|
+
scaffold_plugin, validate_plugin_dir, pack_plugin,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
raw = Path("plugin.zip").read_bytes()
|
|
55
|
+
manifest = load_plugin_bundle(raw)
|
|
56
|
+
warnings = validate_zip(raw)
|
|
57
|
+
extract_plugin_bundle(raw, Path("installed/plugin"))
|
|
58
|
+
|
|
59
|
+
scaffold_plugin("my-plugin", "My Plugin", Path("."))
|
|
60
|
+
errors = validate_plugin_dir(Path("my-plugin"))
|
|
61
|
+
archive = pack_plugin(Path("my-plugin"), Path("dist/my-plugin.zip"))
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Unsafe bundles raise `PluginBundleError`; invalid source directories or pack
|
|
65
|
+
operations raise `PackagingError`.
|
|
66
|
+
|
|
67
|
+
## Signing
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from nutria_plugin import generate_keypair, sign_manifest, verify_manifest
|
|
71
|
+
|
|
72
|
+
private_pem, public_pem = generate_keypair()
|
|
73
|
+
payload = manifest.model_dump(mode="json", exclude_none=True)
|
|
74
|
+
payload["signature"] = sign_manifest(payload, private_pem)
|
|
75
|
+
status = verify_manifest(payload)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Signing uses ECDSA P-256 over canonical JSON with the `signature` field removed.
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Quickstart: a schema 2.2 plugin
|
|
2
|
+
|
|
3
|
+
## Install and scaffold
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
uv add nutria-plugin==0.2.3
|
|
7
|
+
nutria-plugin new inventory-lookup --name "Inventory Lookup"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Define plugin.json
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"schema_version": "2.2",
|
|
15
|
+
"id": "inventory-lookup",
|
|
16
|
+
"name": "Inventory Lookup",
|
|
17
|
+
"version": "0.1.0",
|
|
18
|
+
"description": "Reads authoritative warehouse stock.",
|
|
19
|
+
"author": "Acme Corp",
|
|
20
|
+
"runtime_types": ["declarative_api"],
|
|
21
|
+
"required_secrets": ["WAREHOUSE_API_KEY"],
|
|
22
|
+
"remote_endpoints": ["https://api.warehouse.example"],
|
|
23
|
+
"capabilities": [{
|
|
24
|
+
"id": "warehouse.stock.read",
|
|
25
|
+
"title": "Read stock",
|
|
26
|
+
"description": "Read current stock for one SKU.",
|
|
27
|
+
"effect": "read",
|
|
28
|
+
"tool": "get_stock",
|
|
29
|
+
"connection_id": "warehouse",
|
|
30
|
+
"requirements": {
|
|
31
|
+
"authority": "read",
|
|
32
|
+
"audience": ["team_internal", "public_customer"],
|
|
33
|
+
"task_context": "optional"
|
|
34
|
+
},
|
|
35
|
+
"exposure": "model"
|
|
36
|
+
}],
|
|
37
|
+
"world_providers": [{
|
|
38
|
+
"id": "warehouse",
|
|
39
|
+
"title": "Warehouse",
|
|
40
|
+
"description": "Authoritative warehouse inventory.",
|
|
41
|
+
"connection_id": "warehouse",
|
|
42
|
+
"resource_types": [{
|
|
43
|
+
"id": "warehouse.stock",
|
|
44
|
+
"title": "Stock item",
|
|
45
|
+
"description": "Current stock identity and state.",
|
|
46
|
+
"identity_fields": ["sku"],
|
|
47
|
+
"search_capability": "warehouse.stock.read"
|
|
48
|
+
}]
|
|
49
|
+
}]
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Add the matching declarative connection and skill files generated by the
|
|
54
|
+
scaffold. Assign the connection through the persona's `allowed_connections`;
|
|
55
|
+
the manifest does not own persona assignment.
|
|
56
|
+
|
|
57
|
+
## Validate and package
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
uv run nutria-plugin validate inventory-lookup
|
|
61
|
+
uv run nutria-plugin pack inventory-lookup \
|
|
62
|
+
--output inventory-lookup-0.1.0.zip
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Any schema 2.0/2.1 field, unknown property, missing provider, or incomplete
|
|
66
|
+
authority/exposure contract fails validation and must be corrected explicitly.
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# Reviewable actions and external writes
|
|
2
|
+
|
|
3
|
+
SDK 0.2.3 schema 2.2 defines one reviewable-action architecture:
|
|
4
|
+
|
|
5
|
+
```text
|
|
6
|
+
ChatBotNutralia -> task context, encrypted draft, revision, approval, idempotency, receipts
|
|
7
|
+
Plugin -> provider reads, pure preparation, exact approved delivery
|
|
8
|
+
SDK -> strict capability/provider/reviewable-action contracts
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Plugins do not save drafts and do not expose native saved-draft operations.
|
|
12
|
+
|
|
13
|
+
## Delivery capability
|
|
14
|
+
|
|
15
|
+
A reviewable delivery capability uses `effect: "external_write"`,
|
|
16
|
+
`exposure: "host"`, a `non_callable_reason`, explicit authority/audience/task
|
|
17
|
+
requirements, input bindings, and `reviewable_action_id`:
|
|
18
|
+
|
|
19
|
+
```json
|
|
20
|
+
{
|
|
21
|
+
"id": "whatsapp.send.text",
|
|
22
|
+
"title": "Send WhatsApp text",
|
|
23
|
+
"description": "Deliver the exact approved message.",
|
|
24
|
+
"effect": "external_write",
|
|
25
|
+
"tool": "send_whatsapp_text",
|
|
26
|
+
"connection_id": "whatsapp",
|
|
27
|
+
"requirements": {
|
|
28
|
+
"authority": "write_external",
|
|
29
|
+
"audience": ["team_internal", "private_internal"],
|
|
30
|
+
"task_context": "required"
|
|
31
|
+
},
|
|
32
|
+
"exposure": "host",
|
|
33
|
+
"non_callable_reason": {
|
|
34
|
+
"code": "host_approval_boundary",
|
|
35
|
+
"safe_summary": "Executed only by the host after exact-snapshot approval."
|
|
36
|
+
},
|
|
37
|
+
"reviewable_action_id": "whatsapp-text",
|
|
38
|
+
"inputs": [
|
|
39
|
+
{"semantic_field": "recipient", "argument_name": "recipient"},
|
|
40
|
+
{"semantic_field": "body", "argument_name": "body"},
|
|
41
|
+
{"semantic_field": "idempotency_key", "argument_name": "idempotency_key"}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The matching top-level action maps stable semantic fields to those exact tool
|
|
47
|
+
arguments:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"id": "whatsapp-text",
|
|
52
|
+
"kind": "customer_message",
|
|
53
|
+
"channel": "whatsapp",
|
|
54
|
+
"modes": ["new", "reply"],
|
|
55
|
+
"connection_id": "whatsapp",
|
|
56
|
+
"execute_capability": "whatsapp.send.text",
|
|
57
|
+
"argument_map": {
|
|
58
|
+
"recipient": "recipient",
|
|
59
|
+
"body": "body",
|
|
60
|
+
"idempotency_key": "idempotency_key"
|
|
61
|
+
},
|
|
62
|
+
"required_fields": ["recipient", "body"],
|
|
63
|
+
"editable_fields": ["body"]
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Every delivery maps `idempotency_key`. Required execution inputs must appear in
|
|
68
|
+
the action map. Recipient, source/thread/order identities, channel, and mode are
|
|
69
|
+
immutable; only explicitly editable fields can change.
|
|
70
|
+
|
|
71
|
+
## Pure preparation
|
|
72
|
+
|
|
73
|
+
An optional reply-envelope preparation capability uses `effect: "prepare"`.
|
|
74
|
+
It may resolve authoritative recipient/thread/source fingerprints but cannot
|
|
75
|
+
persist a draft or write externally. The action's `prepare_capability` and
|
|
76
|
+
`execute_capability` must be distinct and use the same connection.
|
|
77
|
+
|
|
78
|
+
## Host lifecycle
|
|
79
|
+
|
|
80
|
+
The host exposes generic prepare, inspect, revise, and send operations. A
|
|
81
|
+
revision creates a new action identity and approval. Delivery executes the
|
|
82
|
+
approved body and immutable envelope exactly once. Success requires the
|
|
83
|
+
declared authoritative completion receipt; unavailable providers keep the local
|
|
84
|
+
draft but cannot produce a successful effect.
|
|
85
|
+
|
|
86
|
+
Validate the whole cross-reference graph with:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv run nutria-plugin validate .
|
|
90
|
+
```
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Public API
|
|
4
4
|
----------
|
|
5
5
|
Models:
|
|
6
|
-
PluginManifest, PluginPaths,
|
|
6
|
+
PluginManifest, PluginPaths, PluginScope, PluginRuntimeType
|
|
7
7
|
|
|
8
8
|
Bundle operations:
|
|
9
9
|
load_plugin_bundle, extract_plugin_bundle, validate_zip
|
|
@@ -15,7 +15,7 @@ Signing:
|
|
|
15
15
|
generate_keypair, sign_manifest, verify_manifest, SignatureStatus
|
|
16
16
|
"""
|
|
17
17
|
|
|
18
|
-
__version__ = "0.2.
|
|
18
|
+
__version__ = "0.2.3"
|
|
19
19
|
|
|
20
20
|
from .capabilities import (
|
|
21
21
|
CapabilityDescriptor,
|
|
@@ -43,7 +43,6 @@ from .manifest import (
|
|
|
43
43
|
PluginAdminFlow,
|
|
44
44
|
PluginAdminFlowKind,
|
|
45
45
|
PluginAdminFlowPlacement,
|
|
46
|
-
PluginCompatibility,
|
|
47
46
|
PluginManifest,
|
|
48
47
|
PluginPaths,
|
|
49
48
|
PreparationToolContract,
|
|
@@ -62,7 +61,6 @@ __all__ = [
|
|
|
62
61
|
# Manifest
|
|
63
62
|
"PluginManifest",
|
|
64
63
|
"PluginPaths",
|
|
65
|
-
"PluginCompatibility",
|
|
66
64
|
"PluginScope",
|
|
67
65
|
"PluginRuntimeType",
|
|
68
66
|
"PluginAdminExtension",
|