สัญญาของ OpenSpec Agent
พื้นผิวที่เครื่องสามารถอ่านได้ของ CLI openspec ซึ่งได้รับการตรวจสอบกับ src/ (การตรวจสอบแบบ capstone, 2026-06-11) รายละเอียดโครงสร้างทั้งหมดด้านล่างนี้ถูกจัดทำขึ้นจากโค้ดที่เป็นแหล่งกำเนิด
1. ข้อตกลงทั่วไป
- หนึ่งเอกสาร JSON ต่อหนึ่งครั้งของการเรียกใช้งาน ในโหมด
--jsonstdout จะส่งคืนเอกสาร JSON เพียงหนึ่งฉบับ (จัดรูปแบบสวยงามโดยเว้นวรรค 2 ช่อง) ข้อความอธิบายสำหรับมนุษย์ ตัวหมุนสถานะ (spinners) และแบนเนอร์ของ store จะถูกส่งไปยัง stderr - แบนเนอร์ของ store ในโหมดสำหรับมนุษย์ เมื่อมีการเลือก root ของ store แล้ว จะพิมพ์ข้อความ
Using OpenSpec root: <id> (<path>)ไปยัง stderr และไม่มีการพิมพ์ข้อความนี้ในโหมด JSON - การใช้ตัวพิมพ์ใหญ่-เล็กของคีย์ขึ้นอยู่กับพื้นผิวการใช้งาน (ดูส่วนความไม่สอดคล้องที่ทราบ): โหลดข้อมูลของ store/doctor/context ใช้
snake_case; โหลดข้อมูลของ workflow (status,instructions,new change,validate,list) ใช้camelCaseยกเว้นออบเจกต์rootที่ฝังอยู่ ซึ่งจะใช้store_idเสมอ - คีย์ที่ไม่จำเป็นจะถูกตัดออก ไม่ใช่กำหนดเป็น null ในโหลดข้อมูลส่วนใหญ่ (เช่น
root.store_id,member.path) ข้อยกเว้นที่กำหนดค่าnullอย่างชัดเจนจะระบุไว้ในแต่ละโครงสร้าง (git.* ของ store doctor, โหลดข้อมูลความล้มเหลว)
2. เอ็นเวลอปสำหรับการวินิจฉัย (The diagnostic envelope)
รูปร่างของเอ็นเวลอปหนึ่งรูปแบบถูกใช้ร่วมกันโดยทุกการวินิจฉัยที่เครื่องอ่านได้ (StoreDiagnostic):
{
"severity": "error" | "warning" | "info",
"code": "snake_case_string",
"message": "human sentence",
"target": "dotted.surface (optional)",
"fix": "one actionable sentence/command (optional)"
}การวินิจฉัยปรากฏในสองตำแหน่ง: อาร์เรย์สถานะ (status: StoreDiagnostic[] ที่ระดับบนสุดหรือต่อรายการ) สำหรับการค้นพบด้านสุขภาพ และ ข้อผิดพลาดที่ถูกโยน (thrown errors) ซึ่งแปลงเป็นอาร์เรย์ status ขนาดหนึ่งองค์ประกอบเมื่อคำสั่งล้มเหลว
3. การเลือกรากและ RootOutput
คำสั่งทั้งหมดที่แก้ไขราก (list, show, validate, status, instructions, instructions apply, instructions archive, new change, archive, doctor, context, schemas) จะแก้ไข OpenSpec root เพียงหนึ่งตัวด้วยลำดับความสำคัญดังนี้:
--store <id>→ รากของสต็อกที่ลงทะเบียน (source: "store").- หากไม่เป็นเช่นนั้น ให้หาผู้บรรพบุรุษที่ใกล้ที่สุดที่มี
openspec/: รูปร่างการวางแผน →source: "nearest"(ตัวชี้store:จะถูกละเว้นพร้อมคำเตือน stderr); ไดเรกทอรีที่มีเฉพาะคอนฟิกพร้อมตัวชี้store:ที่ถูกต้อง → สต็อกนั้น,source: "declared". - ไม่มีรากที่ใกล้ที่สุด + มีการตั้งค่า
defaultStoreทั่วโลก (openspec config set defaultStore <id>) → สต็อกนั้น,source: "global_default"; id ที่ล้าสมัยจะล้มเหลวพร้อมข้อผิดพลาดของสต็อกพื้นฐานและfixที่ระบุopenspec config unset defaultStore. - ไม่มีรากที่ใกล้ที่สุด, ไม่มีค่าเริ่มต้น + มีสต็อกที่ลงทะเบียนอยู่ → ข้อผิดพลาด
no_root_with_registered_stores. - ไม่มีราก, ไม่มีค่าเริ่มต้น, ไม่มีสต็อก: คำสั่งอาจถือว่า cwd เป็น
source: "implicit";doctor,context,listและการตรวจสอบแบบกลุ่มvalidateจะล้มเหลวแทนด้วยno_openspec_root.listจะรักษาการสลับกลับแบบ implicit สำหรับโปรเจกต์รุ่นเก่าที่มีopenspec/project.md
โหลด JSON ที่สำเร็จปกติจะฝังรากไว้ภายใน; schemas --json ที่สำเร็จจงใจยังคงเป็นอาร์เรย์เปล่าตามเอกสารใน §4.13:
"root": { "path": "/abs/path", "source": "store" | "declared" | "global_default" | "nearest" | "implicit", "store_id": "id (only when store-selected)" }สัญญาความล้มเหลวของราก: ในโหมด JSON ความล้มเหลวในการแก้ไขจะพิมพ์ { ...commandNullShape, "status": [diagnostic] } บน stdout และออกด้วยรหัส 1
4. รูปร่าง JSON ของคำสั่ง
4.1 list --json
{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput } — โปรดสังเกตว่า status ต่อการเปลี่ยนแปลงเป็นเอนัมสตริงที่นี่ --specs: { "specs": [ { "id", "requirementCount" } ], "root" }.
4.2 show <item> --json
การเปลี่ยนแปลง: { "id", "title", "deltaCount", "deltas": [...], "root" }. สเปค: { "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" }. ออกด้วยรหัส 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 หมายถึงอาร์ติแฟกต์การวางแผนที่ไม่ได้ถูกละเว้นทุกชิ้นมีอยู่; อาร์ติแฟกต์ที่ถูกละเว้นนับว่าเป็นที่พอใจโดยไม่ต้องสร้าง มันไม่ได้หมายถึงงานด้านการนำไปปฏิบัติเสร็จสิ้น isComplete ถูกเก็บไว้เป็นอิลิแอสความเข้ากันได้ที่มีค่าเดียวกัน requires ของแต่ละอาร์ติแฟกต์คือไอดีของการพึ่งพาโดยตรงของมัน (มีอยู่ในทุกสถานะ ดังนั้นชุดที่ต้องพึ่งพาแบบทรานซิติฟจึงสามารถคำนวณได้แม้ว่าอาร์ติแฟกต์จะเป็น done; missingDeps จะปรากฏเฉพาะเมื่อ blocked เท่านั้น) อาร์เรย์ artifacts อยู่ในลำดับการพึ่งพา โดยลำดับการประกาศ artifacts: ของสเปคมักจะใช้เพื่อแก้กรณีเสมอกันระหว่างอาร์ติแฟกต์ที่กลายเป็น ready พร้อมกัน (ไม่ใช่ตามตัวอักษร) ดังนั้นรายการ ready ตัวแรกคืออาร์ติแฟกต์ที่จะเขียนถัดไป; missingDeps ใช้ลำดับเดียวกัน "skipped" ทำเครื่องหมายอาร์ติแฟกต์whose generates path อยู่ภายใต้ specs/ ในการเปลี่ยนแปลงwhose .openspec.yaml ประกาศ skip_specs: true; มันทำให้การพึ่งพามีความสมบูรณ์แต่ไม่ควรสร้างไฟล์ ไม่มี actively changes: { "changes": [], "message", "root" }, ออกด้วยรหัส 0
--all (แบบแบตช์, ขัดแย้งกับ --change — การรวมกันทั้งสองอย่างถือเป็นข้อผิดพลาดด้วย null-shape { "changes": [], "root": null, "status": [d] }): { "changes": [ <per-change status object, no per-change root>, ... ], "root" }, เรียงตามชื่อการเปลี่ยนแปลง การเปลี่ยนแปลงที่โหลดไม่สำเร็จจะมีส่วน { "changeName", "status": [d] } แทนที่; การกวาดล้างจะดำเนินต่อไป รักษาเอ็นเวลอปให้สมบูรณ์ และออกด้วยรหัส 1 ทั้งในโหมดข้อความและ JSON การกำหนดค่า --schema ที่ไม่ถูกต้องจะทำให้การเรียกใช้งานทั้งหมดล้มเหลวด้วย null-shape แม้ว่าจะไม่มีการเปลี่ยนแปลงก็ตาม
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 ระบุอาร์ติแฟกต์ที่ทำให้ชิ้นนี้พร้อมใช้งาน ตามลำดับการประกาศในสเปค (ลำดับเดียวกับที่ status แนะนำ) "skipped": true (พร้อม "warning") จะปรากฏเมื่อการเปลี่ยนแปลงประกาศ skip_specs: true และอาร์ติแฟกต์นี้ถูกละเว้น — อย่าสร้างไฟล์ของมัน รายการการพึ่งพาที่มี skipped: true ถือว่าเสร็จสมบูรณ์โดยไม่ต้องใช้ไฟล์ — อย่าพยายามอ่านเส้นทางของมัน
ReferenceIndexEntry: { "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] } — รายการที่แก้ไขแล้วจะมี root/specs/fetch; รายการที่ยังไม่แก้ไขจะมี store_id + สถานะ warning ดัชนีจำกัดอยู่ที่ 50KB (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 ล่าช้า (the schema's apply.requires); missingPrerequisites คือทุกอย่างที่ยังต้องสร้างก่อนที่ apply จะทำงานได้ ในลำดับการสร้าง - ปิดล้อมแบบทรานซิติฟของ those requires ดังนั้นอาจเป็นรายการที่ยาวกว่า warnings ระบุปัญหาที่ไม่บล็อกกับการเปลี่ยนแปลงเอง — ปัจจุบันคือการเปลี่ยนแปลงที่พร้อมสำหรับการนำไปปฏิบัติโดยไม่มี delta specs และไม่มี skip_specs: true ซึ่ง state openspec validate ปฏิเสธ ทั้งฟิลด์ root สองฟิลด์ (context, operationGuidance) อ่านจาก root ที่เลือกในทุกการเรียกใช้งาน context เป็นการป้อนข้อมูลระดับ prompt whose ข้อเท็จจริงโครงการที่เกี่ยวข้อง แนวทางปฏิบัติ และข้อจำกัดต้องถูกนำไปใช้; operationGuidance เป็นการป้อนข้อมูลเชิงคำแนะนำ whose entries จะปฏิบัติตามก็ต่อเมื่อเกี่ยวข้องและเข้ากันได้กับ workflow ภายใน ทั้งสองยังคงแยกออกจาก state, tasks, progress, context files และ instruction ภายใน
4.7 instructions archive --json
{ "changeName", "context"?, "operationGuidance"?, "root" }. ต้องการ --change ที่ถูกต้องใน root ของ repo/store ที่แก้ไขแล้ว และใช้ semantics ของ required-context/advisory-guidance เดียวกันกับ apply นี่คือพื้นผิว runtime-input แบบอ่านอย่างเดียว: มันไม่คืนค่า workflow archivestatic, ตรวจสอบหรือรวม delta specs, เขียน main specs หรือย้ายการเปลี่ยนแปลง
4.8 new change <name> --json
สำเร็จ: { "change": { "id", "path", "metadataPath", "schema" }, "root" }. ล้มเหลว: { "change": null, "status": [d] }, ออกด้วยรหัส 1
4.9 archive <name> --json
สำเร็จ: { "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"?, "warnings"? }, "root" }. ล้มเหลว: { "archive": null, "root"?, "status": [d] }, ออกด้วยรหัส 1 specsUpdated เป็นจริงเฉพาะเมื่อมีไฟล์สเปคอย่างน้อยหนึ่งไฟล์ถูกเขียนหรือเกษียณ (ความสามารถwhose requirement สุดท้ายการเปลี่ยนแปลงลบไปจะมีสเปคถูกลบ ซึ่งต้องการ retire_capabilities: true ใน .openspec.yaml ของการเปลี่ยนแปลง; การเกษียณทุกครั้งจะถูกตั้งชื่อใน warnings โดยมีคำสั่งกู้คืน Git ที่สามารถวางแปะได้เฉพาะเมื่อสเปคนั้นอยู่ใน checkout ของผู้เรียกใช้งาน); การเปลี่ยนแปลงที่ซิงค์แล้วจะจัดเก็บด้วย totals เป็นศูนย์ทั้งหมดและการข้ามรายการที่ระบุใน warnings โหมด JSON เป็นแบบโต้ตอบอย่างเคร่งครัด: จุด prompt ทุกจุดจะกลายเป็นโค้ด archive_*
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 (ปรากฏเฉพาะสำหรับ git-backed store checkout ที่มี upstream tracking ref) คือจำนวน ahead/behind เทียบกับ upstream ที่ดึงล่าสุด ไม่ใช่ remote จริง การค้นพบด้านสุขภาพของความรุนแรงใดๆ ออกด้วยรหัส 0 โหลดความล้มเหลว: { "root": null, "store": null, "references": [], "status": [d] }, ออกด้วยรหัส 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}]} (referenced stores ที่พร้อมใช้งานเท่านั้น, ref: prefixes); ในโหมด JSON การเขียนจะดำเนินการก่อนการพิมพ์ดังนั้น stdout จึงมีเอกสารเดียวเสมอแม้ในการเขียนล้มเหลว ความล้มเหลว: { "root": null, "members": [], "status": [d] }, ออกด้วยรหัส 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). การค้นพบด้านสุขภาพออกด้วยรหัส 0; ความล้มเหลวออกด้วยรหัส 1 ด้วย null-shape ที่สอดคล้องกัน การยกเลิก prompt ออกด้วยรหัส 130
4.13 schemas --json / templates --json
schemas: สำเร็จยังคงเป็นอาร์เรย์เปล่า [ {name, description, artifacts, source} ]; มันแก้ไขลำดับความสำคัญของการเลือก root แบบมาตรฐานและยอมรับ --store <id>. ความล้มเหลวในการเลือก root: { "schemas": [], "root": null, "status": [d] }, ออกด้วยรหัส 1 templates: ออบเจกต์ที่มี key { "<artifactId>": {path, source} }, ยังคงใช้ cwd-based โดยไม่มี root/status keys
5. สัญญา exit-code
| สถานการณ์ | Exit | Stdout |
|---|---|---|
| สำเร็จ รวมถึงผลการตรวจสุขภาพ (doctor/context/store doctor) | 0 | payload |
คำสั่งล้มเหลวในโหมด --json | 1 | เอกสาร JSON เอกเดียวที่มี status: [d] และ null-shape ของคำสั่ง |
validate ที่มีรายการล้มเหลว | 1 | รายงานฉบับเต็ม |
ยกเลิกการป้อนข้อมูล (store group, โหมดมนุษย์) | 130 | stderr เท่านั้น |
6. แคตตาล็อกโค้ดวินิจฉัย
การแก้ไข
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; pass-through: invalid_store_id, invalid_store_registry, invalid_store_metadata.
สุขภาพ OpenSpec-root (error, ไม่มีวิธีแก้ไข)
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. ในช่วง stores beta, openspec/specs/, openspec/changes/, และ openspec/changes/archive/ อาจไม่ปรากฏใน root ที่สุขภาพดี; พวกมันจะเป็น error ด้านสุขภาพเฉพาะเมื่อมีอยู่แต่ไม่ใช่ directory
Registry/identity/state ของ store
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 (info).
Setup/register/remove ของ store
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 (warning ใน remove, error ใน doctor), store_root_not_directory.
Git ของ store
store_git_init_failed, store_git_identity_missing, store_git_commit_failed, store_git_no_commits (warning), store_clone_fragile_directories (warning), store_remote_divergence (info, doctor), store_checkout_drift (info, doctor).
References (warning)
reference_invalid_id, reference_registry_unreadable, reference_unresolved, reference_root_unhealthy, reference_index_truncated.
Relationships (warning; doctor; context เก็บเฉพาะ registry เท่านั้น)
relationship_registry_unreadable, root_pointer_ignored, root_pointer_invalid, pointer_declarations_inert.
Archive (โหมด 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
context_file_exists, context_output_dir_missing.
Fallbacks
doctor_failed, context_failed, store_error, change_error, archive_error.
ความไม่สอดคล้องที่ทราบแล้ว
บันทึกโดย capstone audit; การเปลี่ยนชื่อ published-key เป็น product decisions ที่เลื่อนไปหลังการปล่อยเวอร์ชันนี้:
ในโหมดแก้ไขแล้วในรอบ capstone gauntlet:--json, เส้นทางความล้มเหลวหลายเส้นทางพิมพ์ stderr เท่านั้นโดยไม่มีเอกสาร JSONshow/validateรายการที่ไม่รู้จักและไม่ชัดเจนจะส่ง{status:[{code: unknown_item | ambiguous_item, ...}]}; thrown errors ในstatus/instructions/list/show/validateจะผ่าน JSON-aware failure helper (null-shape ของคำสั่ง +status);store <unknown subcommand> --jsonจะส่ง{status:[{code: unknown_store_subcommand}]};listจะนำ null-shape ของ{changes|specs: [], root: null}ไปใช้เมื่อการแก้ไขล้มเหลวstore_root_missingถูกส่งด้วย severity สองระดับ (warning ใน remove, error ใน store doctor) — ขึ้นอยู่กับบริบท, อธิบายไว้ด้านบน- snake_case (store family) กับ camelCase (workflow family) ในการตั้งชื่อ key;
root.store_idเป็น snake_case ทุกที่ - มีคำประกาศประเภท envelope แบบขนานสี่แบบใน src; archive diagnostics ไม่เคยมี
target list --jsonนำ keystatusกลับมาใช้เป็น string enum ต่อ change- เฉพาะ output ของ
validateที่มีฟิลด์version templatesเพิกเฉยการเลือก root (ใช้ cwd เป็นฐาน, ไม่มี--store)- รูปแบบคำนามที่เลิกใช้แล้ว (
change/specsubcommands) ส่ง payload ที่ไม่มี envelope โดยไม่มีroot/status