Handbook
ContractSpec v2 (metadata alongside v1 Markdown)
LCDL task contracts ship as Markdown under:
src/forge_lcdl/contracts/<task_id>/<version>/contract.md
Sprint 1 adds an optional machine-readable sidecar:
src/forge_lcdl/contracts/<task_id>/<version>/contract.json
The Markdown file stays the narrative source for humans. The JSON file (when present) carries ContractSpec fields for tooling: schemas, success criteria, failure modes, and policy hints for cheap models, benchmarks, and future verifiers.
Coexistence with v1
- Directory names and layout are unchanged.
TaskRunnerandrun_taskbehavior are unchanged; they do not readcontract.jsonyet.- Tasks without
contract.jsonstill work:load_contract_specsynthesizes a minimal spec from the registry plus Markdown (best-effort title), so callers never fail only because metadata is missing. - Unknown
task_id/versionraisesUnknownContractError.
API
Use forge_lcdl.contracts_api (src/forge_lcdl/contracts_api.py) — not a Python package named after the bundled contracts/ asset directory.
load_contract_spec(task_id, version="v1") -> ContractSpecvalidate_contract_input(spec, input_obj)/validate_contract_output(spec, output_obj)
ContractSpec fields
task_id,version,titleinput_schema/output_schema: JSON-Schema-like dicts (subset enforced by LCDL)success_criteria,failure_modes: lists of stringsretry_policy,verification_policy,fallback_policy: extensible dictscontract_markdown_path: relative path string matching the bundled layout (e.g.extract_schema_from_text/v1/contract.md)
contract.json format
Top-level object; use "contract_spec_format": 2 for the current metadata shape (format 1 in existing files is still accepted).
ContractSpec fields (v2)
All v1 fields, plus:
capabilities: extensible dict (e.g.uses_llm,supports_rag,returns_citations)execution_policy: dict (e.g.complexity,risk,max_attempts)inference_policy: dict (e.g.mode,min_confidence)rag_policy: dict (e.g.mode,top_k,require_citations,max_context_tokens)prompt_cache_policy: dict (e.g.enabled, stable/dynamic part hints)extensions: dict of unknown top-level keys preserved fromcontract.json(vendor-specific metadata)
Built-in defaults apply when contract.json omits these objects or when the spec is synthesized from Markdown-only tasks.
Unknown keys
Any top-level key in contract.json that is not part of the known ContractSpec mapping is stored in ContractSpec.extensions (not dropped).
Validation subset
validate_contract_input / validate_contract_output perform lightweight checks only (no jsonschema dependency):
- Top-level value must be a
dict. - If the schema has
required(list of strings), every key must be present. - If
propertiesmaps a key to{"type": "<json-schema-type>"}, when that key is present its value must match the shallow type (string,number,integer,boolean,object,array,null).
Nested object schemas are not fully validated in this sprint.
On failure, ContractValidationError is raised with a short message (missing keys or type mismatch).
Import smoke test
Install paths match the rest of the library: use a venv and pip install -e ".[dev]" (see README), then run python / python3 as usual. On a clean checkout without an install, point Python at src/:
cd forge-lcdl
PYTHONPATH=src python3 - <<'PY'
from forge_lcdl.contracts_api import load_contract_spec
for task_id in [
"extract_schema_from_text",
"llm_boolean_gate",
"llm_enum_route",
"decompose_problem",
"plan_decision_pack",
]:
spec = load_contract_spec(task_id, "v1")
print(task_id, spec.version, bool(spec.output_schema))
PY
Packaging
Wheel/sdist include both contracts/**/*.md and contracts/**/*.json (see pyproject.toml).
See also
- Benchmark harness:
docs/BENCHMARKS.md