How input/output schema works with external agents
Modulo Team
An agent in a Modulo pipeline can declare two typed contracts: an input schema and an output schema. Together they make Modulo agent-agnostic: any agent that respects the contract can be plugged into any pipeline node. This is how Modulo integrates with existing agent runtimes like Claude Code, Cursor, and Codex.
Input schema
The input schema defines what data the agent receives when it is dispatched: the trigger context (repository, branch, PR number, ticket ID), the agent's prompt, and any relevant pipeline state. It is validated before dispatch, so invalid input is caught before the agent starts rather than failing mid-execution and wasting the invocation.
Output schema
The output schema defines what the agent must produce: a pull request diff, a PR description, a test file, a documentation update, or any other structured output. It is validated after the agent finishes, before any gate or human reviewer. If it does not match, the run pauses and the validation failure is recorded.
Schema versioning
Schemas are versioned with semver. Existing runs reference the schema version pinned in their snapshot, so updating a schema leaves them unaffected. A major version bump changes the contract in a breaking way: agents configured for the old schema will not be dispatched until updated. A minor bump expands the contract (new optional fields); existing agents continue to work.
Schema inference
Modulo can generate schema drafts from connector data. Connecting a GitHub repository lets Modulo inspect its structure and generate a schema for the types of changes the agent is expected to make. This is not a replacement for hand-authored schemas, but it accelerates initial setup.
What this enables
- Swap the agent runtime without changing the pipeline (Claude Code, Codex, Cursor - any agent that respects the contract)
- Validate agent output before it reaches any downstream system
- Evolve contracts independently of the agents that implement them
- Audit exactly what crossed each boundary in every run
The principle behind this: schema seams - schemas are opt-in, and a boundary that declares one is a typed contract, so an agent cannot pass garbage downstream without a record of it.