Tool
@kindgi/specs/tool.schema.json, schema version 1.3.0.
A tool definition. Authored once; the runtime picks transport (native in-process for tools built into the runtime, MCP over the wire for cross-process / cross-org / third-party tools). Every tool declares its typed I/O, its context needs (typed DI), and its side-effects — enabling policy enforcement and parallel scheduling by the kernel.
id(string, required): Unique tool identifier. Convention: '<pack>.<tool>' (e.g. 'acme.verify-citation') or a bare id for tools built into Kindgi.description(string, required): Human- and LLM-readable description of what this tool does. Load-bearing: this is what the LLM sees when deciding to call the tool.version(string, required)input(object, required): JSON Schema for the tool input. MUST validate under Draft 2020-12, except on an MCP server's tool (transport: "mcp"), whose schemas are in the dialect their$schemadeclares: draft-06, draft-07, 2019-09 or 2020-12.output(object, required): JSON Schema for the tool output. MUST validate under Draft 2020-12, except on an MCP server's tool (transport: "mcp"), whose schemas are in the dialect their$schemadeclares: draft-06, draft-07, 2019-09 or 2020-12.needs(array of Need): Typed context requirements — named slots (e.g.tenant,run,blob,memory:facts) the runtime injects viaToolContext. Declarative: not checked when a flow is loaded.needsSpecis the typed, discriminated form.effects(array of Effect): Declared side-effects. Enables policy enforcement (can this tool run in this tenant?), safe parallelization (are two calls conflicting?), and causal provenance.transport("auto"|"native"|"mcp"): Transport hint. 'auto' (default) lets the runtime pick native when possible, MCP otherwise. 'native' requires in-process execution. 'mcp' requires MCP execution. Deployment-time concern; authoring is unchanged.mcpEndpoint(string): If transport = 'mcp' (or resolved to MCP by 'auto'), the MCP endpoint URI. Format: 'mcp+stdio://<command>', 'mcp+http://<url>', 'mcp+sse://<url>'.metadata(map of any): Free-form annotations (author, docs URL, tags). Not interpreted by the kernel.sandbox("none"|"context-isolated"|"strict"): Isolation posture the runtime enforces around the handler. Optional additive field.mutating(boolean): Semantic marker:truewhen this tool causes observable side effects (writes state, calls external APIs with mutations, sends messages). Read-only tools setfalse. Absent defaults totrue. Consumed by the HITL default classifier — a read-only tool passes straight through, a mutating tool asks on first use. It also decides what runs together: calls to read-only tools that a model step asks for one after another run at the same time, up to 8 at once, unless the agent setsparallelToolCalls: false; a call to a mutating tool runs on its own, and so does a call to a read-only tool that pauses or declares connections, since it may wait.needsApprovalWhenUnattended(boolean):truewhen a person must say yes to every call of this tool in a run no person started (a schedule, a webhook, an event, a mail or a service account's key started it). In such a run an agent's call waits for a person's yes whatever the agent's approval rules say, and a flow's tool step that calls it is refused. A webhook trigger, a schedule or a mail trigger whosetoolsAllowedUnattendednames the tool (a project admin's to set) lifts that, in its own runs only. A tool that uses a person's connection, reads included, counts as declaring it, whatever this ormutatingsays. In a run a mail started, so does a tool that isn'tmutating: false, and one that uses the run's own mailbox. Absent meansfalse. Optional additive field.pauses(boolean):truewhen the tool may make its run wait for another system's answer: each call gets a wait token, hands its link to that system, and answerspause; the system's answer, valid againstoutput, becomes the call's result. The run waits at most 24 days (24 hours by default) and fails the call when the time passes. Only a pack tool with a handler can pause: not one with a declarativespec, nor an MCP tool. Absent meansfalse. Optional additive field.resultIsOutsideData(boolean):truewhen the tool's results are text from outside that nobody checked, such as a mail someone sent or a page a search found: an agent reads each result as data, not instructions, in this turn and in every later turn's history. It changes what the model is told, not what the tool may do. Absent meansfalse. Optional additive field.limits(object): Sandbox-enforced resource caps at dispatch. Optional additive field.memMB(integer, required)cpuMs(integer, required)
network(one of the objects below): Network egress policy. Optional additive field. Discriminated onkind.- an object
kind("none"|"unrestricted", required)
- an object
kind("allowlist", required)hosts(array of string, required)
- an object
needsSpec(object): Typed discriminated needs (env / secrets / config / capabilities / bindings / connections). Optional additive field.env(map of object)secrets(map of object)config(map of object)capabilities(array of string)bindings(array of string)connections(map of ConnectionNeed): Accounts at other apps the tool acts with, by the tool's own name for each (mail). The runtime resolves them per call into the context'sconnections.
codeArtifactRef(one of the objects below): Handler-artifact pointer. Discriminated onkind:ociis the deploy-pipeline shape (image + module path + artifactVersion);filesystemis the local-development shape — absolute host path at the pack's on-disk handler file. Production servers SHOULD rejectfilesystem.- an object
kind("oci", required)imageRef(string, required)modulePath(string, required)artifactVersion(string, required)
- an object
kind("filesystem", required)modulePath(string, required)
- an object
spec(HttpToolSpec): Declarative handler spec. Discriminated onkind; the framework's synthesizer registry maps kind → runtime handler. Mutually exclusive with an imperative handler at author time.
Definitions
Section titled “Definitions”name(string, required): The named context slot (e.g. 'tenant', 'db', 'run', 'provenance', 'memory:facts', 'blob').optional(boolean)
Effect
Section titled “Effect”kind("reads"|"writes"|"deletes"|"network"|"spawns-run"|"emits-event"|"external-side-effect"|"sensitive-data-egress", required)resource(string): Resource identifier (e.g. 'memory:facts', 'blob:*', 'external:api.example.com'). Used by the policy engine to authorize the effect.notes(string)
ToolSecretRef
Section titled “ToolSecretRef”envName(string, required)name(string, required)
HttpHeaderSpec
Section titled “HttpHeaderSpec”name(string, required)value(string, required)
ConnectionNeed
Section titled “ConnectionNeed”app(string, required): The app's entry id:google,github.permissions(array of string, required): The entry's permission keys the call needs:gmail.send.as("person"|"company", required): Whose connection:person, the run's person (the one it acts for, who started it or owns its trigger);company, the tenant's.
HttpAuthSpec
Section titled “HttpAuthSpec”One of:
- an object
kind("bearer", required)secretRef(ToolSecretRef, required)
- an object
kind("header", required)headerName(string, required)secretRef(ToolSecretRef, required)
- an object: A connection the tool declares in
needsSpec.connections, by its name there: sent asAuthorization: Bearer <access token>.kind("connection", required)connection(string, required)
HttpRequestBodySpec
Section titled “HttpRequestBodySpec”One of:
- an object
kind("json-input", required)
- an object
kind("input-passthrough", required)
- an object
kind("text", required)template(string, required)
HttpToolSpec
Section titled “HttpToolSpec”Declarative HTTP-invocation spec. Attached to ToolManifest.spec under the discriminant kind: 'http'. The runtime Tool.handler is synthesized by the 'http' spec synthesizer to perform URL-template substitution, secret-ref resolution via ToolContext.resolveSecret, and the outbound fetch. All fields serialize cleanly to JSON.
kind("http", required)method("GET"|"POST"|"PUT"|"PATCH"|"DELETE", required)urlTemplate(string, required): URL template with{param}placeholders substituted from the tool's input at invoke time.headers(array of HttpHeaderSpec)authorization(HttpAuthSpec)requestBody(HttpRequestBodySpec)timeoutMs(integer): Wall-clock timeout in ms. Default 30000.parseJson(boolean): When true (default), the response body is parsed as JSON before returning to the invoker.successStatus(object)min(integer, required)max(integer, required)