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.
Files changed (43) hide show
  1. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/CHANGELOG.md +12 -0
  2. nutria_plugin-0.2.3/PKG-INFO +135 -0
  3. nutria_plugin-0.2.3/README.md +116 -0
  4. nutria_plugin-0.2.3/docs/index.md +21 -0
  5. nutria_plugin-0.2.3/docs/manifest.md +84 -0
  6. nutria_plugin-0.2.3/docs/python-api.md +78 -0
  7. nutria_plugin-0.2.3/docs/quickstart.md +66 -0
  8. nutria_plugin-0.2.3/docs/reviewable-actions.md +90 -0
  9. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/pyproject.toml +1 -1
  10. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/__init__.py +2 -4
  11. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/capabilities.py +24 -29
  12. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/manifest.py +26 -23
  13. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/packaging.py +34 -2
  14. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_bundle.py +33 -1
  15. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_capability_contracts.py +38 -20
  16. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_manifest.py +49 -8
  17. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_reviewable_actions.py +66 -4
  18. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_signing.py +1 -1
  19. nutria_plugin-0.2.2/PKG-INFO +0 -275
  20. nutria_plugin-0.2.2/README.md +0 -256
  21. nutria_plugin-0.2.2/docs/index.md +0 -60
  22. nutria_plugin-0.2.2/docs/manifest.md +0 -448
  23. nutria_plugin-0.2.2/docs/python-api.md +0 -435
  24. nutria_plugin-0.2.2/docs/quickstart.md +0 -224
  25. nutria_plugin-0.2.2/docs/reviewable-actions.md +0 -150
  26. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/.github/workflows/publish.yml +0 -0
  27. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/.gitignore +0 -0
  28. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/admin-extensions.md +0 -0
  29. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/admin-flows.md +0 -0
  30. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/cli.md +0 -0
  31. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/connection-types.md +0 -0
  32. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/security.md +0 -0
  33. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/docs/skill-format.md +0 -0
  34. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/README.md +0 -0
  35. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/hooks/hooks.json +0 -0
  36. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/plugin.json +0 -0
  37. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/examples/my-first-plugin/settings.schema.json +0 -0
  38. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/bundle.py +0 -0
  39. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/cli.py +0 -0
  40. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/src/nutria_plugin/signing.py +0 -0
  41. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_cli.py +0 -0
  42. {nutria_plugin-0.2.2 → nutria_plugin-0.2.3}/tests/test_packaging.py +0 -0
  43. {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
+ ```
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "nutria-plugin"
7
- version = "0.2.2"
7
+ version = "0.2.3"
8
8
  description = "SDK for building, validating, signing, and packaging Nutria plugins"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -3,7 +3,7 @@
3
3
  Public API
4
4
  ----------
5
5
  Models:
6
- PluginManifest, PluginPaths, PluginCompatibility, PluginScope, PluginRuntimeType
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.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",