Skip to main content

AI agents

A form built with this engine is self-describing: it hands an AI agent (or any automation) the questions, their allowed values and the precedence rules, so answers can arrive unattended - without the agent ever reading your form's source. The facade exposes three calls for this - agentHelp(), schema() and validate() - and you surface them in your own tool, so an agent can discover the form the moment it meets it.

The answer schema

agentHelp() returns a JSON Schema (draft 2020-12) of the answers - the object an agent supplies, keyed by question id. Each property carries its type and allowed values (a select's enum, a number's minimum/maximum), its title and description, its default, and the env variable that sets it. What it deliberately doesn't name is CLI flags: the flags an agent ultimately calls are yours to define. You retrieve the schema and fold it into your own help - an "AI agents" section of --help, a dedicated flag, a generated README:

use DrevOps\Tui\Tui;

// The library hands back the schema; the consumer decides where it goes.
echo (new Tui($form))->agentHelp();

The schema the produce-order form emits:

{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"properties": {
"name": {
"type": "string",
"title": "Order name",
"env": "TUI_NAME"
},
"fruit": {
"type": "string",
"enum": ["apple", "banana", "cherry"],
"title": "Fruit",
"default": "banana",
"env": "TUI_FRUIT"
},
"quantity": {
"type": "integer",
"minimum": 1,
"maximum": 99,
"title": "Quantity",
"default": 6,
"env": "TUI_QUANTITY"
},
"organic": {
"type": "boolean",
"title": "Organic only?",
"default": false,
"env": "TUI_ORGANIC"
}
},
"required": ["name"],
"x-precedence": ["provided", "environment", "discovered", "derived", "default"]
}

Each env is the variable that sets its answer - the uppercased id under the active prefix, which defaults to TUI_ and changes with ->envPrefix('MYAPP_') on the form or new Tui($form, env_prefix: 'MYAPP_'). The root x-precedence is the resolution order described below.

Full metadata and validation

schema() is the fuller, raw description: the same questions with every declared attribute - options, bounds, and the internal when, derive and discover rules - under a prompts key. Reach for it when your tooling wants the complete picture rather than the answer contract:

{
"prompts": [
{
"id": "name",
"type": "text",
"label": "Order name",
"description": "",
"options": [],
"default": "",
"required": true,
"min": null,
"max": null,
"step": null,
"min_date": null,
"max_date": null,
"week_start": null,
"when": null,
"derive": null,
"discover": null,
"depends_on": []
}
]
}

validate() checks an answer set against those rules before collection, so an agent can confirm a payload without running the form. Each violation is one message; an empty list means the answers are valid:

$errors = $tui->validate(['name' => 'Weekly Box', 'fruit' => 'grape', 'quantity' => 500]);
// [
// 'Question "fruit": value "grape" is not one of: apple, banana, cherry.',
// 'Question "quantity" must be between 1 and 99.',
// ]

Precedence and environment variables

The schema's x-precedence spells out how every field resolves - the first source that provides a value wins:

  1. Provided - an explicit value you pass in, however your interface accepts one. Highest precedence.
  2. Environment - the per-question variable named in env (e.g. TUI_NAME), the uppercased id under the active prefix.
  3. Discovered - a value detected from the target directory (see Discovery).
  4. Derived - a value computed from other fields.
  5. Default - the declared default.

Runnable example

playground/08-headless-agent-cli.php folds agentHelp() into a consumer tool's help, and agentHelp(), schema() and validate() each have a script of their own beside it in playground/08-headless-*.

See also Headless collection for driving the same form from CI and self-describing answers for what comes back.