تجريد محول إطار العمل
بروتوكول HarnessAdapter — كيف تترجم محولات Apothem الملف التعريفي المشترك.
يستخدم Apothem ملف تعريف YAML واحدًا مُتحقَّقًا منه عبر
المخطّط بوصفه المصدر الدلالي للحقيقة، ويشتقّ كل سطح تثبيت خاصّ بإطار العمل من خلال
أصناف محوِّلة تُنفِّذ بروتوكول HarnessAdapter. يكتب كل محوِّل إلى
موقع المستخدم أو المشروع الموثَّق لدى إطار العمل، ولا يستخدم مسارات الدعم المملوكة
لـ Apothem إلّا حين لا يملك إطار العمل بدائيّة أصليّة مطابِقة.
لماذا تجريد المحوِّل
يتحدّث كل إطار عمل بلهجة تهيئة مختلفة: واحد يريد ملفّ إعدادات JSON،
وآخر دليلًا من ملفّات قواعد .mdc، وثالث ملفّ تعليمات Markdown
واحدًا. لو رمّز Apothem تلك المعرفة بقيمة ثابتة داخل CLI،
لتسرّب كل إطار عمل افتراضاته إلى النواة، ولأصبحت إضافة إطار عمل تعني لمس منطق
التثبيت والتحديث وإلغاء التثبيت والتحقّق في تناغم واحد.
يعكس نمط المحوِّل ذلك. لا تعرف النواة سوى بروتوكول HarnessAdapter — عقدٍ صغير من توابع دورة الحياة. تعيش لهجة كل إطار عمل داخل حزمة فرعية واحدة مكتفية بذاتها تُنفِّذ العقد. تطلب النواة من محوِّل أن يُثبِّت دون أن تعرف ما إذا كان ذلك يعني إخراج ملفّ JSON، أم كتابة دليل قواعد، أم بسط شجرة دعم. تنضمّ أطر العمل الجديدة بتلبية البروتوكول، وبإضافة مدخل HARNESS_REGISTRY في src/apothem/lib/harness_registry_data.py (مع رفع SUPPORTED_HARNESS_COUNT هناك)، ومرآته في نقاط دخول apothem.harnesses في pyproject.toml، وإضافة المعرّف إلى تعداد harnessId في src/apothem/schemas/profile.schema.json. وهذا هو السبب البنيوي وراء بقاء Apothem محايدًا للمضيف — فالتجريد هو الحدّ الذي يمنع انتشار المعرفة الخاصة بإطار العمل.
شكل المحوِّل
تنقسم المحوِّلات إلى شكلين من أشكال التجسيد، وكلاهما ظاهر في السجلّ:
- عارِضات الملفّ الواحد تترجم حقول الملف التعريفي إلى ملفّ تهيئة واحد أصليّ لإطار العمل. مثال ذلك محوِّل OpenCode الذي يُجسِّد ملف تهيئته الأصلي من الملف التعريفي المشترك عبر مُجسِّد.
- محوِّلات سطح القواعد وشجرة الدعم تنشر حزمة حمولة Apothem إلى موقع القواعد الموثَّق لدى إطار العمل، فتحوّل الحزمةَ إلى الصيغة الأصلية حيث توجد واحدة، وتُركِن البقيّة تحت شجرة دعم فرعية يملكها Apothem ومُشار إليها من المرساة الأصلية. يكتب محوِّل Cursor ملفًّا واحدًا
.cursor/rules/apothem-rules.mdcفي جذر المشروع المُزوَّد. وقبل ذلك الملف يكتب مجلّدين مشتركين في الدليل المنزلي للمستخدم: تذهب المهارات، والأوامر المُغلَّفة بوصفها مهارات، إلى~/.agents/skills/، وتذهب القواعد والقوالب التي تستشهد بها تلك المهارات إلى~/.config/apothem/. ولا يُجسِّد محوِّل Claude Code ملفsettings.jsonمن الملف التعريفي؛ بل ينسخ قالب الإعدادات المُضمَّن إلى~/.claude/settings.jsonمع تعبئة مُفسِّر الخطّافات، ويسطّح أدلّة اصطلاحات Apothem (agents/وrules/وskills/…) بجانبه، ويكتب الملف التعريفي في كتلة مُدارة محدودة بعلامات حارسة داخلCLAUDE.md.
أي محوِّل بعينه إمّا أن يكون بنطاق المستخدم (يكتب تحت الدليل المنزلي) أو
بنطاق المشروع (يتطلّب --project <path> ويكتب ملف مشروعه داخل تلك
الشجرة)؛ ويُسجِّل السجلّ أيّهما. وتكتب سبعة محوِّلات بنطاق المشروع (cursor
وgithub-copilot وwindsurf وzed وcodebuddy وkiro وtrae) أيضًا مجلّدات مشتركة في الدليل
المنزلي للمستخدم، مثل ~/.agents/skills/ و~/.config/apothem/،
ولا يُغيّر --project مكان كتابتها.
طوبولوجيا المحوِّلات الحاليّة
%% provenance: hand-authored %%
%% verified: 2026-10-25 %%
%% cross-reference: src/apothem/harnesses/ (adapter sub-packages) %%
flowchart TD
accTitle: Apothem adapter topology
accDescr: The single shared profile at the center feeds the adapter layer, which fans out to one adapter per supported harness; each adapter writes to a user-scope or project-scope native surface, rendering a single config file or propagating a rules and support-tree cohort.
P["Shared profile (YAML)<br/>~/.config/apothem/profile.yaml<br/>+ packaged payload cohorts"]
P --> AL["Adapter layer<br/>HarnessAdapter protocol<br/>(17 registered adapters)"]
AL --> CC["claude-code adapter<br/>(user scope)"]
AL --> CX["codex adapter<br/>(user scope)"]
AL --> CU["cursor adapter<br/>(project scope)"]
AL --> CO["github-copilot adapter<br/>(project scope)"]
AL --> WS["windsurf adapter<br/>(project scope)"]
AL --> ETC["… 12 more registered adapters<br/>(antigravity, gemini-cli, glm, hermes,<br/>kimi-code, open-claw, opencode, qwen-code,<br/>codebuddy, kiro, trae, zed)"]
CC --> CCN["~/.claude/settings.json<br/>+ flattened convention dirs<br/>(template copy)"]
CX --> CXN["~/.codex/AGENTS.md + hooks.json<br/>+ converted TOML agents<br/>(render + support tree)"]
CU --> CUN["<project>/.cursor/rules/apothem-rules.mdc<br/>+ ~/.agents/skills/ and ~/.config/apothem/<br/>(project rules file + user-home folders)"]
CO --> CON["<project>/.github/copilot-instructions.md<br/>+ ~/.agents/skills/ and ~/.config/apothem/<br/>(project rules file + user-home folders)"]
WS --> WSN["<project>/.devin/rules/apothem-rules.md<br/>+ ~/.agents/skills/ and ~/.config/apothem/<br/>(project rules file + user-home folders)"]
ETC --> ETCN["each harness's documented<br/>native surface or Apothem-owned<br/>support subtree"]التوزيع المروحيّ من المركز إلى الحافّة هو البنية التي يُرمِّزها اسم المشروع: ملف تعريف واحد في القلب، وكل إطار عمل على مسافة متساوية على امتداد محوِّله الخاصّ.
تعريف البروتوكول
from pathlib import Path
from typing import Protocol
class HarnessAdapter(Protocol):
name: str
output_path: Path
def install(self, profile: dict[str, object]) -> object:
...
def update(self, profile: dict[str, object]) -> object:
...
def uninstall(self) -> None:
...
def is_installed(self) -> bool:
...
def verify(self) -> bool:
...يجوز لمحوِّلات نطاق-المشروع أن تقبل إضافةً project: Path | None على
توابع دورة-الحياة وأن تكشف resolve_output_path(project). لا تمرّر
CLI الوسيط --project PATH إلّا للمحوِّلات التي يقبله توقيع
توابعها.
تسجيل نقطة الدخول
تُسجَّل المحوِّلات عبر مجموعة نقاط دخول setuptools الموسومة
apothem.harnesses:
[project.entry-points."apothem.harnesses"]
cursor = "apothem.harnesses.cursor:CursorAdapter"يُسجِّل السجلّ المركزي في src/apothem/lib/harness_registry.py المعرّفات
العامّة السبعة عشر بالضبط، ونقاط الدخول، ومسارات المستندات، ومسارات الهدف،
ومتطلّبات بيانات-الحزمة، وحالات القدرة، ومسارات تثبيت الاصطلاح المعياري. تُحمِّل
CLI المحوِّلات عبر ذلك السجلّ بدلًا من إعادة اكتشاف حقائق المنتج في كل
أمر.
التعيين من ملف التعريف إلى الأصليّ
يُنفِّذ كل محوِّل منطق الترجمة الملائم لإطار عمله:
YAML profile + payload cohort Harness-native surface
----------------------------- ----------------------
identity / preferences --> native config fields or rendered instruction context
commands/*.md --> native commands or SKILL.md folders
rules/*.md --> native rules where supported, otherwise support trees
hooks/messages/*.md --> native hooks where supported, otherwise support trees
agents/*.md --> native agent formats where supported
skills/*/SKILL.md --> native skill folders where supportedتصير خلايا القدرة غير المدعومة والمنتظِرة للاكتشاف تحذيرات مُهيكَلة قبل عمليّات الكتابة. ولا تُسقَط صامتةً على أسطح مورِّدين مُختلَقة.
إضافة محوِّل جديد
انظر كتابة محوِّل إطار عمل للحصول على دليل خطوة بخطوة.