Skip to content

Manifest and Schemas

Sovereign

The manifest is your tool’s contract. It tells Valdr what the tool is called, which files it needs, how to start it, and exactly what each action accepts and returns. Because the contract is explicit, the Builder can offer the right input fields, Valdr can reject bad input before your code runs, and later steps can rely on the output shape.

Start with the working example, then use this page to look up a field.

The manifest at a glance

A manifest file ends in .tool.yaml, .tool.yml, or .tool.json and lives in a folder the pack includes. The finished example looks like this:

my-tools/
  pack.yaml
  tools/
    text/
      text.tool.yaml
      main.mjs
FieldWhat it holds
schemaVersionAlways 1
idThe tool’s identity, in the form <prefix>.user.<name>, such as my-tools.user.text. Use the pack value from pack.yaml (here my-tools) as the prefix so your IDs don’t collide with another pack’s. The name after .user. starts with a lowercase letter and uses lowercase letters and digits, with single dots, underscores, or hyphens between them
revisionThe exact revision string, such as 1.0.0. Use semantic versions so the newest revision is easy to tell apart
name, descriptionHuman-readable labels. name is what the Builder library shows
iconOptional icon name, such as code-bracket. See the supported list below
filesEvery file the tool needs, as {path, executable?} entries relative to the manifest
processHow to start the program: executable, a literal args list, and optional inheritEnv variable names; see environment setup
limitsPositive whole numbers for timeoutSeconds, maxInputBytes, maxResultBytes, and maxLogBytes
actionsOne or more actions the tool supports

Supported icons are command-line, code-bracket, code-bracket-square, variable, cube, cpu-chip, server-stack, cloud, ticket, and document-text. An omitted or unknown name uses the default tool icon.

The pack’s version and the tool’s revision are separate. Bump the tool revision whenever anything in the manifest or its listed files changes; Valdr rejects changed content under a revision it has already imported, even if that revision was removed from the catalog. Renaming a tool ID creates a new tool; workflows that pinned the old ID keep using it.

On each Valdr host, a tool ID belongs to the pack that first imported it. Importing the same ID from a different pack is rejected, even after the owner’s revisions are removed from the catalog, so ship updates from the owning pack and keep its pack value unchanged, or give your tool a new ID.

Actions

One tool can expose many actions from a single program. Valdr sends the chosen action’s id in the request, and your program dispatches on it.

Action fieldWhat it holds
idUnique within the tool, lowercase, such as summarize or repo-view. Valdr sends this as the request’s action
pathA list of words describing the command, such as [repo, view]. It is catalog metadata only and never becomes process arguments
name, descriptionHuman-readable labels
inputSchemaThe shape of the action’s input. Its root must be an object
outputSchemaThe shape of the successful data your program returns
executionsupported, or unsupported for actions you list but haven’t implemented
unsupportedReasonRequired for unsupported actions, and shown to users
sideEffectsread, write, or unknown. Describe what the action really does
retryidempotent if repeating the same operation is safe, otherwise manual

Put related actions in one tool. Use separate tools when programs need different runtimes, environment access, or release schedules.

To list a command you haven’t implemented yet, add it with execution: unsupported and a reason, such as unsupportedReason: "Interactive sign-in must be completed on the host." It stays visible in the Builder with that reason but can’t run.

Files, runtimes, and dependencies

List every file your tool needs under files. Valdr keeps exactly those files, verifies them before every run, and carries them through export and import.

Program kindprocess.executableprocess.argsThe workflow host provides
Nodenode[main.mjs]Node; list main.mjs in files
TypeScriptbun[main.ts]Bun; list main.ts
Pythonpython3[main.py]Python and any packages you import; list main.py
Shellsh[main.sh]A shell plus a real JSON parser such as jq; list main.sh
Packaged native program./bin/my-tool[]A compatible OS and architecture; list bin/my-tool with executable: true
Program already on the hostmy-tool[]A program on the host’s PATH that speaks the tool protocol

Good to know:

  • Arguments that name a listed file become absolute paths to the tool’s retained copy, so main.mjs still works when the step runs in a project folder. Other arguments stay literal, and Valdr never expands shell syntax, variables, or globs.
  • A bare executable name is found on the host’s PATH. A relative path containing / resolves inside the tool’s folder.
  • Import never installs anything. No package managers, install hooks, or compilers run. Bundle the helper files you need, or document what must be installed on the host. A lockfile alone doesn’t install dependencies.
  • Treat the tool’s own folder as read-only. Write output to the working directory, a destination given as input, or a temp folder. In Node, find bundled files with new URL('./asset.json', import.meta.url) and workflow files with process.cwd(). In Python, use Path(__file__).parent and Path.cwd().
  • Don’t set process.cwd. The workflow step chooses the working directory.
  • Wrapping a CLI? Most CLIs don’t speak the tool protocol, so point executable at an adapter program rather than at gh or aws directly. See Wrap a CLI.
File and path rules
Use relative paths with / separators and no empty, ., or .. segments. Valdr rejects missing or excluded files, symlinks, paths that escape the tool folder, duplicate IDs, and references to other tool manifests. A packaged executable must be listed with executable: true. An absolute executable path works but ties the tool to one host.

Input and output schemas

Schemas are where the contract gets its teeth. Valdr checks input before your program starts and checks your result before later steps see it.

  • Input: inputSchema describes the input object your program receives. Its root must be type: object.
  • Output: outputSchema describes only the successful data value, not the whole result envelope. It can be a schema object or true.
  • In the Builder: an input schema appears as named fields when its root sets additionalProperties: false, uses only type, properties, required, additionalProperties, title, and description, and every property is a string, number, integer, or boolean. Any other schema, including nested objects and arrays, uses JSON input. Both paths are validated against the same schema.
  • No silent fixes: Valdr doesn’t insert defaults, coerce strings to numbers, or strip extra properties. A default annotation is documentation only, so apply defaults in your program.

Use ordinary JSON Schema keywords: type, properties, required, additionalProperties, enum, minimum, maximum, minLength, maxLength, pattern, items, and $defs. For a nullable string, write type: [string, "null"].

Keep schemas specific. outputSchema: true accepts any JSON, but then users can’t count on stable fields to map.

For the summary example, the input is {"text":"Hello Valdr\nTools are ready."} and the successful data is {"characters":28,"words":5,"lines":2}. Both schemas reject extra properties.

Run valdr validate-pack to check your schemas before you import.

Strict validation rules

Schemas use a strict subset of JSON Schema 2020-12. Local $ref pointers within the same schema work. Remote references, $id, anchors, dynamic references, and custom keywords don’t. String format values such as date-time aren’t supported and fail validation. Older definitions and dependencies keywords, OpenAPI’s nullable, and vendor extensions also fail validation.

Manifests must be JSON-compatible: YAML files must contain one document with unique keys and no non-finite numbers or non-JSON values. Equivalent YAML and JSON manifests describe the same tool.

Unknown fields are rejected at every level: manifest, action, process, limits, and file entries. An optional top-level $schema is allowed as an editor hint.

Next step

Learn the request and result format your program reads and writes.