Pi 1.5.0, released on November 2, 2026, changes input validation for custom AI tools: some extension-defined checks no longer run automatically. Affected extension authors need to preserve those rules before the tool takes action.
Pi is software for running AI assistants and extending them with tools. This migration concerns checks attached through TypeBox, a library used to describe tool inputs. It does not mean every Pi user needs to rewrite extensions: ordinary JSON Schema validation remains.
Version 1.5.0 is available on npm, with Node.js 22.19.0 or newer required. For affected tools, the useful upgrade question is whether the same inputs will still be accepted or rejected—not merely whether the extension loads.
Find the rules that need attention
Review the extensions you actually load, including installed packages and shared schema helpers. Search their source for Type.Refine, Format.Set, Type.Codec, Type.BigInt, Type.Undefined and Type.Void. Follow aliases and wrappers too; a text search is a starting point, not a complete inventory.
The version-pinned extension guide distinguishes these cases:
Existing feature | What Pi 1.5 does |
|---|---|
| Skips the custom predicate. Its underlying JSON Schema constraints still matter. |
| Does not use TypeBox’s custom format registrations. Standard formats remain checked, along with url and json-pointer-uri-fragment. |
| Does not decode the value delivered to |
| Cannot accept a JSON value at those schema positions. An optional property may still be omitted. |
These are different migration problems. An ignored predicate can let an otherwise valid value through; an unsupported value type can prevent a call from passing. The repository’s regression-test definitions include both an unenforced refinement and an omitted optional Undefined property that is expected to pass.
Keep each rule enforceable before the action
Keep required fields, bounds, patterns and permitted-value lists in JSON Schema where they express the intended rule. Pi’s schema library supports these constraints; a validator change alone is not a reason to rewrite every TypeBox-built schema.
For a custom rule that cannot be expressed equivalently there, place the check at the start of execute(), before the file write, network request or other action it governs. Reject by throwing an informative error or returning a proper tool result with isError: true. Both are documented error mechanisms; plain text saying “error” does not set the failure flag.
The order matters. The agent loop catches execution errors, but an error raised after an action cannot undo that action. As a migration check, identify the first side effect in each affected tool and ensure every relevant custom rule runs before it.
Handle representation changes separately. If a tool needs a decoded value, make the decoding explicit in its implementation. For a large integer identifier, consider a validated decimal string followed by explicit conversion, rather than routing it through a JavaScript number. These are design choices to review for the particular tool, not a universal replacement patch.
Check what reaches execute(), not just what was sent
Pi normalizes arguments before execution—converting input into forms allowed by the schema. Depending on that schema, a numeric string can become a number, and a scalar can become a one-item array. An optional property set to null is removed when its schema rejects null; a property that permits null keeps it. The coercion rules describe the distinctions.
There is a consequential edge case for integer fields. Pi’s upstream test definitions expect 3.7 and "3.7" to become 3 for a plain integer schema. These are the project’s expected outcomes, not results of an extension test performed for this article.
The implication is that adding Number.isInteger() inside execute() cannot reveal a fractional part already removed. If the rule must reject an originally fractional input, review how the value is represented and where it is checked. Moving a predicate without considering conversion may preserve the code but change the rule’s meaning.
Conversion itself is not entirely new: the 1.4.0 validator already included a plain-JSON conversion path. The 1.5.0 release notes describe a common conversion path for TypeBox and plain JSON Schema tools, including tools connected through the Model Context Protocol (MCP). That is not a reason to weaken independent server-side checks or permissions.
Verify permitted and rejected calls
Before relying on the upgraded extension, use a controlled setup with real writes and external requests replaced by harmless stand-ins that record whether they were called. Send calls through Pi’s validation-and-execution path, not only directly into execute(). Record the supplied arguments, the normalized values, the result and whether the action ran.
Use the project’s validation tests as a reference for schema behavior, then add cases for your own rules:
A valid input should reach the intended action with the expected normalized values.
An input that satisfies the basic JSON type but fails the old custom rule should produce an error without invoking the action.
A missing required field and unconvertible numeric text should still fail schema validation.
Review numeric strings, fractions in integer fields, scalar-to-array conversion and optional nulls. Include a nullable property to distinguish null from omission.
Where relevant, check decoded values and large identifiers for the intended representation and precision.
Also review scripts that match exact error messages: the release notes document changed validation wording. Use each extension’s actual schema and rules, and compare with the previously supported version where available.
For teams also maintaining OpenCode, the separate guide to preserving OpenCode access rules after its policy change addresses a different upgrade. Those permission rules should not be confused with Pi’s input validation.
