SSD Nodes Learn 🎉 VPS من $4.99/شهر
الأدلة Matt Connorبقلم Matt Connor

استضافة OpenTag ذاتيًا لذكر @agent

شغّل OpenTag على VPS لتصل إشارات Slack وGitHub إلى وكيل البرمجة، مع شرح TLS، والتحقق من توقيع webhook، ونطاقات الرموز والإعدادات الآمنة.

ما يفعله OpenTag عند ذكر وكيل

يحوّل OpenTag إشارة @mention في سلسلة محادثة على Slack أو في issue على GitHub إلى تشغيل وكيل برمجة على جهاز تملكه. يعلّق أحدهم @opentag investigate this على issue. يستقبل مستمع الحدث القادم من المنصة، ويتحقق من توقيعه، ويربط الإشارة بالمشروع المقرون بها، ثم يشغّل وكيل برمجة على نسخة checkout محلية، وينشر النتيجة في سلسلة المحادثة نفسها.

المشروع مرخّص بموجب MIT وموجود في amplifthq/opentag. اعتباراً من August 2026، أحدث إصدار موسوم هو v0.9.0، وقد نُشر في 28 July 2026، ويُوزّع على شكل حزمة npm. لا توجد صورة حاوية رسمية، لذلك فإن العنصر الذي تثبّته هو إصدار npm. كل أمر أدناه يثبّت الإصدار.

يصبح هذا مشروع VPS بدلاً من مشروع على جهاز محمول بسبب جانب GitHub. يرسل GitHub أحداث المستودع عبر إجراء طلب HTTP إلى عنوان URL تسجّله مرة واحدة، لذلك يجب أن يستجيب عنوان URL نفسه من العنوان نفسه غداً.

الأجزاء الأربعة المتحركة

المستقبِل يتلقى أحداث المنصة، ولكل منصة مستقبِل خاص بها. مستقبِل GitHub هو نقطة نهاية HTTP على المنفذ 3050 والمسار /github/webhooks. أما مستقبِل Slack Events API فيعمل على المنفذ 3040 عند /slack/events. ويمكن لـSlack أيضاً العمل في Socket Mode، حيث يفتح التطبيق اتصال WebSocket صادراً ولا يحتاج إلى أي منفذ وارد.

الموزّع هو المنسّق. يستمع افتراضياً على المنفذ 3030، ويحفظ حالة التشغيل في ملف قاعدة بيانات محلي يحدده OPENTAG_DATABASE_PATH، ويسجل مسار تدقيق لكل تشغيل. يجب ألا يصل أي شيء خارج الخادم إلى هذا المنفذ.

المشغّل هو البرنامج الخفي المحلي. يستطلع الأعمال المتاحة، ويحجز تشغيلًا، ويحتفظ بتأجير له، ويرسل إشارة نبض كل 15 ثانية افتراضياً ما دام التشغيل نشطاً. ويرفض أي تشغيل محجوز إذا كان هدف المشروع مفقوداً أو خارج قائمة السماح في إعداداته الخاصة. هذا الفحص هو ما يمنع حدث GitHub من توجيه وكيلك إلى مستودع لم تربطه مسبقاً.

المنفّذ هو وكيل البرمجة نفسه. يشغّله OpenTag عبر ACP (بروتوكول عميل الوكيل)، وهو بروتوكول JSON-RPC يتواصل عبر الإدخال والإخراج القياسيين. لذلك يعمل الوكيل كعملية فرعية داخل دليل عمل يمرره إليه OpenTag. تتضمن الأسماء المضمّنة echo وcodex وclaude-code وcursor وopencode وhermes وopenclaw. ابدأ باستخدام echo، وهو المنفّذ المضمّن في إعداد المثال، لأنه يثبت عمل المسار كاملاً قبل أن يغيّر النموذج شيفرتك.

لا يتغير الترتيب أبداً: حدث المنصة، والتحقق من التوقيع، وسجل التشغيل، والحجز، والوكيل، ثم الرد في سلسلة المحادثة.

لماذا لا يكفي الحاسوب المحمول والنفق

يطلب منك دليل إعداد GitHub تشغيل ngrok http 3050 ولصق مضيف النفق في webhook المستودع. ينجح ذلك خلال الدقائق العشر الأولى. يتغير مضيف النفق المجاني في كل مرة تُعاد فيها العملية، ويتوقف عن الوجود عندما يدخل الحاسوب المحمول في وضع السكون. يحتفظ GitHub بعنوان URL القديم للحمولة ويواصل محاولة استخدامه، لذلك تمتلئ علامة تبويب Recent Deliveries في إعدادات webhook بحالات الفشل بينما تظل سلسلة المناقشة صامتة. لا يلاحظ أحد ذلك لمدة أسبوع، لأن webhook الذي لا يفعل شيئاً يبدو تماماً كأنه bot لم يذكره أحد.

يعالج VPS المشكلتين اللتين تسببان الفشل. لا يتغير اسم DNS، لذلك يظل عنوان URL للحمولة الذي تلصقه مرة واحدة صحيحاً. لا يدخل الجهاز في وضع السكون، لذلك يحصل التعليق المنشور عند الساعة 02:00 على إجابة. أعد إعداد الجهاز بشكل صحيح أولاً: يغطي الدقائق العشر الأولى على VPS جديد مستخدم تسجيل الدخول وجدار الحماية اللذين يفترضهما هذا الدليل.

Slack هو الاستثناء. في Socket Mode، ينشئ اتصالاً صادراً ولا يحتاج إلى عنوان URL عاماً، لذلك يمكن أن يظل النشر الذي يستخدم Slack فقط مغلقاً. لا يوفّر GitHub بديلاً مماثلاً. تصل webhooks الخاصة بالمستودعات عبر HTTP الوارد، وهذا يعني ضرورة توفير نقطة نهاية عامة، وبالتالي استخدام TLS (أمان طبقة النقل) والتحقق من التوقيع.

استضافة OpenTag ذاتياً على Ubuntu من إصدار مثبت

يتطلب OpenTag v0.9.0 الإصدار 22 أو إصداراً أحدث من Node.js. يوفّر Ubuntu 24.04 الإصدار 18 من Node.js في مستودعه الخاص، لذلك ثبّته من NodeSource.

curl -fsSL https://deb.nodesource.com/setup_22.x -o nodesource_setup.sh
sudo -E bash nodesource_setup.sh
sudo apt install -y nodejs
node -v

يجب أن يطبع node -v القيمة v22 أو قيمة أعلى. في Node 20 يطبع التثبيت تحذيراً من EBADENGINE، وقد يفشل CLI عند بدء تشغيله.

امنح الخدمة حساباً خاصاً بها. يعمل الوكيل بصلاحيات هذا المستخدم، لذلك يجب ألا يكون حساب تسجيل دخولك، ويجب ألا يكون root. يوضّح المستخدمون ذوو الصلاحيات المحدودة على VPS سبب أهمية هذا الفصل رغم الخطوة الإضافية.

sudo adduser --disabled-password --gecos "" opentag
sudo loginctl enable-linger opentag
sudo npm install -g @opentag/cli@0.9.0
command -v opentag

يجب أن يطبع command -v opentag مساراً مثل /usr/bin/opentag. إعداد linger مهم في Linux: يثبّت OpenTag خدمته الخلفية عبر systemd، وتتوقف خدمة المستخدم التي لا تستخدم lingering بمجرد إغلاق جلسة SSH.

نفّذ الإعداد بهذا المستخدم.

sudo -iu opentag opentag setup

يسألك الإعداد عن ستة أمور: لغة CLI، وعنوان الاستماع المحلي، ووكيل البرمجة، والمشروع المحلي الذي سيعمل عليه، وبيانات اعتماد المنصة المطلوب حفظها، وطريقة التشغيل. أبقِ عنوان الاستماع على 127.0.0.1، لأن nginx ينهي TLS ويوجّه الطلبات إليه، ولذلك لا تحتاج نقاط الاستماع إلى أن تكون قابلة للوصول من الخارج. بالنسبة إلى GitHub، سيسألك أيضاً عن المستودع بصيغة owner/repo، وما إذا كان يمكنه فتح pull requests، ومنفذ webhook (القيمة الافتراضية 3050)، والرمز المميز. اختر وضع الخدمة الخلفية في النهاية. إذا كان لديك إعداد مسبق وتريد تثبيت الخدمة من دون مطالبات، ينفّذ opentag setup --service ذلك.

يُحفظ الإعداد في /home/opentag/.config/opentag/config.json، وتحفظ حالة التشغيل في /home/opentag/.local/state/opentag. راجع هذه المفاتيح يدوياً بعد أن يكتب الإعداد الملف.

{
  "runnerId": "runner_local",
  "dispatcherUrl": "http://localhost:3030",
  "runnerToken": "...",
  "approvalMode": "ask",
  "repositories": []
}

استخدم runnerToken، وهو الرمز المميز لحامل الصلاحيات الخاص بالتشغيل، بدلاً من pairingToken المشترك الأقدم. يحتفظ ملف الإعداد ببيانات الاعتماد بنص واضح ما لم تستبدلها بمرجع إلى سر، إذ يقرأ المرجع القيمة من البيئة أو من ملف على القرص عند بدء التشغيل. في كلتا الحالتين، يُعد هذا الملف أكثر الملفات حساسية على الخادم: اضبط نمطه على 600، واجعله مملوكاً لـ opentag، ولا تضعه داخل مستودع git. يرد النقاش الأوسع في إبعاد الأسرار عن وكلاء الذكاء الاصطناعي.

تحقق من التثبيت قبل إتاحة أي شيء للخارج.

sudo -iu opentag opentag doctor
sudo -iu opentag opentag status

يتحقق opentag doctor من الموزّع، وعمليات الربط، ونسخ المستودعات، والمنفّذات. يطبع opentag status الإعداد وحالة التشغيل، ويمكن تحديده لتشغيل واحد بعد وجود عمليات تشغيل. أصلح كل ما يبلّغ عنه doctor قبل توجيه منصة إلى هذا الخادم.

ضع TLS في الواجهة وافتح مسارين فقط

ينهي nginx جلسة TLS ويمرّر مسارين محددين فقط. يعيد كل ما عداه الاستجابة 404، لذلك لا يعرف الماسح الذي يعثر على المضيف شيئاً عن الخدمات التي تعمل خلفه.

اكتب كتلة خادم عادية على المنفذ 80 في /etc/nginx/sites-available/opentag، مع الموقعين أدناه، ثم اترك Certbot يضيف جزء TLS.

sudo apt install -y nginx certbot python3-certbot-nginx
sudo ln -s /etc/nginx/sites-available/opentag /etc/nginx/sites-enabled/opentag
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d opentag.example.com

يطبع nginx -t الرمز syntax is ok والرمز test is successful، وهو الحاجز الوحيد بين خطأ مطبعي وإعادة تحميل تؤدي إلى توقف الموقع. يشرح Certbot على Ubuntu 24.04 مع nginx التجديد وطرق فشل تحدي ACME (بيئة إدارة الشهادات التلقائية). تبدو الكتلة النهائية كما يلي.

server {
    listen 443 ssl;
    server_name opentag.example.com;

    ssl_certificate     /etc/letsencrypt/live/opentag.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/opentag.example.com/privkey.pem;

    client_max_body_size 2m;

    location = /github/webhooks {
        proxy_pass http://127.0.0.1:3050;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }

    location = /slack/events {
        proxy_pass http://127.0.0.1:3040;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
    }

    location / {
        return 404;
    }
}

إنّ = في location = /github/webhooks تطابق تام، ويمرّر proxy_pass من دون أي شيء بعد المنفذ معرّف URI الأصلي من دون تغيير. احذف =، وسيُمرَّر كل مسار ضمن /github/webhooks/ أيضاً، وهذا يوسّع سطح التعرض أكثر مما يحتاج إليه المستمع.

يبقى الجدار الناري محدوداً.

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status

لا تُفتح المنافذ 3030 و3040 و3050 مطلقاً. تأكد من ربطها بالواجهة loopback بدلاً من ربطها بكل الواجهات.

sudo ss -tlnp

يجب أن يقرأ كل سطر OpenTag 127.0.0.1:3030 أو ما يشابهه. يعني السطر الذي يقرأ 0.0.0.0:3050 أن المستمع يقدّم نفسه إلى الإنترنت بالكامل، وأن ufw وحده هو الذي يمنع الوصول إليه. وهذا يعني أن خطأً واحداً في الجدار الناري قد يفتح نقطة تشغيل الوكيل. يشرح أساسيات جدار ufw الناري ما يفعله المنع الافتراضي فعلياً.

يثبت فحصان الواجهة الأمامية. يعيد curl -I https://opentag.example.com/ القيمة 404 من nginx، وهذا يثبت صلاحية الشهادة وإغلاق المسار الشامل. ويجب ألا يعيد طلب إلى /slack/events أو /github/webhooks من دون توقيع الاستجابة 200 مطلقاً.

تحقّق من كل توقيع، لأن عنوان URL عام

يمكن لأي شخص العثور على عنوان URL للحمولة. فهو موجود في إعدادات المستودع، وفي سجل المتصفح، وفي لقطة شاشة أُدرجت في تذكرة. والتوقيع هو الشيء الوحيد الذي يميّز تسليم GitHub حقيقياً عن طلب كتبه شخص يدوياً.

يوقّع GitHub كل تسليم باستخدام سر webhook، ويرسل النتيجة في ترويسة x-hub-signature-256. ويتحقق OpenTag من هذه الترويسة مقابل platforms.github.webhookSecret. تنص ملاحظات تقوية المشروع على القاعدة مباشرة: لا تقبل أحداث المصدر غير الموقّعة على /github/webhooks. يوقّع Slack كل طلب باستخدام SLACK_SIGNING_SECRET ويتضمّن طابعاً زمنياً، لذلك لا يمكن إعادة تشغيل جسم ملتقط بعد ساعات.

تجاهل ذلك ليس خطراً بسيطاً. تقبل نقطة نهاية غير متحقَّق منها حمولة issue_comment مكتوبة يدوياً وتتضمن @opentag، ثم يشغّل OpenTag عميلاً برمجياً باستخدام رمزك المميز، وفي نسخة العمل الخاصة بك، بناءً على تعليمات من شخص مجهول. ويذهب الرد إلى أي سلسلة محادثة تحددها الحمولة الزائفة.

يضيف OpenTag طبقتين فوق ذلك. تُتتبَّع عمليات تسليم المصدر بواسطة معرّف التسليم، لذلك لا يؤدي تسليم الحدث نفسه مرة أخرى إلى بدء تشغيل ثانٍ. وتقبل استدعاءات Runner مفاتيح idempotency، لذلك تؤدي إعادة تشغيل أحدها إلى إرجاع نجاح من دون إلحاق حدث تدقيق آخر.

يمكن ضبط حدود المعدل، ويجب تفعيلها. يحدّد OPENTAG_RATE_LIMIT_WINDOW_MS وOPENTAG_RATE_LIMIT_MAX_REQUESTS معدل الطلبات، ويحدّد OPENTAG_MAX_REQUEST_BODY_BYTES حجم الجسم، وتُرفض الحمولة الكبيرة جداً باستخدام 413 request_body_too_large. يوجد OPENTAG_RATE_LIMIT_DISABLED=true للتطوير المحلي، ولا مكان له على خادم عام. وتنص الملاحظات نفسها على قاعدة إضافية: يجب أن يستخدم عنوان URL للترحيل العام HTTPS، ولا تسمح CLI باستخدام HTTP العادي إلا مع localhost.

ما نطاقات الرموز التي يحتاج إليها الروبوت فعلياً؟

في GitHub، يستخدم OpenTag رمز وصول شخصياً دقيق الصلاحيات بدلاً من GitHub App. توضح الوثائق أن مسار App مخطط له وليس إعداد CLI الافتراضياً في الوقت الحالي. ويترتب على ذلك أمر يغفل عنه بعض المستخدمين: يضيف الروبوت التعليقات باسم الشخص الذي أنشأ الرمز. أنشئ الرمز ضمن حساب تقبل أن يظهر اسمه في كل رد من ردود الفرز.

قيّد النطاقات كما يحدّدها دليل الإعداد. اختر Only select repositories وحدد مستودعاً واحداً. امنح الرمز الصلاحيتين Issues: Read and write وPull requests: Read and write. يكفي ذلك لقراءة إشارة والرد في سلسلة النقاش.

لاحظ الصلاحية الغائبة: الوصول للكتابة إلى الشيفرة. لا يرفع OpenTag فروعاً ما لم يتم ضبط preparePullRequestBranch على true. ويوجد githubApplyToken منفصل حتى لا يكون الرمز الذي يكتب الشيفرة هو نفسه الرمز الذي يكتب التعليقات. أبقِ الرمزين منفصلين، ولا تفعّل رمز الكتابة حتى يعمل مسار القراءة والتعليق لبضعة أسابيع.

تجنب إعداد رمز يملك Contents: Read and write عبر All repositories. كل من يستطيع التعليق في أي من تلك المستودعات سيتمكن عندئذ من توجيه وكيل يملك صلاحية إجراء عمليات commit، وسيوضح سجل التدقيق أن مالك الرمز هو من نفّذها. وسّع النطاق لمستودع واحد في كل مرة، بعد أن يثبت الوكيل استحقاقه.

في Slack، نطاقات الروبوت هي app_mentions:read وchat:write وreactions:write وchannels:history. تحتاج القنوات الخاصة أيضاً إلى groups:history، إضافة إلى الاشتراك في الحدث message.groups. يتطلب Socket Mode رمزاً على مستوى التطبيق يتضمن connections:write، وهو الرمز الذي يبدأ بـxapp-. يقرأ channels:history سجل الرسائل في القنوات العامة التي أُضيف إليها الروبوت. لذلك أضف الروبوت إلى القنوات المطلوبة، لا إلى جميع القنوات.

معالجة مشكلة واحدة من البداية إلى النهاية

يبدأ الإعداد بالـwebhook. في المستودع، افتح Settings، ثم Webhooks، ثم Add webhook. عنوان payload هو https://opentag.example.com/github/webhooks، ونوع المحتوى هو application/json، والسر هو السر الذي أنشأه الإعداد. اشترك في Issue comments وPull request review comments فقط.

يرسل GitHub عملية ping delivery فور حفظ الإعداد. افتح Recent Deliveries وتحقق من وصول الطلب إلى الخادم أصلاً. ظهور 502 هناك يعني أن nginx تعذّر عليه الوصول إلى المستمع، وهذه مشكلة محلية وليست مشكلة في GitHub.

استخدمه الآن. افتح issue تصف خطأً وأضف التعليق التالي:

@opentag triage this. Reproduce the report against the current main branch, then reply with the file and function most likely responsible, plus the test you would write first.

يُفترض أن يحدث ما يلي بالترتيب. يسجل Recent Deliveries عملية issue_comment delivery مع استجابة 2xx. يسجل dispatcher عملية تشغيل. يستولي runner عليها ويبدأ إرسال heartbeats. يفتح executor نسخة checkout ويعمل عليها. تصل الإجابة في صورة تعليق ضمن سلسلة issue نفسها. يعرض sudo -iu opentag opentag status عملية التشغيل أثناء تنفيذها، لذلك يمكنك مراقبتها بدلاً من التخمين.

اضبط approvalMode على ask قبل أول عملية تشغيل فعلية. في وضع ask تتوقف العملية وتنتظر شخصاً قبل تنفيذ أي إجراء يغيّر الحالة. وضعا auto وautonomous متاحان، ومن المناسب استخدامهما لاحقاً في مستودع قرأت فيه نصوص التشغيل لمدة شهر.

في جانب Slack، تبدأ عملية التشغيل نفسها باستخدام /bind owner/repo في القناة، ثم بإشارة mention. يجيب bot أيضاً عن /help و/status و/doctor و/stop و/unbind confirm. قيّد من يمكنه تغيير الارتباطات باستخدام OPENTAG_SLACK_BINDING_ADMIN_USER_IDS، وهي قائمة مفصولة بفواصل من Slack user IDs، لأن الارتباط هو التعيين بين قناة عامة وcheckout على خادمك.

تُعد Triage مساراً أولاً جيداً لأنها تقرأ ولا تكتب، كما أن تقييم الإجابة سهل. أما Review فهي الخطوة التالية، حيث يعلّق agent على diff بدلاً من issue: agent لمراجعة pull request مستضاف ذاتياً هو البنية نفسها الموجّهة إلى pull requests. إذا أردت أن يصل agent إلى أنظمتك الخاصة أثناء عمله، فهذه مهمة خوادم MCP على VPS.

ماذا يحدث عندما يخطئ الوكيل أمام الجميع؟

سيخطئ الوكيل. والسؤال هو حجم التكلفة الناتجة عن ذلك.

الرد الخاطئ في issue عامة هو تعليق تحت اسم يتعرف إليه فريقك، ويرسل GitHub رسالة بريد إلكتروني إلى كل المشتركين فور نشره. حذف التعليق لا يسحب الرسالة من البريد. وينطبق الأمر نفسه على إشعار Slack. خطط على أساس احتمال أن تكون الإجابة خاطئة علناً، لا على أساس أن تكون صحيحة في بيئة خاصة.

تحد أربعة خيارات حجم الضرر، وهي أهم من أي prompt تكتبه.

  • شغّل الوكيل في وضع ask، بحيث يقترح الوكيل الخطة، ويوافق عليها شخص، ولا يتسبب الخطر الناتج عن خطة خاطئة إلا في نقرة واحدة.
  • اترك preparePullRequestBranch على القيمة الافتراضية false، بحيث تكون أسوأ نتيجة لتشغيل سيئ تعليقاً خاطئاً بدلاً من فرع خاطئ.
  • اربط مستودعاً واحداً وقناة واحدة في البداية. يرفض runner أي تشغيل يكون هدف المشروع فيه خارج قائمة السماح المحلية، ولذلك لا يمكن لمستودع غير مرتبط أن يستدعي الوكيل للعمل عليه.
  • افصل token التعليق عن أي token للتطبيق، بحيث لا يؤدي إلغاء صلاحية الكتابة إلى تعطيل triage معها.

يحتوي Slack على الأمر /stop لإيقاف تشغيل يسير في الاتجاه الخاطئ. يترك كل تشغيل أيضاً سجلاً تدقيقياً يتضمن الإشارة التي بدأته وما فعله الوكيل. تقرأ هذا السجل لاحقاً لتحديد موضع الخطأ.

الجانب الاجتماعي مهم بقدر أهمية الإعدادات. ضع bot في قناة واحدة يتوقع فيها الأشخاص وجود آلة، ويعرفون أنها قد تخطئ. الإجابة الخاطئة الواثقة في قناة تضم أربعين شخصاً يفترضون أن إنساناً راجعها تكلف أكثر من الوقت الذي وفّره triage. اكتب في وصف القناة اسم المسؤول عن bot ومن يراجع مخرجاته.

النسخ الاحتياطية والترقيات وتثبيت الإصدار

يوجد كل شيء في مسارين: /home/opentag/.config/opentag/config.json و/home/opentag/.local/state/opentag. يحتوي الأول على بيانات الاعتماد، ويحتوي الثاني على سجل التشغيل وملف قاعدة البيانات. انسخ كليهما احتياطياً باستخدام النمط 600، واحتفظ بالنسخ خارج الخادم. فقدانهما يعني إعادة إنشاء الرموز والربط، وليس إعادة بناء الخادم.

الترقيات هي تحديث للإصدار ثم إعادة تشغيل.

sudo npm install -g @opentag/cli@0.9.0
sudo -iu opentag opentag service stop
sudo -iu opentag opentag service start
sudo -iu opentag opentag doctor

ثبّت الإصدار بدلاً من تتبّع @latest. يشغّل هذا البرنامج وكيلاً برمجياً على مستودعك باستخدام رمز حي، ولذلك فإن إصداراً يُنشر أثناء الليل يمثل تغييراً غير مُراجَع في ذلك الوكيل. لا تنقل سياسة الأمان الإصلاحات إلى الإصدارات الأقدم، ولا تصل الإصلاحات إلا إلى أحدث إصدار. لذلك يعني تثبيت الإصدار قراءة سجل التغييرات ثم الترقية عن قصد. لا يعني ذلك البقاء على v0.9.0 إلى الأبد. يُظهر السجل حتى July 2026 صدور عدة إصدارات شهرياً، وهذا سبب وجيه لقراءة ملاحظات الإصدار قبل كل تحديث.

FAQ

هل أحتاج إلى VPS لتشغيل OpenTag، أم يكفي حاسوب محمول؟

يكفي حاسوب محمول لتشغيل Slack وحده، لأن Socket Mode يفتح WebSocket صادراً ولا يحتاج إلى منفذ وارد. يختلف GitHub عن ذلك. تُرسل webhooks الخاصة بالمستودع عبر HTTP وارد إلى URL تسجّله مرة واحدة، لذلك يجب أن يبقى العنوان ثابتاً وأن يستجيب أثناء نومك. يغيّر tunnel host من حساب مجاني عنوانه عند كل إعادة تشغيل، ويواصل GitHub الإرسال إلى العنوان القديم. يظهر ذلك كإدخالات فاشلة في علامة Recent Deliveries الخاصة بالمستودع، وكصمت في سلسلة المحادثة. يزيل VPS باسم DNS ثابت وشهادة كلا المشكلتين.

ما أذونات GitHub التي يحتاج إليها OpenTag؟

يحتاج إلى personal access token دقيق الصلاحيات، مقيّد بخيار Only select repositories، مع Issues: Read and write وPull requests: Read and write. يغطي ذلك قراءة الإشارة والرد في سلسلة المحادثة. لا يلزم الوصول للكتابة إلى الشيفرة إلا إذا ضبطت preparePullRequestBranch على true لكي يدفع OpenTag الفروع، كما يتوفر githubApplyToken منفصل لإبقاء token الخاص بكتابة الشيفرة منفصلاً عن token الخاص بالتعليقات. تجنّب token لجميع المستودعات مع صلاحية contents write، لأن أي شخص يستطيع التعليق على أي من تلك المستودعات سيتمكن عندئذ من توجيه agent يستطيع إجراء commit.

كيف أوقف عملية تشغيل تسير في الاتجاه الخاطئ؟

يحتوي Slack على الأمر /stop لهذا الغرض تحديداً. على الخادم، يعرض opentag status ما يعمل حالياً، بينما يوقف opentag service stop daemon، وينهي ذلك خط المعالجة بالكامل بدلاً من عملية تشغيل واحدة. لتجنب الحاجة إلى أي منهما، اضبط approvalMode على ask لكي تتوقف عمليات التشغيل بانتظار شخص قبل أن تغيّر أي شيء، واترك preparePullRequestBranch مضبوطاً على false لكي تنتج عملية التشغيل السيئة تعليقاً بدلاً من فرع.

لماذا يعيد webhook الحالة 502 بينما تبقى سلسلة المحادثة صامتة؟

تأتي الحالة 502 من nginx، لا من OpenTag، وهذا يعني أن الـproxy لم يتمكن من الوصول إلى listener. سيعرض /var/log/nginx/error.log القيمة connect() failed (111: Connection refused) while connecting to upstream. إما أن listener متوقف، أو أنه يعمل على منفذ مختلف عن المنفذ المذكور في السطر proxy_pass. شغّل sudo ss -tlnp وتأكد من وجود listener على 127.0.0.1:3050 لـGitHub وعلى 127.0.0.1:3040 لـSlack، ثم شغّل opentag doctor لعرض عمليات الربط والمنفّذات.