agent-contracts 0.12.4 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -332,7 +332,7 @@ Design regressions become testable.
332
332
  * **Guardrail generation** from DSL + policy + bindings via `generate guardrails`
333
333
  * **Flexible file splitting** via `$ref` (replacement), `$refs` (import + deep-merge), and JSON Pointer `$ref` (in-document)
334
334
  * **YAML safety linting** for reserved word collision detection across YAML 1.1/1.2
335
- * **`x-extensions` declarations** for documenting project-specific custom extension fields
335
+ * **`extensions` declarations** with scope, schema validation, and strict enforcement for custom `x-*` fields
336
336
  * **`resolve --expand-defaults`** to materialize all Zod schema defaults in output
337
337
  * **DSL completeness scoring** with 7 dimensions, text/JSON output, and `--threshold` CI gate
338
338
  * **JSON Schema for editor support and external tooling**
@@ -373,15 +373,20 @@ guardrail_policies: {}
373
373
  components:
374
374
  schemas: {}
375
375
 
376
- # Optional: declare project-specific x-* extensions
377
- x-extensions:
376
+ extensions:
378
377
  x-flags:
379
378
  type: array
380
379
  items: string
381
380
  description: "CLI flags for tool commands"
382
- x-check-script:
381
+ x-path-hint:
383
382
  type: string
384
- description: "Path to hook check script"
383
+ description: "Filesystem path hint"
384
+ scope: [artifact]
385
+ schema:
386
+ type: string
387
+ minLength: 1
388
+ required: true
389
+ extensions_strict: false
385
390
  ````
386
391
 
387
392
  This makes definitions easy to merge, extend, and reference by stable identifiers.
@@ -612,22 +617,53 @@ tasks:
612
617
  `x-` prefixed custom properties work at any nesting level — including inside
613
618
  `execution_steps`, `rules`, `workflow.steps`, and other nested objects.
614
619
 
615
- ### `x-extensions` declarations
620
+ ### Extension declarations
616
621
 
617
- Projects can optionally declare their custom `x-*` extension fields in the DSL using `x-extensions`. This makes extensions discoverable and self-documenting:
622
+ Projects can declare their custom `x-*` extension fields in the DSL using `extensions`. This makes extensions discoverable, self-documenting, and — optionally — machine-validated:
618
623
 
619
624
  ````yaml
620
- x-extensions:
625
+ extensions:
621
626
  x-flags:
622
627
  type: array
623
628
  items: string
624
629
  description: "CLI flags for tool commands"
625
- x-check-script:
630
+ x-path-hint:
626
631
  type: string
627
- description: "Path to hook check script"
632
+ description: "Filesystem path hint"
633
+ scope: [artifact]
634
+ schema:
635
+ type: string
636
+ minLength: 1
637
+ required: true
638
+
639
+ extensions_strict: true # undeclared x-* properties become errors
628
640
  ````
629
641
 
630
- Each key must start with `x-` (validated at schema level). The `type`, `items`, and `description` fields describe the expected shape. This declaration is informational today; future versions may validate `x-*` field values against their declared schemas.
642
+ Each key must start with `x-` (validated at schema level). The declaration supports:
643
+
644
+ | Field | Type | Default | Description |
645
+ |-------|------|---------|-------------|
646
+ | `type` | `string` | *(required)* | Informational type descriptor |
647
+ | `items` | `string` | — | Item type (for array-typed extensions) |
648
+ | `description` | `string` | — | Human-readable description |
649
+ | `scope` | `string[]` | all node types | Restricts which DSL node types this extension may appear on |
650
+ | `schema` | `object` | — | JSON Schema to validate the extension value |
651
+ | `required` | `boolean` | `false` | Whether the extension must be present on every in-scope entity |
652
+
653
+ **Scope values**: `root`, `system`, `agent`, `task`, `execution_step`, `artifact`, `tool`, `tool_command`, `validation`, `handoff_type`, `workflow`, `workflow_step`, `policy`, `guardrail`, `guardrail_policy`, `rule`, `escalation_criterion`, `prerequisite`
654
+
655
+ **`extensions_strict`**: When `true`, any `x-*` property not declared in `extensions` is an error. When `false` (default), undeclared extensions produce a warning.
656
+
657
+ **Diagnostics**:
658
+
659
+ | Code | Severity | Trigger |
660
+ |------|----------|---------|
661
+ | `extension-scope-mismatch` | error | Extension used on a node type outside its declared `scope` |
662
+ | `extension-schema-violation` | error | Extension value fails the declared JSON Schema |
663
+ | `extension-required-missing` | error | Required extension missing on an in-scope entity |
664
+ | `undeclared-extension` | warning/error | Extension not declared in `extensions` (error when `extensions_strict: true`) |
665
+
666
+ > **Backward compatibility:** `x-extensions` and `x-extensions-strict` are still accepted as deprecated aliases. They produce a `deprecated-property` warning and are normalized to `extensions` / `extensions_strict` during validation.
631
667
 
632
668
  ---
633
669
 
@@ -1130,7 +1166,7 @@ guardrail_policies:
1130
1166
 
1131
1167
  ### Software bindings
1132
1168
 
1133
- Bindings define software-specific check implementations:
1169
+ Bindings define software-specific check implementations, output generation, and rendering:
1134
1170
 
1135
1171
  ````yaml
1136
1172
  # bindings/cursor.yaml
@@ -1152,6 +1188,19 @@ outputs:
1152
1188
  mode: write
1153
1189
  executable: true
1154
1190
  template: ./templates/cursor-hook-wrapper.sh.hbs
1191
+
1192
+ renders:
1193
+ - context: agent
1194
+ output: "{cursor_root}/agent-team/{agent.id}.md"
1195
+ template: ./templates/agent-prompt.md.hbs
1196
+ exclude:
1197
+ - architect
1198
+ - context: system
1199
+ output: "{cursor_root}/rules/agent-team.mdc"
1200
+ inline_template: |
1201
+ {{#each agents}}
1202
+ - {{@key}}: {{this.role_name}}
1203
+ {{/each}}
1155
1204
  ````
1156
1205
 
1157
1206
  ### Binding inheritance
@@ -1208,6 +1257,7 @@ Merge behavior:
1208
1257
  | `software` | Project wins |
1209
1258
  | `guardrail_impl` | Map merge by guardrail ID (new IDs added; same ID deep-merged) |
1210
1259
  | `outputs` | Map merge by output ID (project overrides base) |
1260
+ | `renders` | Array concatenation (base renders + project renders) |
1211
1261
  | `reporting` | Deep merge (project fields override base) |
1212
1262
  | passthrough fields | Project wins |
1213
1263
 
@@ -1239,6 +1289,62 @@ paths:
1239
1289
  git_hooks_root: scripts/git-hooks
1240
1290
  ````
1241
1291
 
1292
+ ### Binding template context
1293
+
1294
+ Both `outputs` and `renders` templates have access to the full binding generation context:
1295
+
1296
+ | Variable | Type | Description |
1297
+ |----------|------|-------------|
1298
+ | `system` | `{ id, name }` | System metadata |
1299
+ | `guardrails` | `Record<string, Guardrail>` | All guardrail definitions |
1300
+ | `policy` | `GuardrailPolicy` | Active guardrail policy |
1301
+ | `binding` | `SoftwareBinding` | Current binding |
1302
+ | `all_bindings` | `Record<string, SoftwareBinding>` | All loaded bindings |
1303
+ | `vars` | `Record<string, string>` | Variables from `config.vars` |
1304
+ | `paths` | `Record<string, string>` | Path variables from `config.paths` |
1305
+ | `reporting` | `{ commands, fail_open, timeout_ms } \| null` | Reporting config |
1306
+ | `resolved_checks` | `ResolvedCheck[]` | Resolved guardrail checks |
1307
+ | `tasks` | `Record<string, Task>` | All DSL tasks |
1308
+ | `artifacts` | `Record<string, Artifact>` | All DSL artifacts |
1309
+ | `agents` | `Record<string, Agent>` | All DSL agents |
1310
+ | `handoff_types` | `Record<string, HandoffType>` | All DSL handoff types |
1311
+ | `workflow` | `Record<string, Workflow>` | All DSL workflows |
1312
+
1313
+ DSL entities include passthrough fields (`x-*` extensions), so custom metadata defined in the DSL is accessible in templates (e.g., `{{agents.implementer.x-team}}`).
1314
+
1315
+ ### Binding renders
1316
+
1317
+ Binding `renders` provide entity-iteration rendering with full DSL context — the same capability as config-level `renders`, but defined within binding YAML files.
1318
+
1319
+ Each render target specifies a `context` type and an `output` path pattern:
1320
+
1321
+ | Field | Required | Description |
1322
+ |-------|----------|-------------|
1323
+ | `context` | yes | Entity type: `agent`, `task`, `artifact`, `tool`, `workflow`, `system`, etc. |
1324
+ | `output` | yes | Output path with `{entity.id}` and `{paths_var}` expansion |
1325
+ | `template` | one of | Path to external `.hbs` template file |
1326
+ | `inline_template` | one of | Inline Handlebars template string |
1327
+ | `include` | no | Only render these entity IDs |
1328
+ | `exclude` | no | Skip these entity IDs |
1329
+ | `skip_empty` | no | Delete target if rendered output is empty |
1330
+ | `executable` | no | Set file permissions to 0755 |
1331
+
1332
+ For non-`system` contexts, one file is generated per entity (filtered by `include`/`exclude`). The output path supports two types of variable expansion:
1333
+
1334
+ - `{agent.id}`, `{task.id}`, etc. — replaced with the current entity ID
1335
+ - `{cursor_root}`, `{observability_root}`, etc. — replaced from `config.paths`
1336
+
1337
+ **When to use binding renders vs config renders vs binding outputs:**
1338
+
1339
+ | Use case | Recommended |
1340
+ |----------|-------------|
1341
+ | Generate per-entity files (agent prompts, workflow docs) | Binding `renders` or config `renders` |
1342
+ | Generate guardrail/policy runtime artifacts | Binding `outputs` |
1343
+ | Generate files using DSL data + guardrail data | Binding `renders` (has both) |
1344
+ | Simple config without bindings | Config `renders` |
1345
+
1346
+ Config `renders` remains supported and is not deprecated. Binding `renders` offers the advantage of co-locating templates with their binding definition and having access to the full binding context (`vars`, `paths`, `resolved_checks`, etc.) in addition to DSL entities.
1347
+
1242
1348
  ### Generate command
1243
1349
 
1244
1350
  ````bash
@@ -1263,6 +1369,8 @@ Checks:
1263
1369
  * handoff schema shape (meta-validated as valid JSON Schema via ajv)
1264
1370
  * `allOf` composition in handoff schemas
1265
1371
  * invalid custom properties without `x-` prefix (checked at all nesting levels)
1372
+ * `extensions` declaration validation — scope, schema, required, and undeclared checks
1373
+ * `extensions_strict` enforcement — reject undeclared `x-*` properties when enabled
1266
1374
 
1267
1375
  Custom properties with `x-` prefix are allowed on any object in the DSL — top-level entities (agents, tasks, artifacts, …), nested objects (rules, execution steps, workflow steps, …), and the root DSL itself.
1268
1376