From 1ecab24520df538b5584921e0afddf441bc81d48 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Thu, 12 Mar 2026 14:44:18 -0700 Subject: [PATCH 1/2] docs: add tool metadata documentation to webhook payload guides Updated both "Build Your Own" pages (contextual-access and logic-extensions) to document the new optional metadata field in webhook payloads (PR #517). Added comprehensive Tool Metadata section including structure table, examples for pre/post/access hooks, and use cases. Updated external GitHub URLs to canonical repositories (oapi-codegen and openapi-ts). Fixes #872. --- .../contextual-access/build-your-own/page.mdx | 103 +++++++++++++++++- .../logic-extensions/build-your-own/page.mdx | 103 +++++++++++++++++- 2 files changed, 196 insertions(+), 10 deletions(-) diff --git a/app/en/guides/contextual-access/build-your-own/page.mdx b/app/en/guides/contextual-access/build-your-own/page.mdx index ff7165836..bb30b3392 100644 --- a/app/en/guides/contextual-access/build-your-own/page.mdx +++ b/app/en/guides/contextual-access/build-your-own/page.mdx @@ -21,9 +21,9 @@ Use the OpenAPI spec with standard code generators to scaffold your server: | Language | Generator | | --- | --- | -| **Go** | [oapi-codegen](https://github.com/deepmap/oapi-codegen), [ogen](https://github.com/ogen-go/ogen) | +| **Go** | [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen), [ogen](https://github.com/ogen-go/ogen) | | **Python** | [openapi-generator](https://openapi-generator.tech/), [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator) | -| **TypeScript** | [openapi-typescript](https://github.com/drwpow/openapi-typescript), [openapi-generator](https://openapi-generator.tech/) | +| **TypeScript** | [openapi-typescript](https://github.com/openapi-ts/openapi-typescript), [openapi-generator](https://openapi-generator.tech/) | **Example (Go with oapi-codegen):** @@ -55,7 +55,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `execution_id` | string | Correlates request/response across hooks | -| `tool` | object | `name`, `toolkit`, `version` | +| `tool` | object | `name`, `toolkit`, `version`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | | `inputs` | object | Tool inputs (name → value) | | `context` | object | `authorization` (OAuth per provider), `secrets` (key names only), `metadata`, `user_id` | @@ -76,7 +76,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `execution_id` | string | Correlates with pre-execution hook | -| `tool` | object | `name`, `toolkit`, `version` | +| `tool` | object | `name`, `toolkit`, `version`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | | `inputs` | object | Tool inputs | | `success` | boolean | Whether the tool call succeeded | | `output` | any | The execution output (any JSON type) | @@ -101,7 +101,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `user_id` | string | User to check | -| `toolkits` | object | Map of toolkit name → toolkit info (tools, versions, requirements) | +| `toolkits` | object | Map of toolkit name → toolkit info. Each toolkit contains a `tools` map of tool name → version info arrays. Each version info includes `version`, `requirements`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | ### Response @@ -114,6 +114,99 @@ Return either an allow list or a deny list (not both): If you return neither field, the Arcade treats it as "no change" — all tools remain allowed at this hook. +## Tool Metadata + +Tools can include an optional `metadata` field with classification, behavioral, and custom information. Webhook servers can use this metadata to make more granular access and filtering decisions. + +All metadata fields are optional and omitted from the JSON when empty, so existing webhook servers continue to work without changes. + +For the full list of valid `service_domains` and `operations` values, see [Add Tool Metadata](/guides/create-tools/tool-basics/add-tool-metadata). + +### Structure + +| Field | Type | Description | +| --- | --- | --- | +| `metadata` | object \| absent | Container for tool metadata. Omitted when the tool has no metadata set. | +| `metadata.classification` | object | Classification information. | +| `metadata.classification.service_domains` | string[] | Service domains this tool interfaces with (for example, `"email"`, `"calendar"`, `"crm"`). | +| `metadata.behavior` | object | Behavioral characteristics. | +| `metadata.behavior.operations` | string[] | Operations this tool performs (for example, `"read"`, `"create"`, `"update"`, `"delete"`, `"opaque"`). | +| `metadata.behavior.read_only` | boolean | Whether the tool only reads data. | +| `metadata.behavior.destructive` | boolean | Whether the tool can delete or irreversibly modify data. | +| `metadata.behavior.idempotent` | boolean | Whether repeated calls with the same inputs produce the same result. | +| `metadata.behavior.open_world` | boolean | Whether the tool can affect state outside its defined outputs. | +| `metadata.extras` | object | Arbitrary additional metadata set by the toolkit author (for example, `{"IdP": "entra_id"}`). | + +### Example: pre/post hook request with metadata + +```json +{ + "execution_id": "exec_abc123", + "tool": { + "name": "ListEmails", + "toolkit": "Gmail", + "version": "1.0.0", + "metadata": { + "classification": { + "service_domains": ["email"] + }, + "behavior": { + "operations": ["read"], + "read_only": true, + "destructive": false, + "idempotent": true, + "open_world": false + }, + "extras": { + "IdP": "entra_id" + } + } + }, + "inputs": { "query": "from:boss@company.com" }, + "context": { "user_id": "user_123" } +} +``` + +### Example: access hook request with metadata + +```json +{ + "user_id": "user_123", + "toolkits": { + "Gmail": { + "tools": { + "ListEmails": [ + { + "version": "1.0.0", + "metadata": { + "classification": { + "service_domains": ["email"] + }, + "behavior": { + "operations": ["read"], + "read_only": true + } + }, + "requirements": { + "authorization": [{ "provider_type": "oauth2" }] + } + } + ] + } + } + } +} +``` + +### Use cases + +Webhook servers can use tool metadata to make more granular decisions: + +- **Block destructive operations** — Deny tools where `metadata.behavior.destructive` is `true` for certain users +- **Restrict by service domain** — Only allow tools in the `"email"` domain for a particular project +- **Audit read vs. write** — Log or rate-limit tools based on their `operations` array +- **Route by IdP** — Use `metadata.extras.IdP` to apply provider-specific policies + ## Response codes (pre and post) | Code | Meaning | diff --git a/app/en/guides/logic-extensions/build-your-own/page.mdx b/app/en/guides/logic-extensions/build-your-own/page.mdx index 08c8c2e94..5c5e26323 100644 --- a/app/en/guides/logic-extensions/build-your-own/page.mdx +++ b/app/en/guides/logic-extensions/build-your-own/page.mdx @@ -21,9 +21,9 @@ Use the OpenAPI spec with standard code generators to scaffold your server: | Language | Generator | | --- | --- | -| **Go** | [oapi-codegen](https://github.com/deepmap/oapi-codegen), [ogen](https://github.com/ogen-go/ogen) | +| **Go** | [oapi-codegen](https://github.com/oapi-codegen/oapi-codegen), [ogen](https://github.com/ogen-go/ogen) | | **Python** | [openapi-generator](https://openapi-generator.tech/), [datamodel-code-generator](https://github.com/koxudaxi/datamodel-code-generator) | -| **TypeScript** | [openapi-typescript](https://github.com/drwpow/openapi-typescript), [openapi-generator](https://openapi-generator.tech/) | +| **TypeScript** | [openapi-typescript](https://github.com/openapi-ts/openapi-typescript), [openapi-generator](https://openapi-generator.tech/) | **Example (Go with oapi-codegen):** @@ -55,7 +55,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `execution_id` | string | Correlates request/response across hooks | -| `tool` | object | `name`, `toolkit`, `version` | +| `tool` | object | `name`, `toolkit`, `version`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | | `inputs` | object | Tool inputs (name → value) | | `context` | object | `authorization` (OAuth per provider), `secrets` (key names only), `metadata`, `user_id` | @@ -76,7 +76,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `execution_id` | string | Correlates with pre-execution hook | -| `tool` | object | `name`, `toolkit`, `version` | +| `tool` | object | `name`, `toolkit`, `version`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | | `inputs` | object | Tool inputs | | `success` | boolean | Whether the tool call succeeded | | `output` | any | The execution output (any JSON type) | @@ -101,7 +101,7 @@ You do not need to implement all endpoints. Only implement the ones you configur | Field | Type | Description | | --- | --- | --- | | `user_id` | string | User to check | -| `toolkits` | object | Map of toolkit name → toolkit info (tools, versions, requirements) | +| `toolkits` | object | Map of toolkit name → toolkit info. Each toolkit contains a `tools` map of tool name → version info arrays. Each version info includes `version`, `requirements`, and optional `metadata` (see [Tool Metadata](#tool-metadata)) | ### Response @@ -114,6 +114,99 @@ Return either an allow list or a deny list (not both): If you return neither field, the Arcade treats it as "no change" — all tools remain allowed at this hook. +## Tool Metadata + +Tools can include an optional `metadata` field with classification, behavioral, and custom information. Webhook servers can use this metadata to make more granular access and filtering decisions. + +All metadata fields are optional and omitted from the JSON when empty, so existing webhook servers continue to work without changes. + +For the full list of valid `service_domains` and `operations` values, see [Add Tool Metadata](/guides/create-tools/tool-basics/add-tool-metadata). + +### Structure + +| Field | Type | Description | +| --- | --- | --- | +| `metadata` | object \| absent | Container for tool metadata. Omitted when the tool has no metadata set. | +| `metadata.classification` | object | Classification information. | +| `metadata.classification.service_domains` | string[] | Service domains this tool interfaces with (for example, `"email"`, `"calendar"`, `"crm"`). | +| `metadata.behavior` | object | Behavioral characteristics. | +| `metadata.behavior.operations` | string[] | Operations this tool performs (for example, `"read"`, `"create"`, `"update"`, `"delete"`, `"opaque"`). | +| `metadata.behavior.read_only` | boolean | Whether the tool only reads data. | +| `metadata.behavior.destructive` | boolean | Whether the tool can delete or irreversibly modify data. | +| `metadata.behavior.idempotent` | boolean | Whether repeated calls with the same inputs produce the same result. | +| `metadata.behavior.open_world` | boolean | Whether the tool can affect state outside its defined outputs. | +| `metadata.extras` | object | Arbitrary additional metadata set by the toolkit author (for example, `{"IdP": "entra_id"}`). | + +### Example: pre/post hook request with metadata + +```json +{ + "execution_id": "exec_abc123", + "tool": { + "name": "ListEmails", + "toolkit": "Gmail", + "version": "1.0.0", + "metadata": { + "classification": { + "service_domains": ["email"] + }, + "behavior": { + "operations": ["read"], + "read_only": true, + "destructive": false, + "idempotent": true, + "open_world": false + }, + "extras": { + "IdP": "entra_id" + } + } + }, + "inputs": { "query": "from:boss@company.com" }, + "context": { "user_id": "user_123" } +} +``` + +### Example: access hook request with metadata + +```json +{ + "user_id": "user_123", + "toolkits": { + "Gmail": { + "tools": { + "ListEmails": [ + { + "version": "1.0.0", + "metadata": { + "classification": { + "service_domains": ["email"] + }, + "behavior": { + "operations": ["read"], + "read_only": true + } + }, + "requirements": { + "authorization": [{ "provider_type": "oauth2" }] + } + } + ] + } + } + } +} +``` + +### Use cases + +Webhook servers can use tool metadata to make more granular decisions: + +- **Block destructive operations** — Deny tools where `metadata.behavior.destructive` is `true` for certain users +- **Restrict by service domain** — Only allow tools in the `"email"` domain for a particular project +- **Audit read vs. write** — Log or rate-limit tools based on their `operations` array +- **Route by IdP** — Use `metadata.extras.IdP` to apply provider-specific policies + ## Response codes (pre and post) | Code | Meaning | From 78576e26a873bfa797631ed0695c447eca5627e8 Mon Sep 17 00:00:00 2001 From: Evan Tahler Date: Thu, 12 Mar 2026 14:47:27 -0700 Subject: [PATCH 2/2] style: remove spaces around em dashes per Vale Google style Co-Authored-By: Claude Opus 4.6 --- .../guides/contextual-access/build-your-own/page.mdx | 10 +++++----- app/en/guides/logic-extensions/build-your-own/page.mdx | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/app/en/guides/contextual-access/build-your-own/page.mdx b/app/en/guides/contextual-access/build-your-own/page.mdx index bb30b3392..b9a88f989 100644 --- a/app/en/guides/contextual-access/build-your-own/page.mdx +++ b/app/en/guides/contextual-access/build-your-own/page.mdx @@ -112,7 +112,7 @@ Return either an allow list or a deny list (not both): | `only` | object | If present, **only** these tools are allowed (deny list ignored) | | `deny` | object | Tools listed here are denied (ignored if `only` is present) | -If you return neither field, the Arcade treats it as "no change" — all tools remain allowed at this hook. +If you return neither field, the Arcade treats it as "no change"—all tools remain allowed at this hook. ## Tool Metadata @@ -202,10 +202,10 @@ For the full list of valid `service_domains` and `operations` values, see [Add T Webhook servers can use tool metadata to make more granular decisions: -- **Block destructive operations** — Deny tools where `metadata.behavior.destructive` is `true` for certain users -- **Restrict by service domain** — Only allow tools in the `"email"` domain for a particular project -- **Audit read vs. write** — Log or rate-limit tools based on their `operations` array -- **Route by IdP** — Use `metadata.extras.IdP` to apply provider-specific policies +- **Block destructive operations**—Deny tools where `metadata.behavior.destructive` is `true` for certain users +- **Restrict by service domain**—Only allow tools in the `"email"` domain for a particular project +- **Audit read vs. write**—Log or rate-limit tools based on their `operations` array +- **Route by IdP**—Use `metadata.extras.IdP` to apply provider-specific policies ## Response codes (pre and post) diff --git a/app/en/guides/logic-extensions/build-your-own/page.mdx b/app/en/guides/logic-extensions/build-your-own/page.mdx index 5c5e26323..c906f8cfa 100644 --- a/app/en/guides/logic-extensions/build-your-own/page.mdx +++ b/app/en/guides/logic-extensions/build-your-own/page.mdx @@ -112,7 +112,7 @@ Return either an allow list or a deny list (not both): | `only` | object | If present, **only** these tools are allowed (deny list ignored) | | `deny` | object | Tools listed here are denied (ignored if `only` is present) | -If you return neither field, the Arcade treats it as "no change" — all tools remain allowed at this hook. +If you return neither field, the Arcade treats it as "no change"—all tools remain allowed at this hook. ## Tool Metadata @@ -202,10 +202,10 @@ For the full list of valid `service_domains` and `operations` values, see [Add T Webhook servers can use tool metadata to make more granular decisions: -- **Block destructive operations** — Deny tools where `metadata.behavior.destructive` is `true` for certain users -- **Restrict by service domain** — Only allow tools in the `"email"` domain for a particular project -- **Audit read vs. write** — Log or rate-limit tools based on their `operations` array -- **Route by IdP** — Use `metadata.extras.IdP` to apply provider-specific policies +- **Block destructive operations**—Deny tools where `metadata.behavior.destructive` is `true` for certain users +- **Restrict by service domain**—Only allow tools in the `"email"` domain for a particular project +- **Audit read vs. write**—Log or rate-limit tools based on their `operations` array +- **Route by IdP**—Use `metadata.extras.IdP` to apply provider-specific policies ## Response codes (pre and post)