Skip to content

عقد وكيل OpenSpec ​

الأسطح القابلة للقراءة آليًا لواجهة openspec السطرية، مُتحقَّق منها مقابل src/ (تدقيق نهائي، 2026-06-11). كل شكل أدناه موثَّق من الكود المُصدر.

1. الاتفاقيات العامة ​

  • مستند JSON واحد لكل استدعاء. في وضع --json، يحمل stdout مستند JSON واحد بالضبط (منسّق بفراغين). النصوص البشرية، ومؤشرات الدوران، وشريط المتجر تُرسل إلى stderr.
  • شريط المتجر. في الوضع البشري، يطبع الجذر المُختار من المتجر 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 صراحةً مُذكورة لكل شكل (store doctor git.*، حمولات الفشل).

2. الغلاف التشخيصي ​

يتشارك شكل غلاف واحد في كل تشخيص قابل للقراءة آلياً (StoreDiagnostic):

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

تظهر التشخيصات في موقعين: مصفوفات الحالة (status: StoreDiagnostic[] على المستوى العلوي أو لكل إدخال) لنتائج الصحة، والأخطاء المقذوفة التي تتحول إلى مصفوفة status ذات عنصر واحد عند فشل الأمر.

3. اختيار الجذر و RootOutput ​

تحل جميع الأوامر التي تحدد الجذر (list, show, validate, status, instructions, instructions apply, instructions archive, new change, archive, doctor, context, schemas) جذر OpenSpec واحد باستخدام أولوية واحدة:

  1. --store <id> → جذر المتجر المسجل (source: "store").
  2. خلاف ذلك، أقرب سلف يحتوي على openspec/: شكل التخطيط → source: "nearest" (يتم تجاهل مؤشر store: مع تحذير stderr)؛ دليل يحتوي فقط على التكوين ومؤشر store: صالح → ذلك المتجر، source: "declared".
  3. لا يوجد جذر قريب + تعيين defaultStore عالمي (openspec config set defaultStore <id>) → ذلك المتجر، source: "global_default"؛ معرف قديم يفشل بخطأ المتجر الأساسي و fix يحدد openspec config unset defaultStore.
  4. لا يوجد جذر قريب، ولا افتراضي + توجد متاجر مسجلة → خطأ no_root_with_registered_stores.
  5. لا يوجد جذر، ولا افتراضي، ولا متاجر: قد تعامل الأوامر الدليل الحالي (cwd) بأنه source: "implicit"؛ بدلاً من ذلك تفشل doctor، context، list، والتحقق الشامل validate بالخطأ no_openspec_root. تحتفظ list بالسقوط الاحتياطي الضمني للمشاريع القديمة التي تحتوي على openspec/project.md.

عادةً ما تضمّن حمولات JSON الناجحة الجذر؛ يبقى schemas --json الناجح عمداً كمصفوفة عارية متوافقة موثقة في §4.13:

json
"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 الأول هو العنصر الذي يجب كتابته التالي؛ يستخدم missingDeps نفس الترتيب. يحدد "skipped" عنصراً يكون مسار generates الخاص به ضمن specs/ في تغيير يعلن .openspec.yaml الخاص به عن skip_specs: true؛ فهو يشبع التبعيات ولكن لا ينبغي إنشاء ملفاته. لا توجد تغييرات نشطة: { "changes": [], "message", "root" }، يخرج بـ 0.

--all (دفعة، متنافية مع --change — الجمع بينهما خطأ مع الشكل الخالي { "changes": [], "root": null, "status": [d] }): { "changes": [ <كائن حالة لكل تغيير، بدون جذر لكل تغيير>, ... ], "root" }، مرتبة حسب اسم التغيير. يساهم التغيير الذي يفشل في التحميل بـ { "changeName", "status": [d] } مكانه؛ يستمر المسح، يحافظ على الغلاف الكامل، ويخرج بـ 1 في كل من الوضع النصي وJSON. يفشل --schema غير الصالح الاستدعاء بالكامل بالشكل الخالي، حتى عندما لا توجد تغييرات.

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": [] } — تحملEntries المحلولة الجذر/المواصفات/الجلب؛ تحمل Entries غير المحلولة store_id + حالة تحذير. المؤشر مقيد بـ 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.requires في المخطط)؛ missingPrerequisites هو كل ما لا يزال لبنائه قبل أن يعمل التطبيق، بترتيب البناء - الإغلاق الانتقالي لتلك الـ requires، لذا يمكن أن تكون القائمة الأطول. warnings تذكر المشاكل غير المعيقة الخاصة بالتغيير نفسه - اليوم، تغيير جاهز للتنفيذ بدون مواصفات delta وبدون skip_specs: true، ترفضه حالة openspec validate. كلا الحقلين الاختياريين للجذر (context، operationGuidance) يُقرأان من الجذر المحدد في كل استدعاء. context هو إدخال مطلوب على مستوى المطالبة يجب تطبيق حقائق المشروع ذات الصلة، والاتفاقيات، والقيود عليه؛ operationGuidance هو إدخال استشاري يتم اتباع إدخالاته فقط عندما تكون قابلة للتطبيق ومتوافقة مع سير العمل المدمج. تبقى منفصلة عن الحالة، والمهام، والتقدم، وملفات السياق، والتعليمات المدمجة.

4.7 instructions archive --json ​

{ "changeName", "context"?, "operationGuidance"?, "root" }. يتطلب --change صالحاً في جذر المستودع/المتجر المحلول ويستخدم نفس دلالات السياق المطلوب/الإرشاد الاستشاري كما في التطبيق. هذا سطح إدخال وقت تشغيل للقراءة فقط: لا يعيد سير عمل الأرشيف الثابت، أو يفحص أو يدمج مواصفات delta، أو يكتب المواصفات الرئيسية، أو ينقل التغيير.

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 صحيحة فقط عندما تمت كتابة أو تقاعد ملف مواصفة واحد على الأقل (يتم حذف مواصفة القدرة التي أزال متطلباتها الأخيرة التغيير، وهو ما يتطلب retire_capabilities: true في .openspec.yaml الخاص بالتغيير؛ يتم تسمية كل تقاعد في warnings، مع أمر استرداد Git قابلاً للصق فقط عندما عاشت المواصفة في فحص المتصل)؛ يؤرشف التغيير المتزامن بالفعل بإجماليات صفرية والسجلات المدرجة في warnings. وضع JSON غير تفاعلي تماماً: يصبح كل نقطة مطالبة رمز 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 لديه مرجع تتبع علوي) هو عددها أمام/خلف مقابل آخر جلب علوي، وليس الخلفية الحية. نتائج الصحة بأي شدة تخرج بـ 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": [] }. متاح = المسار موجود وحالة فارغة. --code-workspace <path> يكتب {folders:[{name,path}]} (فقط المتاجر المرجعية المتاحة، بادئات ref:)؛ في وضع JSON، يعمل الكتابة قبل الطباعة بحيث يحمل stdout مستنداً واحداً بالضبط حتى على فشل الكتابة. فشل: { "root": null, "members": [], "status": [d] }، يخرج بـ 1.

4.12 store ... --json ​

إعداد/تسجيل: { "store": {id, root, metadata_path?}, "registry": {path, registered, already_registered}, "git": {is_repository, initialized, committed}, "created_files": [], "status": [] }. إلغاء تسجيل/إزالة: { "store", "registry": {path, removed}, "files": {deleted, deleted_path, left_on_disk}, "status": [] }. قائمة: { "stores": [{id, root}], "status": [] }. طبيب: { "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 = مجهول/لم يتم فحصه). تخرج نتائج الصحة بـ 0؛ تخرج الفشل بـ 1 مع الشكل الخالي المطابق. خروج المطالبة بـ 130.

4.13 schemas --json / templates --json ​

schemas: يبقى النجاح كمصفوفة عارية [ {name, description, artifacts, source} ]؛ يحلل أولوية اختيار الجذر القياسية ويقبل --store <id>. فشل اختيار الجذر: { "schemas": [], "root": null, "status": [d] }، يخرج بـ 1. templates: كائن مفتاحي { "<artifactId>": {path, source} }، لا يزال قائماً على cwd بدون مفاتيح جذر/حالة.

5. عقد رمز الخروج ​

الحالةرمز الخروجالإخراج القياسي
نجاح، بما في ذلك نتائج الفحص (doctor/context/store doctor)0الحمولة
فشل الأمر في وضع --json1مستند JSON واحد يحتوي على status: [d] وشكل القيمة الفارغة للأمر
validate مع عناصر فاشلة1التقرير الكامل
إلغاء المُوجِّه (store group، الوضع البشري)130الإخراج القياسي للخطأ فقط

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؛ المرور المباشر: 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. خلال فترة تجريب المتاجر (stores beta)، قد تغيب 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 (تحذير في الإزالة، خطأ في doctor)، store_root_not_directory.

Git للمتاجر ​

store_git_init_failed، store_git_identity_missing، store_git_commit_failed، store_git_no_commits (تحذير)، store_clone_fragile_directories (تحذير)، store_remote_divergence (معلومة، doctor)، store_checkout_drift (معلومة، doctor).

المراجع (تحذير) ​

reference_invalid_id، reference_registry_unreadable، reference_unresolved، reference_root_unhealthy، reference_index_truncated.

العلاقات (تحذير؛ doctor؛ context يحتفظ بسجل العلاقات فقط) ​

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 ​

context_file_exists، context_output_dir_missing.

البدائل الاحتياطية ​

doctor_failed، context_failed، store_error، change_error، archive_error.

عدم اتساقات معروفة ​

سُجّلت من خلال تدقيق المشروع الختامي؛ إعادة تسمية المفاتيح المنشورة هي قرارات منتج مؤجّلة لما بعد هذا الإصدار:

  1. في وضع --json، كانت مسارات فشل متعددة تُطبع الإخراج القياسي للخطأ فقط دون مستند JSON. تم إصلاحه في جولة الاختبار الشاملة للمشروع الختامي: العناصر المجهولة وغير الواضحة في show/validate تُصدر {status:[{code: unknown_item | ambiguous_item, ...}]}؛ الأخطاء المستثناة في status/instructions/list/show/validate تمر عبر مساعد الفشل الواعي بـ JSON (شكل القيمة الفارغة للأمر + status)؛ store <unknown subcommand> --json يُصدر {status:[{code: unknown_store_subcommand}]}؛ list يحمل شكل القيمة الفارغة {changes|specs: [], root: null} عند فشل الحل.
  2. store_root_missing يُصدر بمستويين من الخطورة (تحذير في الإزالة، خطأ في store doctor) — يعتمد على السياق، موثّق أعلاه.
  3. تباين تسمية المفاتيح بين snake_case (عائلة المتاجر) وcamelCase (عائلة سير العمل)؛ root.store_id هو snake_case في كل مكان.
  4. توجد أربع إعلانات موازٍ لنوع الغلاف (envelope) في src؛ تشخيصات الأرشيف لا تحمل أبدًا target.
  5. list --json يعيد استخدام مفتاح status كـ enum نصي لكل تغيير.
  6. فقط مخرجات validate تحمل حقل version.
  7. templates يتجاهل اختيار الجذر (يعتمد على cwd، لا --store).
  8. الأشكال الإسمية المهجورة (أوامر change/spec الفرعية) تُصدر حمولات غير مغلفة دون root/status.