Manage tools as code
Keep your Tool definitions in your repository. Review and version them with your code, then converge them at deploy time. This page applies the ensure protocol to saved Tools. For related guides, see Manage Agents as code and Manage Flows as code.
Define the tool
defineTool is a local constructor that does not make network requests. It validates the top-level definition shape and returns a canonical definition object. The definition includes the tool’s name, description, toolType, parametersSchema, and config fields.
Use the following code to define a weather lookup Tool:
Use one of these toolType values: external, custom, graphql, mcp, local, flow, or subagent. A Tool’s identity consists of its name and account scope. The account scope is organizational or personal. The API endpoint and credentials determine the environment.
If you rename a definition, ensure creates a Tool with that name and leaves the old Tool in
place. ensure never deletes or renames Tools. Treat the name as the stable identity.
flow and subagent Tools can reference saved Flows and Agents through config.flowId and
config.agentId. Raw flow_ and agent_ identifiers are tied to an account and environment. Use
references such as flow:Order Lookup and agent:Billing Specialist for portable definitions.
Converge at deploy time
Configure the SDK and converge the Tool definition with the following code:
The result includes result, toolId, and contentHash. The result value is unchanged, created, or updated.
ensure starts with a hash-only probe. In the managed steady state, the SDK sends one probe and writes no content changes. When the definition differs, the SDK sends the full definition and creates or updates the Tool unless the conflict rules reject the write.
The content hash covers toolType, description, parametersSchema, and config. The name identifies the Tool and does not contribute to the hash. When a response includes contentHash, the server computes it from the canonical, normalized definition. The SDK uses that server-computed hash in later probes.
Tools do not have version snapshots. ensure has no release: 'publish' option or versionId
result. It converges the live Tool definition directly.
Detect drift in CI
A dry run sends the full definition without writing changes and returns a plan. Run a dry run with the following code:
The plan includes result: 'plan', a changes value of none, create, or update, changedKeys, contentHash, and an optional remoteHash. The changedKeys array names changes such as toolType, description, parametersSchema, and changed keys within config.
To make a CI drift check fail when the plan is not none, pass expectNoChanges: true:
The SDK throws ToolDriftError when the plan reports create or update.
To bind an apply step to the state that the dry run inspected, pass its remoteHash as expectedRemoteHash:
If the remote state changes before the apply step, the API returns a 409 conflict with code: 'remote_changed'.
Conflicts with dashboard edits
The API records the source of each Tool write. When a dashboard or API edit changes a managed Tool away from its code definition, the next ensure returns status code 409 by default. The SDK exposes this response as a ToolEnsureConflictError with code: 'external_modification'. The dashboard shows a Managed in code badge and warns you before you save an edit.
Choose one of these resolutions:
- Repository wins: Pass
onConflict: 'overwrite'to overwrite the dashboard edit with the repository definition. - Dashboard wins: Call
pull, review the returned definition as a git diff, then commit or revert the change.
Pull the canonical definition with the following code:
What ensure does and does not manage
ensure converges the Tool definition, including its name, description, type, parameters schema, and config. It applies the same custom-tool code validation and secret-reference validation as Tool creation and updates. For example, use a {{secret:API_KEY}} reference when API_KEY is the secret name.
ensure does not manage which Agents or Flow steps reference the Tool. It never deletes or renames Tools.
Call the API directly
If you do not use the TypeScript SDK, authenticate each request with Authorization: Bearer YOUR_API_KEY. Replace YOUR_API_KEY with your Runtype API key. The ensure protocol has three steps:
- Send a hash-only request to
POST /v1/tools/ensurewithnameandcontentHash:{ "name": "Weather Lookup", "contentHash": "YOUR_SHA256_HASH" }. ReplaceYOUR_SHA256_HASHwith the lowercase hexadecimal SHA-256 hash for the definition. A matching hash returns status code200with{ "result": "unchanged" }. A nonmatching hash returns status code200with{ "result": "definitionRequired" }. - When the response is
{ "result": "definitionRequired" }, resend the request with the fulldefinitionand omitcontentHash. The server recomputes the canonical hash over the submitted definition and returnscontentHashon content-bearing responses. Use that value in later probes. - Handle conflicts as follows. The API returns status code
409forexternal_modificationorremote_changed. If the submittedcontentHashdoes not match the server’s recomputed hash for the definition, the API returns status code422withcontent_hash_mismatch. OmitcontentHashfrom full requests to avoid this validation error.
To pull a Tool definition directly, send GET /v1/tools/pull with the name query parameter. The API returns the canonical definition and contentHash, lastModifiedSource, and updatedAt fields.
Next steps
Continue with these guides:
- Manage Agents as code: converge Agent definitions from your repository
- Manage Flows as code: converge Flow definitions from your repository
- Creating external tools: configure saved HTTP tools in the dashboard