Skip to content

Hợp đồng Agent của OpenSpec ​

Các bề mặt có thể đọc được bởi máy của CLI openspec, được xác minh đối chiếu với src/ (kiểm toán tổng kết, 2026-06-11). Mọi cấu trúc bên dưới đều được tài liệu hóa từ mã phát sinh.

1. Các quy ước chung ​

  • Một tài liệu JSON cho mỗi lần gọi. Ở chế độ --json, stdout chứa đúng một tài liệu JSON (định dạng đẹp với 2 khoảng trắng). Văn bản cho người dùng, bộ chỉ báo tiến trình và banner cửa hàng được ghi ra stderr.
  • Banner cửa hàng. Ở chế độ người dùng, root được chọn bởi cửa hàng sẽ in Using OpenSpec root: <id> (<path>) ra stderr. Không bao giờ in ở chế độ JSON.
  • Việc viết hoa chữ cái của khóa phụ thuộc vào bề mặt (xem Bất nhất quán đã biết): các payload store/doctor/context sử dụng snake_case; các payload workflow (status, instructions, new change, validate, list) sử dụng camelCase, ngoại trừ đối tượng root nhúng, luôn sử dụng store_id.
  • Các khóa tùy chọn bị bỏ qua, không đặt là null, trong hầu hết các payload (ví dụ: root.store_id, member.path). Các ngoại lệ sử dụng null tường minh được chỉ ra theo từng cấu trúc (store doctor git.*, các payload lỗi).

2. Lớp vỏ chẩn đoán ​

Tất cả các chẩn đoán máy đọc được (StoreDiagnostic) đều dùng chung một hình dạng lớp vỏ:

json
{
  "severity": "error" | "warning" | "info",
  "code": "snake_case_string",
  "message": "human sentence",
  "target": "dotted.surface (optional)",
  "fix": "one actionable sentence/command (optional)"
}

Chẩn đoán xuất hiện ở hai vị trí: mảng trạng thái (status: StoreDiagnostic[] ở cấp cao nhất hoặc trên mỗi mục) dành cho kết quả kiểm tra sức khỏe, và lỗi được ném ra được chuyển thành mảng status một phần tử khi lệnh thất bại.

3. Chọn thư mục gốc và RootOutput ​

Tất cả các lệnh phân giải thư mục gốc (list, show, validate, status, instructions, instructions apply, instructions archive, new change, archive, doctor, context, schemas) đều phân giải một thư mục gốc OpenSpec với thứ tự ưu tiên:

  1. --store <id> → thư mục gốc của store đã đăng ký (source: "store").
  2. Ngược lại, thư mục tiền nhiệm gần nhất có openspec/: hình dạng planning → source: "nearest" (con trỏ store: bị bỏ qua kèm cảnh báo stderr); thư mục chỉ chứa cấu hình có con trỏ store: hợp lệ → store đó, source: "declared".
  3. Không có thư mục gốc gần nhất + cài đặt defaultStore toàn cục (openspec config set defaultStore <id>) → store đó, source: "global_default"; id lỗi thời sẽ thất bại với lỗi store nền và fix đề cập openspec config unset defaultStore.
  4. Không có thư mục gốc gần nhất, không có mặc định + có store đã đăng ký → lỗi no_root_with_registered_stores.
  5. Không có thư mục gốc, không có mặc định, không có store: các lệnh có thể coi cwd là source: "implicit"; riêng doctor, context, list, và validate khối sẽ thất bại với no_openspec_root. list giữ lại phương án dự phòng ẩn dành cho các dự án cũ có openspec/project.md.

Payload JSON thành công thường nhúng thư mục gốc; riêng schemas --json thành công cố ý giữ nguyên mảng tương thích trần được ghi nhận ở §4.13:

json
"root": { "path": "/abs/path", "source": "store" | "declared" | "global_default" | "nearest" | "implicit", "store_id": "id (chỉ khi được chọn qua store)" }

Hợp đồng khi thất bại phân giải thư mục gốc: ở chế độ JSON, lỗi phân giải in ra { ...commandNullShape, "status": [diagnostic] } lên stdout và thoát với mã 1.

4. Hình dạng JSON của các lệnh ​

4.1 list --json ​

{ "changes": [ { "name", "completedTasks", "totalTasks", "lastModified", "status": "no-tasks"|"complete"|"in-progress" } ], "root": RootOutput } — lưu ý status của mỗi thay đổi ở đây là một enum chuỗi. --specs: { "specs": [ { "id", "requirementCount" } ], "root" }.

4.2 show <item> --json ​

Thay đổi: { "id", "title", "deltaCount", "deltas": [...], "root" }. Đặc tả: { "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" }. Thoát 1 nếu bất kỳ mục nào thất bại.

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 nghĩa là mọi artifact planning không bị bỏ qua đều tồn tại; artifact bị bỏ qua tính là đã thỏa mãn mà không cần tạo. Điều này không có nghĩa là các tác vụ triển khai đã hoàn thành. isComplete được giữ lại như một bí danh tương thích với cùng giá trị. requires của mỗi artifact là các id phụ thuộc trực tiếp (xuất hiện ở mọi trạng thái, do đó tập phụ thuộc bắc cầu vẫn tính được ngay cả khi artifact đã done); missingDeps chỉ xuất hiện khi blocked. Mảng artifacts được sắp xếp theo thứ tự phụ thuộc, với thứ tự khai báo artifacts: trong schema dùng để giải quyết đồng hạng giữa các artifact sẵn sàng cùng lúc (không bao giờ theo bảng chữ cái), vì vậy mục ready đầu tiên là artifact cần viết tiếp theo; missingDeps dùng chính thứ tự đó. "skipped" đánh dấu artifact có đường dẫn generates nằm dưới specs/ trong thay đổi mà .openspec.yaml khai báo skip_specs: true; nó thỏa mãn phụ thuộc nhưng không được tạo. Không có thay đổi nào hoạt động: { "changes": [], "message", "root" }, thoát 0.

--all (chạy hàng loạt, loại trừ lẫn nhau với --change — kết hợp chúng là lỗi với dạng null { "changes": [], "root": null, "status": [d] }): { "changes": [ <đối tượng trạng thái cho mỗi thay đổi, không có root riêng>, ... ], "root" }, sắp xếp theo tên thay đổi. Một thay đổi không tải được sẽ đóng góp { "changeName", "status": [d] } thay cho vị trí đó; vòng quét tiếp tục, bảo toàn lớp vỏ hoàn chỉnh, và thoát 1 ở cả chế độ văn bản và JSON. Một --schema không hợp lệ khiến toàn bộ lệnh gọi thất bại với dạng null, ngay cả khi không có thay đổi nào.

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 liệt kê các artifact mà artifact này khiến sẵn sàng, theo thứ tự khai báo của schema (cùng thứ tự mà status khuyến nghị). "skipped": true (kèm "warning") xuất hiện khi thay đổi khai báo skip_specs: true và artifact này bị bỏ qua — không tạo các tệp của nó. Một mục phụ thuộc có skipped: true được coi là thỏa mãn mà không cần tệp — không cố gắng đọc đường dẫn của nó.

ReferenceIndexEntry: { "store_id", "root"?, "specs"?: [{id,summary}], "fetch"?, "status": [] } — các mục đã phân giải mang theo root/specs/fetch; các mục chưa phân giải mang store_id + trạng thái cảnh báo. Chỉ mục bị giới hạn 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 là thứ mà apply đang chặn (yêu cầu apply.requires của schema); missingPrerequisites là mọi thứ vẫn cần xây dựng trước khi apply chạy được, theo thứ tự xây dựng — bao đóng bắc cầu của những yêu cầu đó, vì vậy có thể là danh sách dài hơn. warnings liệt kê các vấn đề không gây chặn của chính thay đổi — hiện tại, một thay đổi sẵn sàng triển khai nhưng không có delta spec và không có skip_specs: true, trạng thái mà openspec validate từ chối. Cả hai trường root tùy chọn (context, operationGuidance) được đọc từ thư mục gốc đã chọn trong mỗi lần gọi. context là một đầu vào cấp prompt bắt buộc, chứa các dữ kiện, quy ước và ràng buộc liên quan của dự án phải được áp dụng; operationGuidance là đầu vào tư vấn, các mục của nó chỉ được tuân theo khi phù hợp và tương thích với quy trình tích hợp sẵn. Cả hai đều tách biệt với state, tasks, progress, context files và hướng dẫn tích hợp.

4.7 instructions archive --json ​

{ "changeName", "context"?, "operationGuidance"?, "root" }. Yêu cầu một --change hợp lệ trong thư mục gốc repo/store đã phân giải và sử dụng cùng ngữ nghĩa ngữ cảnh bắt buộc / hướng dẫn tư vấn như apply. Đây là một bề mặt đầu vào thời gian chạy chỉ-đọc: nó không trả về quy trình lưu trữ tĩnh, không kiểm tra hoặc hợp nhất delta spec, không ghi main spec, và không di chuyển thay đổi.

4.8 new change <name> --json ​

Thành công: { "change": { "id", "path", "metadataPath", "schema" }, "root" }. Thất bại: { "change": null, "status": [d] }, thoát 1.

4.9 archive <name> --json ​

Thành công: { "archive": { "change", "archivedAs": "YYYY-MM-DD-name", "path", "specsUpdated", "totals"?, "warnings"? }, "root" }. Thất bại: { "archive": null, "root"?, "status": [d] }, thoát 1. specsUpdated chỉ đúng khi ít nhất một tệp spec được ghi hoặc đã loại bỏ (một năng lực mà yêu cầu cuối cùng bị thay đổi xóa sẽ xóa spec của nó, yêu cầu retire_capabilities: true trong .openspec.yaml của thay đổi; mỗi lần loại bỏ đều được nêu trong warnings, kèm lệnh khôi phục Git có thể dán được chỉ khi spec sống trong bản checkout của người gọi); một thay đổi đã đồng bộ sẽ được lưu trữ với tổng toàn không và các lần bỏ qua được liệt kê trong warnings. Chế độ JSON hoàn toàn không tương tác: mọi điểm prompt trở thành mã 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 (chỉ có ở bản checkout store được git hỗ trợ có tham chiếu theo dõi upstream) là số lượng ahead/behind so với upstream đã fetch lần cuối, không phải so với remote trực tiếp. Các phát hiện sức khỏe ở bất kỳ mức độ nghiêm trọng nào đều thoát 0. Payload thất bại: { "root": null, "store": null, "references": [], "status": [d] }, thoát 1.

4.11 context --json ​

{ "root": { "path", "source", "store_id"?, "role": "openspec_root" }, "members": [ { "role": "referenced_store", "id", "path"?, "remote"?, "fetch"?, "status": [] } ], "status": [] }. KHẢ DỤNG = đường dẫn tồn tại VÀ trạng thái rỗng. --code-workspace <path> ghi {folders:[{name,path}]} (chỉ các store được tham chiếu khả dụng, tiền tố ref:); ở chế độ JSON, việc ghi chạy trước khi in ra nên stdout chứa đúng một tài liệu ngay cả khi ghi thất bại. Thất bại: { "root": null, "members": [], "status": [d] }, thoát 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 = không xác định / chưa thăm dò). Phát hiện sức khỏe thoát 0; lỗi thoát 1 với dạng null tương ứng. Hủy bỏ prompt thoát 130.

4.13 schemas --json / templates --json ​

schemas: thành công vẫn là một mảng trần [ {name, description, artifacts, source} ]; nó phân giải thứ tự ưu tiên chọn thư mục gốc chính tắc và chấp nhận --store <id>. Thất bại phân giải thư mục gốc: { "schemas": [], "root": null, "status": [d] }, thoát 1. templates: đối tượng có khóa { "<artifactId>": {path, source} }, vẫn dựa trên cwd, không có khóa root/status.

5. Hợp đồng mã thoát ​

Tình huốngMã thoátStdout
Thành công, bao gồm phát hiện sức khỏe (doctor/context/store doctor)0payload
Lỗi lệnh trong chế độ --json1một tài liệu JSON với status: [d] và null-shape của lệnh
validate có các mục thất bại1báo cáo đầy đủ
Hủy prompt (nhóm store, chế độ người dùng)130chỉ stderr

6. Danh mục mã chẩn đoán ​

Phân giải ​

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.

Sức khỏe OpenSpec-root (lỗi, không có cách sửa) ​

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. Trong giai đoạn beta của stores, openspec/specs/, openspec/changes/, và openspec/changes/archive/ có thể vắng mặt trong một root khỏe mạnh; chúng chỉ là lỗi sức khỏe khi có mặt nhưng không phải là thư mục.

Registry/identity/trạng thái của 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).

Thiết lập/đăng ký/xóa 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 (cảnh báo trong remove, lỗi trong doctor), store_root_not_directory.

Store git ​

store_git_init_failed, store_git_identity_missing, store_git_commit_failed, store_git_no_commits (cảnh báo), store_clone_fragile_directories (cảnh báo), store_remote_divergence (info, doctor), store_checkout_drift (info, doctor).

Tham chiếu (cảnh báo) ​

reference_invalid_id, reference_registry_unreadable, reference_unresolved, reference_root_unhealthy, reference_index_truncated.

Mối quan hệ (cảnh báo; doctor; context chỉ giữ lại registry) ​

relationship_registry_unreadable, root_pointer_ignored, root_pointer_invalid, pointer_declarations_inert.

Archive (chế độ 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.

Ghi context ​

context_file_exists, context_output_dir_missing.

Fallback ​

doctor_failed, context_failed, store_error, change_error, archive_error.

Các bất nhất đã biết ​

Được ghi nhận bởi cuộc kiểm toán capstone; việc đổi tên published-key là các quyết định sản phẩm bị hoãn sau bản phát hành này:

  1. Trong chế độ --json, một số đường dẫn lỗi chỉ in stderr mà không có tài liệu JSON. Đã sửa trong vòng gauntlet của capstone: các mục không xác định và mơ hồ của show/validate phát ra {status:[{code: unknown_item | ambiguous_item, ...}]}; các lỗi ném ra trong status/instructions/list/show/validate đi qua helper lỗi nhận thức JSON (null-shape của lệnh + status); store <unknown subcommand> --json phát ra {status:[{code: unknown_store_subcommand}]}; list mang null-shape {changes|specs: [], root: null} của nó trong các lỗi phân giải.
  2. store_root_missing được phát ra với hai mức độ nghiêm trọng (cảnh báo trong remove, lỗi trong store doctor) — phụ thuộc ngữ cảnh, đã được tài liệu hóa ở trên.
  3. snake_case (nhóm store) so với camelCase (nhóm workflow) về kiểu viết key; root.store_id là snake_case ở mọi nơi.
  4. Bốn khai báo kiểu envelope song song tồn tại trong src; chẩn đoán archive không bao giờ mang target.
  5. list --json tái sử dụng key status như một enum chuỗi cho từng change.
  6. Chỉ đầu ra của validate mang trường version.
  7. templates bỏ qua việc chọn root (dựa trên cwd, không có --store).
  8. Các dạng danh từ đã ngừng hỗ trợ (lệnh con change/spec) phát ra payload không bọc envelope mà không có root/status.