OpenSpec एजेंट अनुबंध
openspec CLI के मशीन-पठनीय सतह, src/ के विरुद्ध सत्यापित (कैपस्टोन ऑडिट, 2026-06-11)। नीचे दिया गया प्रत्येक आकार उत्सर्जक कोड से प्रलेखित है।
1. सामान्य प्रथाएँ
- प्रत्येक आह्वान पर एक JSON दस्तावेज़।
--jsonमोड में, stdout बिल्कुल एक JSON दस्तावेज़ (2-स्पेस सुंदर-मुद्रित) ले जाता है। मानव गद्य, स्पिनर और स्टोर बैनर stderr को जाते हैं। - स्टोर बैनर। मानव मोड में, स्टोर-चयनित रूट stderr पर
Using OpenSpec root: <id> (<path>)प्रिंट करता है। JSON मोड में कभी प्रिंट नहीं होता। - कुंजी कैसिंग सतह-निर्भर है (ज्ञात असंगतियाँ देखें): store/doctor/context पेलोड
snake_caseका उपयोग करते हैं; वर्कफ़्लो पेलोड (status,instructions,new change,validate,list)camelCaseका उपयोग करते हैं, सिवाय एम्बेडेडrootऑब्जेक्ट के, जो हमेशाstore_idका उपयोग करता है। - वैकल्पिक कुंजियाँ अधिकांश पेलोड में छोड़ दी जाती हैं, null नहीं सेट होती हैं (उदा.
root.store_id,member.path)। अपवाद जो स्पष्टnullका उपयोग करते हैं, आकार के अनुसार उल्लेखित हैं (स्टोर डॉक्टरgit.*, विफलता पेलोड)।
2. Diagnostic Envelope
हर machine-readable diagnostic (StoreDiagnostic) द्वारा एक ही envelope shape साझा किया जाता है:
{
"severity": "error" | "warning" | "info",
"code": "snake_case_string",
"message": "human sentence",
"target": "dotted.surface (optional)",
"fix": "one actionable sentence/command (optional)"
}Diagnostics दो स्थानों में प्रकट होते हैं: status arrays (status: StoreDiagnostic[] top level पर या per entry) health findings के लिए, और thrown errors जो command failure पर single-element status array में परिवर्तित हो जाते हैं।
3. Root Selection और RootOutput
सभी root-resolving commands (list, show, validate, status, instructions, instructions apply, instructions archive, new change, archive, doctor, context, schemas) एक OpenSpec root को एक ही precedence के साथ resolve करते हैं:
--store <id>→ registered store का root (source: "store")।- अन्यथा, nearest ancestor जिसमें
openspec/हो: planning shape →source: "nearest"(एकstore:pointer को stderr warning के साथ ignore किया जाता है); config-only dir जिसमें validstore:pointer हो → वह store,source: "declared"। - कोई nearest root नहीं + global
defaultStoreset है (openspec config set defaultStore <id>) → वह store,source: "global_default"; stale id underlying store error औरfixके साथ fail करता है जोopenspec config unset defaultStoreका नाम लेता है। - कोई nearest root नहीं, कोई default नहीं + registered stores मौजूद हैं → error
no_root_with_registered_stores। - कोई root नहीं, कोई default नहीं, कोई stores नहीं: commands cwd को
source: "implicit"के रूप में treat कर सकते हैं;doctor,context,list, और bulkvalidateइसके बजायno_openspec_rootके साथ fail करते हैं।listlegacy projects के लिए implicit fallback को preserve करता है जिनमेंopenspec/project.mdहोता है।
Successful JSON payloads सामान्यतः root को embed करते हैं; successful schemas --json deliberately compatibility bare array में रहता है जो §4.13 में documented है:
"root": { "path": "/abs/path", "source": "store" | "declared" | "global_default" | "nearest" | "implicit", "store_id": "id (only when store-selected)" }Root-failure contract: JSON mode में resolution failure stdout पर { ...commandNullShape, "status": [diagnostic] } print करता है और exit 1 करता है।
4. Command JSON Shapes
4.1 list --json
{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput } — ध्यान दें कि per-change status यहाँ string enum है। --specs: { "specs": [ { "id", "requirementCount" } ], "root" }।
4.2 show <item> --json
Change: { "id", "title", "deltaCount", "deltas": [...], "root" }। Spec: { "id", "title", "overview", "requirementCount", "requirements": [...], "metadata": { "version", "format", "sourcePath"? }, "root" }।
4.3 validate --json
{ "items": [ { "id", "type": "change"|"spec", "valid", "issues": [ { "level", "path", "message", "line"?, "column"? } ], "durationMs" } ], "summary": { "totals": {items,passed,failed}, "byType": {...} }, "version": "1.0", "root" }। जब कोई भी item fail हो तो Exit 1।
4.4 status --json
{ "changeName", "schemaName", "planningHome"?: { "kind", "root", "changesDir", "defaultSchema" }, "changeRoot", "artifactPaths": { "<id>": {outputPath, resolvedOutputPath, existingOutputPaths} }, "nextSteps": ["..."], "actionContext": { "mode": "repo-local", "sourceOfTruth": "repo", "planningArtifacts", "linkedContext", "allowedEditRoots", "requiresAffectedAreaSelection", "constraints" }, "isPlanningComplete", "isComplete", "applyRequires", "artifacts": [ {id, outputPath, status: "done"|"skipped"|"ready"|"blocked", requires, missingDeps?} ], "root" }। isPlanningComplete का अर्थ है कि हर non-skipped planning artifact मौजूद है; skipped artifacts को created किए बिना satisfied माना जाता है। इसका अर्थ यह नहीं है कि implementation tasks complete हैं। isComplete को compatibility alias के रूप में same value के साथ retained किया गया है। हर artifact का requires उसके direct dependency ids हैं (हर status के लिए present, ताकि transitive required set compute किया जा सके भले ही artifact done हो); missingDeps केवल तभी appear करता है जब blocked हो। artifacts array dependency order में है, जिसमें schema का artifacts: declaration order ties को break करता है artifacts के बीच जो एक ही समय पर ready हो जाते हैं (कभी alphabetical नहीं), इसलिए पहला ready entry वह artifact है जो अगला लिखना है; missingDeps उसी order का उपयोग करता है। "skipped" एक artifact को mark करता है जिसका generates path specs/ के तहत है एक change में जिसका .openspec.yaml skip_specs: true declare करता है; यह dependencies को satisfy करता है लेकिन इसे created नहीं किया जाना चाहिए। कोई active changes नहीं: { "changes": [], "message", "root" }, exit 0।
--all (batch, --change के साथ mutually exclusive — दोनों को combine करना error है जिसमें { "changes": [], "root": null, "status": [d] } null-shape होता है): { "changes": [ <per-change status object, no per-change root>, ... ], "root" }, change name के अनुसार sorted। एक change जो load करने में fail करता है { "changeName", "status": [d] } contribute करता है उसकी जगह; sweep जारी रहता है, complete envelope को preserve करता है, और text और JSON दोनों modes में exit 1 करता है। एक invalid --schema पूरे invocation को null-shape के साथ fail कर देता है, भले ही कोई changes मौजूद न हों।
4.5 instructions <artifact> --json
{ "changeName", "artifactId", "schemaName", "changeDir", "planningHome"?, "outputPath", "resolvedOutputPath", "existingOutputPaths", "description", "instruction"?, "context"?, "rules"?, "references"?: ReferenceIndexEntry[], "skipped"?, "warning"?, "template", "dependencies": [{id,done,path,description,skipped?}], "unlocks", "root" }। unlocks उन artifacts को list करता है जिन्हें यह ready बनाता है, schema के declaration order में (वही order जो status उन्हें recommend करता है)। "skipped": true (साथ में "warning") तभी appear करता है जब change skip_specs: true declare करता है और यह artifact skipped है — इसके files को created नहीं करना चाहिए。skipped: true वाला dependency entry files के बिना satisfied होता है — इसके paths को पढ़ने की कोशिश नहीं करनी चाहिए।
ReferenceIndexEntry: { "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] } — resolved entries root/specs/fetch carry करते हैं; unresolved entries store_id + warning status carry करते हैं। Index 50KB पर capped है (reference_index_truncated)।
4.6 instructions apply --json
{ "changeName", "changeDir", "schemaName", "contextFiles": { "<artifactId>": ["/abs", ...] }, "progress": {total,complete,remaining}, "tasks": [{id,description,done}], "state": "blocked"|"all_done"|"ready", "missingArtifacts"?, "missingPrerequisites"?, "warnings"?, "instruction", "references"?, "context"?, "operationGuidance"?, "root" }। missingArtifacts वह है जिस पर apply block होता है (schema का apply.requires); missingPrerequisites वह सब कुछ है जो apply के चलने से पहले बनाना है, build order में - उन requires का transitive closure, इसलिए यह लंबी list हो सकती है। warnings change के साथ non-blocking problems को list करता है - आज, एक change जो implement करने के लिए ready है लेकिन कोई delta specs नहीं और skip_specs: true नहीं, जो state openspec validate reject करता है। दोनों optional root fields (context, operationGuidance) हर invocation पर selected root से पढ़े जाते हैं। context एक required prompt-level input है जिसके relevant project facts, conventions, और constraints को apply किया जाना चाहिए; operationGuidance advisory input है जिसके entries केवल तभी follow किए जाते हैं जब applicable हों और built-in workflow के साथ compatible हों। दोनों state, tasks, progress, context files, और built-in instruction से अलग रहते हैं।
4.7 instructions archive --json
{ "changeName", "context"?, "operationGuidance"?, "root" }। resolved repo/store root में valid --change आवश्यक है और apply के रूप में same required-context/advisory-guidance semantics का उपयोग करता है। यह एक read-only runtime-input surface है: यह static archive workflow लौटाना नहीं, delta specs को inspect या merge करना नहीं, main specs लिखना नहीं, या change को move करना नहीं करता है।
4.8 new change <name> --json
Success: { "change": { "id", "path", "metadataPath", "schema" }, "root" }। Failure: { "change": null, "status": [d] }, exit 1।
4.9 archive <name> --json
Success: { "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"?, "warnings"? }, "root" }। Failure: { "archive": null, "root"?, "status": [d] }, exit 1। specsUpdated केवल तभी true होता है जब कम से कम एक spec file लिखा या retired हो (एक capability जिसका last requirement change ने हटाया है उसका spec deleted होता है, जिसके लिए change के .openspec.yaml में retire_capabilities: true आवश्यक है; हर retirement को warnings में नामित किया जाता है, और pasteable Git recovery command केवल तभी जब spec caller के checkout में था); पहले से synced change सभी zero totals के साथ archive होता है और skips को warnings में list किया जाता है। JSON mode strictly non-interactive है: हर prompt point एक archive_* code बन जाता है।
4.10 doctor --json
{ "root": { "path", "source", "store_id"?, "healthy", "status": [] }, "store": { "id", "metadata": {present,valid,remote?}, "origin_url"?, "drift"?: {ahead,behind}, "status": [] } | null, "references": [...], "status": [] }। drift (केवल तभी present जब git-backed store checkout में upstream tracking ref हो) last-fetched upstream के विरुद्ध ahead/behind counts हैं, live remote के विरुद्ध नहीं। किसी भी severity के health findings exit 0 करते हैं। Failure payload: { "root": null, "store": null, "references": [], "status": [d] }, exit 1।
4.11 context --json
{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store", "id", "path"?, "remote"?, "fetch"?, "status": [] } ], "status": [] }। AVAILABLE = path present AND status empty। --code-workspace <path> {folders:[{name,path}]} लिखता है (केवल available referenced stores, ref: prefixes के साथ); JSON mode में write print करने से पहले चलता है ताकि write failure पर भी stdout में exactly one document हो। Failure: { "root": null, "members": [], "status": [d] }, exit 1।
4.12 store ... --json
setup/register: { "store": {id, root, metadata_path?}, "registry": {path, registered, already_registered}, "git": {is_repository, initialized, committed}, "created_files": [], "status": [] }। unregister/remove: { "store", "registry": {path, removed}, "files": {deleted, deleted_path, left_on_disk}, "status": [] }। list: { "stores": [{id, root}], "status": [] }। doctor: { "stores": [ { id, root, metadata_path?, openspec_root: {...healthy, status}, metadata: {present, valid, id?, remote}, git: {is_repository, has_commits, has_uncommitted_changes, has_remote, origin_url}, status } ], "status": [] } (null = unknown/not probed)। Health findings exit 0 करते हैं; failures exit 1 करते हैं matching null-shape के साथ। Prompt cancellation exit 130 करता है।
4.13 schemas --json / templates --json
schemas: success bare array [ {name, description, artifacts, source} ] में रहता है; यह canonical root-selection precedence resolve करता है और --store <id> accept करता है। Root-selection failure: { "schemas": [], "root": null, "status": [d] }, exit 1। templates: keyed object { "<artifactId>": {path, source} }, अभी भी cwd-based root/status keys के बिना।
5. एग्ज़िट-कोड अनुबंध
| स्थिति | एग्ज़िट | स्टडआउट (Stdout) |
|---|---|---|
| सफलता, स्वास्थ्य निष्कर्षों सहित (डॉक्टर/संदर्भ/स्टोर डॉक्टर) | 0 | पेलोड |
--json मोड में कमांड विफलता | 1 | status: [d] और कमांड के नल-आकार (null-shape) के साथ एक JSON दस्तावेज़ |
असफल आइटमों के साथ validate | 1 | पूर्ण रिपोर्ट |
प्रॉम्प्ट रद्द (store समूह, मानव मोड) | 130 | केवल stderr |
6. नैदानिक कोड सूची
समाधान (Resolution)
no_openspec_root, no_root_with_registered_stores, no_registered_stores, unknown_store, store_identity_mismatch, unhealthy_store_root, store_path_not_supported, invalid_store_pointer, initiative_option_removed, areas_option_removed; पास-थ्रू: invalid_store_id, invalid_store_registry, invalid_store_metadata।
OpenSpec-रूट स्वास्थ्य (त्रुटि, कोई सुधार नहीं)
openspec_store_root_missing, openspec_store_root_not_directory, openspec_root_missing, openspec_root_not_directory, openspec_config_missing, openspec_config_not_file, openspec_specs_not_directory, openspec_changes_not_directory, openspec_archive_not_directory। स्टोर बीटा के दौरान, openspec/specs/, openspec/changes/, और openspec/changes/archive/ एक स्वस्थ रूट में अनुपस्थित हो सकते हैं; वे केवल त्रुटि हैं जब मौजूद हों लेकिन निर्देशिका न हों।
स्टोर रजिस्ट्री/पहचान/स्थिति
invalid_store_id, invalid_store_registry, invalid_store_metadata, store_registry_busy, store_not_found, no_store_registry, store_registry_changed, store_metadata_missing, store_metadata_id_mismatch, store_metadata_invalid, store_id_conflict, store_path_conflict, store_already_registered (सूचना)।
स्टोर सेटअप/पंजीकरण/हटाना
store_setup_id_required, store_setup_path_required, store_setup_path_not_directory, store_setup_inside_git_repo, store_setup_non_empty_directory, store_setup_cancelled, store_path_required, store_path_missing, store_path_not_directory, store_root_pointer_declared, store_register_root_unhealthy, store_register_identity_confirmation_required, store_register_cancelled, store_remote_empty, store_remote_requires_hand_edit, store_remove_confirmation_required, store_remove_cancelled, store_remove_path_not_directory, store_remove_metadata_missing, store_root_missing (हटाने में चेतावनी, डॉक्टर में त्रुटि), store_root_not_directory।
स्टोर गिट
store_git_init_failed, store_git_identity_missing, store_git_commit_failed, store_git_no_commits (चेतावनी), store_clone_fragile_directories (चेतावनी), store_remote_divergence (सूचना, डॉक्टर), store_checkout_drift (सूचना, डॉक्टर)।
संदर्भ (चेतावनी)
reference_invalid_id, reference_registry_unreadable, reference_unresolved, reference_root_unhealthy, reference_index_truncated।
संबंध (चेतावनी; डॉक्टर; संदर्भ केवल रजिस्ट्री वाला रखता है)
relationship_registry_unreadable, root_pointer_ignored, root_pointer_invalid, pointer_declarations_inert।
संग्रह (JSON मोड)
archive_change_name_required, archive_change_not_found, archive_change_symlink, archive_validation_failed, archive_confirmation_required, archive_tasks_incomplete, archive_spec_update_failed, archive_spec_validation_failed, archive_target_exists, archive_error।
संदर्भ लेखन
context_file_exists, context_output_dir_missing।
फॉलबैक
doctor_failed, context_failed, store_error, change_error, archive_error।
ज्ञात असंगतियाँ
कैपस्टोन ऑडिट द्वारा दर्ज; प्रकाशित-कुंजी नामकरण उत्पाद निर्णय हैं जो इस रिलीज़ से परे स्थगित किए गए हैं:
कैपस्टोन गॉन्टलेट राउंड में ठीक किया गया:--jsonमोड में, कई विफलता पथ केवल stderr पर प्रिंट करते थे, कोई JSON दस्तावेज़ नहीं।show/validateअज्ञात और अस्पष्ट आइटम{status:[{code: unknown_item | ambiguous_item, ...}]}उत्सर्जित करते हैं;status/instructions/list/show/validateमें फेंके गए त्रुटियाँ JSON-जागरूक विफलता सहायक (कमांड का नल-आकार +status) के माध्यम से मार्ग बदलती हैं;store <अज्ञात उपकमांड> --json{status:[{code: unknown_store_subcommand}]}उत्सर्जित करता है;listसमाधान विफलताओं पर अपना{changes|specs: [], root: null}नल-आकार रखता है।store_root_missingदो गंभीरताओं के साथ उत्सर्जित होता है (हटाने में चेतावनी, स्टोर डॉक्टर में त्रुटि) — संदर्भ-निर्भर, ऊपर दस्तावेज़ित।- snake_case (स्टोर परिवार) बनाम camelCase (कार्यप्रवाह परिवार) कुंजी प्रकार;
root.store_idहर जगह snake_case है। - src में चार समानांतर लिफाफा प्रकार घोषणाएँ मौजूद हैं; संग्रह डायग्नोस्टिक्स कभी भी
targetनहीं रखते। list --jsonप्रत्येक परिवर्तन के लिएstatusकुंजी को एक स्ट्रिंग एनम के रूप में पुन: उपयोग करता है।- केवल
validateआउटपुट मेंversionफ़ील्ड होता है। templatesरूट चयन को अनदेखा करता है (cwd-आधारित, कोई--storeनहीं)।- पुराने संज्ञा रूप (
change/specउपकमांड)root/statusके बिना अनलिफाफा पेलोड उत्सर्जित करते हैं।