Skip to main content
Custom tools are a beta surface. Validate them in the sandbox before assigning them to production agents.
A custom tool is a TypeScript module that default-exports defineTool. Its name must match ^[a-z][a-z0-9_]*$ and an agent must list that exact name in allowedTools.
create_invoice.ts
execute returns a string or a ToolResult.

Execution context

There are no ambient platform credentials. Custom tools read external secrets through ctx.connections; tokens are resolved server-side from project Connections and injected only for the tool call.
The methods above are the legacy project-scoped contract. For multi-user or multi-resource applications, declare a logical Connection slot instead. The slot is not part of the model-facing parameters, and the runtime selects one Connection from immutable invocation identity and metadata.
site_update.ts
Strict slots fail closed when no Connection matches, more than one matches, the grant is missing, or required scopes are unavailable. They never fall back to an arbitrary project Connection. A capability is valid only during the current tool invocation.

Trusted invocation bindings

Use trusted bindings when a tool must receive application identity or authorization data that the model must not supply. Binding fields are separate from parameters, are not included in the model-facing tool schema, and are resolved immediately before execution.
site_context_get.ts
Supported binding roots are invocation.requestId, invocation.runId, invocation.sessionId, invocation.user, invocation.surface, and nested invocation.metadata.* JSON values. A missing or schema-invalid required value fails the tool before execute runs. Model arguments cannot override a binding with the same name. For durable loop resumes, trusted values are not restored from a persisted private snapshot. The host must re-authorize them through the invocation resolver; a missing or changed identity fails closed.

Dependencies and bundling

Cloud detects imported npm packages, installs them with lifecycle scripts disabled, and bundles the tool with esbuild for Node 22. Pure JavaScript dependencies are supported. Native addons containing .node binaries or binding.gyp are rejected; choose a pure JavaScript alternative. From 0.15.66, a tool entrypoint may import relative TypeScript, JavaScript, TSX, or JSON modules in the same source directory. The CLI resolves the static local graph and uploads one versioned artifact. Cycles and literal dynamic imports are supported. Computed dynamic imports, symlinks, files outside the tool directory, path traversal, and unsupported paths fail before upload. @polpo-ai/tools and @sinclair/typebox are runtime externals and do not need to be bundled.

Manage tools

polpo deploy also synchronizes .polpo/tools/*.ts. The Agent API exposes the same registry:
Saving source and deploying a bundle are distinct API operations. The CLI and dashboard perform both steps for you.