agent-contracts 0.6.1 → 0.7.1

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
@@ -204,6 +204,15 @@ An **Artifact** defines the objects that move through the workflow:
204
204
  * required validations
205
205
  * visibility
206
206
 
207
+ ### Workflow
208
+
209
+ A **Workflow** defines a phase-level execution sequence:
210
+
211
+ * description
212
+ * entry conditions
213
+ * trigger
214
+ * ordered steps (handoff, validation, decision)
215
+
207
216
  ### Handoff
208
217
 
209
218
  A **Handoff** is a runtime delegation instance.
@@ -244,6 +253,7 @@ Design regressions become testable.
244
253
  * **Structured handoff definitions**
245
254
  * **Artifact ownership and lifecycle modeling**
246
255
  * **Config-driven prompt rendering**
256
+ * **Variable substitution** via `${vars.xxx}` in DSL values
247
257
  * **Inheritance with merge operators via `extends`**
248
258
  * **Flexible file splitting** via `$ref` (replacement) and `$refs` (import + deep-merge)
249
259
  * **JSON Schema for editor support and external tooling**
@@ -457,12 +467,13 @@ tasks:
457
467
  execution_steps:
458
468
  - id: read-specs
459
469
  action: "Read spec-md and design-docs"
460
- description: "Read all relevant specification and design documents"
470
+ reads_artifact: spec-md
461
471
  - id: implement
462
472
  action: "Implement changes in codebase"
473
+ produces_artifact: codebase
474
+ depends_on: [read-specs]
463
475
  - id: run-db-lint
464
476
  action: "Run db-lint"
465
- description: "Run database schema linter to check migrations"
466
477
  uses_tool: db-lint
467
478
  x-timeout: 120
468
479
  completion_criteria:
@@ -492,6 +503,33 @@ artifacts:
492
503
 
493
504
  ---
494
505
 
506
+ ## Example: Workflow definition
507
+
508
+ ````yaml
509
+ workflow:
510
+ specify:
511
+ description: "Externalize requirements — create spec.md from user stories"
512
+ entry_conditions:
513
+ - User story or feature request received
514
+ trigger: "User invokes /speckit.specify or asks to create a feature spec."
515
+ steps:
516
+ - type: handoff
517
+ handoff_kind: delegation
518
+ task: specify-feature
519
+ from_agent: main-architect
520
+ - type: validation
521
+ validation_id: spec-semantic-review
522
+ - type: decision
523
+ agent: main-architect
524
+ options:
525
+ - label: approve
526
+ next_workflow: plan
527
+ - label: revise
528
+ retry_from_step: 0
529
+ ````
530
+
531
+ ---
532
+
495
533
  ## Inheritance and merge operators
496
534
 
497
535
  `agent-contracts` supports shared base definitions with project-level overrides through `extends`.
@@ -533,6 +571,67 @@ Supported merge operators:
533
571
 
534
572
  ---
535
573
 
574
+ ## Variable substitution
575
+
576
+ When using `extends` to share a base DSL across projects, base definitions often contain values that differ per project (project name, language, repository URL, etc.).
577
+
578
+ `vars` in `agent-contracts.config.yaml` lets you define project-specific values that are substituted into DSL string values using `${vars.xxx}` syntax.
579
+
580
+ ### Defining vars
581
+
582
+ Add a `vars` section to your config file. Values must be flat string key-value pairs.
583
+
584
+ ````yaml
585
+ # agent-contracts.config.yaml
586
+ vars:
587
+ project_name: "my-service"
588
+ language: "TypeScript"
589
+ repo_url: "https://github.com/org/my-service"
590
+ ````
591
+
592
+ ### Using placeholders in DSL
593
+
594
+ Use `${vars.<key>}` in any string value within the DSL YAML (base or project).
595
+
596
+ ````yaml
597
+ # base/agent-contracts.yaml
598
+ agents:
599
+ implementer:
600
+ purpose: "Implements features for ${vars.project_name}"
601
+ constraints:
602
+ - "Use ${vars.language} for all implementations"
603
+ - "Repository: ${vars.repo_url}"
604
+ ````
605
+
606
+ ### Processing order
607
+
608
+ Variable substitution happens **after** DSL resolution (`extends` merge) and **before** schema validation:
609
+
610
+ 1. Load config (including `vars`)
611
+ 2. Resolve DSL (load + merge `extends`)
612
+ 3. Substitute `${vars.xxx}` in all string values
613
+ 4. Validate schema
614
+ 5. Render / lint / check
615
+
616
+ This ensures that merged strings from both base and project are substituted, and the resulting values pass schema validation.
617
+
618
+ ### Error handling
619
+
620
+ If a placeholder references an undefined variable, the command exits with an error:
621
+
622
+ ````
623
+ VarsSubstitutionError: Undefined variable "repo_url" in value "Repository: ${vars.repo_url}"
624
+ Defined vars: project_name, language
625
+ ````
626
+
627
+ ### Notes
628
+
629
+ - Only string values are substituted; object keys are not affected.
630
+ - `vars` is optional. If omitted, no substitution occurs.
631
+ - Patterns that do not match `${vars.<key>}` (e.g. `${env.HOME}`, `$vars.xxx`, `{{vars.xxx}}`) are left unchanged.
632
+
633
+ ---
634
+
536
635
  ## CLI
537
636
 
538
637
  ### Installation
@@ -576,6 +675,11 @@ Rendering is configured via `agent-contracts.config.yaml`.
576
675
  ````yaml
577
676
  dsl: ./agent-contracts.yaml
578
677
 
678
+ vars:
679
+ project_name: "my-service"
680
+ language: "TypeScript"
681
+ repo_url: "https://github.com/org/my-service"
682
+
579
683
  renders:
580
684
  - template: ./templates/agent-prompt.md.hbs
581
685
  context: agent
@@ -597,6 +701,68 @@ This lets you generate static outputs for:
597
701
 
598
702
  all from the same resolved DSL.
599
703
 
704
+ ### Available context types
705
+
706
+ Each `context` type provides a different rendering scope:
707
+
708
+ | Context | Scope | Output | Key variables |
709
+ |---------|-------|--------|---------------|
710
+ | `system` | Single file | `output` as-is | `system`, `dsl` |
711
+ | `agent` | Per agent | `{agent.id}` in output path | `agent`, `receivableTasks`, `delegatableTasks`, `relatedArtifacts`, `relatedTools`, `relatedHandoffTypes`, `mergedBehavior`, `dsl` |
712
+ | `task` | Per task | `{task.id}` in output path | `task`, `targetAgent`, `dsl` |
713
+ | `artifact` | Per artifact | `{artifact.id}` in output path | `artifact`, `relatedTools`, `relatedValidations`, `producerAgents`, `consumerAgents`, `editorAgents`, `createdInWorkflows`, `dsl` |
714
+ | `tool` | Per tool | `{tool.id}` in output path | `tool`, `invokableAgents`, `inputArtifactDetails`, `outputArtifactDetails`, `dsl` |
715
+ | `validation` | Per validation | `{validation.id}` in output path | `validation`, `dsl` |
716
+ | `handoff_type` | Per handoff type | `{handoff_type.id}` in output path | `handoff_type`, `relatedTasks`, `dsl` |
717
+ | `workflow` | Per workflow phase | `{workflow.id}` in output path | `workflow`, `relatedAgents`, `relatedTasks`, `relatedTools`, `relatedArtifacts`, `relatedValidations`, `dsl` |
718
+ | `policy` | Per policy | `{policy.id}` in output path | `policy`, `dsl` |
719
+
720
+ #### Enriched context details
721
+
722
+ **`workflow` context** collects all entities involved in a phase:
723
+
724
+ * `relatedTasks` — tasks where `task.workflow` matches this phase
725
+ * `relatedAgents` — agents from task `target_agent`, `allowed_from_agents`, step `from_agent`, and validation executors
726
+ * `relatedTools` — tools from `can_execute_tools` of all related agents, plus `uses_tool` in execution steps
727
+ * `relatedArtifacts` — artifacts from `can_read_artifacts`, `can_write_artifacts`, `input_artifacts`, plus `produces_artifact` and `reads_artifact` in execution steps
728
+ * `relatedValidations` — validations referenced in workflow steps
729
+
730
+ **`artifact` context** provides ownership and cross-reference data:
731
+
732
+ * `relatedTools` — tools with this artifact in `input_artifacts` or `output_artifacts`
733
+ * `relatedValidations` — validations targeting this artifact
734
+ * `producerAgents` / `consumerAgents` / `editorAgents` — resolved agent records
735
+ * `createdInWorkflows` — workflow phases where this artifact is written
736
+
737
+ **`tool` context** resolves agent and artifact references:
738
+
739
+ * `invokableAgents` — agents listed in `invokable_by`
740
+ * `inputArtifactDetails` / `outputArtifactDetails` — resolved artifact records
741
+
742
+ ### Handlebars helpers
743
+
744
+ Templates can use these built-in helpers:
745
+
746
+ | Helper | Usage | Description |
747
+ |--------|-------|-------------|
748
+ | `eq` | `{{#if (eq a b)}}` | Strict equality |
749
+ | `notEmpty` | `{{#if (notEmpty obj)}}` | True when object has at least one key |
750
+ | `inc` | `{{inc @index}}` | Increment number by 1 (for 1-based indexing) |
751
+ | `yamlBlock` | `{{{yamlBlock obj}}}` | Render value as YAML-formatted text |
752
+ | `lookupPayloadFields` | `{{#each (lookupPayloadFields payload)}}` | Extract payload field info (name, type, required, enum) |
753
+ | `join` | `{{join arr ", "}}` | Join array elements with separator |
754
+ | `contains` | `{{#if (contains arr "x")}}` | True when array includes value |
755
+ | `groupBy` | `{{#with (groupBy arr "key")}}` | Group array elements by field value |
756
+ | `filterByField` | `{{#each (filterByField arr "field" "val")}}` | Filter array by field match |
757
+ | `keys` | `{{#each (keys obj)}}` | Object keys as array |
758
+ | `values` | `{{#each (values obj)}}` | Object values as array |
759
+ | `size` | `{{size obj}}` | Array length or object key count |
760
+ | `not` | `{{#if (not x)}}` | Boolean negation |
761
+ | `or` | `{{#if (or a b)}}` | Boolean OR (variadic) |
762
+ | `and` | `{{#if (and a b)}}` | Boolean AND (variadic) |
763
+ | `gt` / `gte` / `lt` | `{{#if (gt a b)}}` | Numeric comparisons |
764
+ | `sequenceDiagram` | `{{{sequenceDiagram}}}` | Generate Mermaid sequence diagram from workflow context (requires `workflow` context) |
765
+
600
766
  ---
601
767
 
602
768
  ## Validation model