راهنمای نصب و میزبانی OpenTag برای Coding Agent
با نصب OpenTag روی VPS، منشنهای Slack و GitHub را به ایجنت خود متصل کنید. این راهنما تنظیمات TLS، بررسی امضای Webhook و پیکربندی نسخه 0.9.0 را برای عملکرد امن شرح میدهد.
وقتی یک agent را منشن میکنید، OpenTag چه کاری انجام میدهد
OpenTag یک @mention در یک thread در Slack یا یک issue در GitHub را به اجرای یک coding agent روی ماشینی که مالک آن هستید، تبدیل میکند. شخصی در یک issue عبارت @opentag investigate this را کامنت میکند. یک listener رویداد پلتفرم را دریافت کرده، امضای آن را بررسی میکند، منشن را با یک پروژهٔ متصل تطبیق میدهد، یک coding agent را روی یک checkout محلی اجرا میکند و نتیجه را در همان thread ارسال میکند.
این پروژه دارای مجوز MIT است و در amplifthq/opentag قرار دارد. تا اکتبر 2026، جدیدترین نسخهٔ تگشده v0.10.0 است که در 17 اوت 2026 منتشر شده است. این CLI به عنوان یک پکیج npm عرضه میشود. در آنجا، 0.10.0 دارای تگ latest و 0.11.0 دارای تگ next است، اما فایل README نسخه v0.10.0 همچنان از 0.9.0 به عنوان نسخهٔ پایدار مستندشده نام میبرد، بنابراین 0.9.0 نسخهای است که این راهنما بر آن تأکید دارد. تمام دستورات زیر آن را ثابت نگه میدارند. OpenTag یک image کانتینر رسمی برای Control Plane اختیاری که در 0.10.0 اضافه شده، منتشر میکند. این image با نام ghcr.io/amplifthq/opentag-control-plane برای linux/amd64 ساخته شده و با SHA منبع تگ میشود. این image هیچ تگ latest ندارد، بنابراین باید آن را با sha256 digest ثابت کنید. این راهنما از Control Plane استفاده نمیکند، بنابراین چیزی که در اینجا ثابت میکنید، نسخهٔ npm است.
این پروژه به دلیل بخش GitHub، به جای یک پروژهٔ لپتاپی، به یک پروژهٔ VPS تبدیل میشود. GitHub رویدادهای مخزن را با ارسال یک درخواست HTTP به آدرسی که یک بار ثبت میکنید، تحویل میدهد، بنابراین آن آدرس باید فردا هم در همان نشانی پاسخگو باشد.
چهار بخش متحرک
شنونده (The listener) رویدادهای پلتفرم را دریافت میکند و هر پلتفرم شنوندهٔ اختصاصی خود را دارد. شنوندهٔ GitHub یک endpoint از نوع HTTP روی پورت 3050 و در مسیر /github/webhooks است. شنوندهٔ Slack Events API روی پورت 3040 و در مسیر /slack/events قرار دارد. Slack همچنین میتواند در حالت Socket Mode اجرا شود که در آن، برنامه یک WebSocket خروجی باز میکند و نیازی به هیچ پورت ورودی ندارد.
توزیعکننده (The dispatcher) هماهنگکنندهٔ سیستم است. این بخش بهصورت پیشفرض روی پورت 3030 گوش میدهد، وضعیت اجرا را در یک فایل دیتابیس محلی که توسط OPENTAG_DATABASE_PATH تعیین شده نگه میدارد و برای هر اجرا یک مسیر حسابرسی (audit trail) ثبت میکند. هیچ موجودیتی خارج از این جعبه نباید به این پورت دسترسی داشته باشد.
اجراکننده (The runner) یک دیمون محلی است. این بخش برای دریافت کار نظرسنجی (poll) میکند، یک اجرا را تصاحب کرده، آن را در اختیار میگیرد و بهصورت پیشفرض هر 15 ثانیه در طول مدت فعال بودن اجرا، یک heartbeat ارسال میکند. این بخش از پذیرش هر اجرای تصاحبشدهای که پروژهٔ هدف آن موجود نباشد یا خارج از لیست مجاز (allowlist) در پیکربندیاش باشد، خودداری میکند؛ این همان بررسی امنیتی است که مانع از آن میشود که یک رویداد GitHub، عامل شما را به مخزنی که هرگز به آن متصل نکردهاید، هدایت کند.
مجری (The executor) همان عامل کدنویسی است. OpenTag آن را از طریق ACP (پروتکل کلاینت عامل) راهاندازی میکند؛ یک پروتکل JSON-RPC که از طریق ورودی و خروجی استاندارد (stdin/stdout) تبادل میشود، بنابراین عامل بهعنوان یک پردازش فرزند در دایرکتوری کاری که OpenTag به آن اختصاص میدهد، اجرا میشود. نامهای داخلی شامل echo، codex، claude-code، cursor، opencode، hermes و openclaw هستند. با echo شروع کنید، مجریای که در پیکربندی نمونه ارائه شده است، زیرا پیش از آنکه یک مدل با کد شما تعامل داشته باشد، صحت کل مسیر را اثبات میکند. اگر حلقهای که یک prompt را میخواند، ابزارها را فراخوانی میکند و تصمیم میگیرد چه زمانی کار تمام شده است برای شما همچنان یک جعبه سیاه است، نوشتن یک حلقهٔ عامل کوچک توسط خودتان باعث میشود حالتهای شکست در این خط لوله بسیار سادهتر قابلتشخیص باشند.
ترتیب عملیات هرگز تغییر نمیکند: رویداد پلتفرم، بررسی امضا، ثبت اجرا، تصاحب، عامل، پاسخ در thread.
چرا لپتاپ و تونل کافی نیستند
راهنمای راهاندازی GitHub به شما میگوید که ngrok http 3050 را اجرا کنید و میزبان تونل را در webhook مخزن قرار دهید. این روش برای ده دقیقه اول کار میکند. آدرس دیگر مشکل نیست: طرح رایگان ngrok به هر حساب یک دامنه توسعه پایدار میدهد و ngrok http هر بار که آن را مجدداً راهاندازی میکنید، از همان دامنه استفاده میکند. مشکل اصلی خودِ تونل است. تونل فقط زمانی پاسخ میدهد که فرآیند agent روی لپتاپی که روشن است اجرا شود و با به خواب رفتن لپتاپ، تونل از بین میرود. با این حال، GitHub همچنان به تلاش برای ارسال payload URL ادامه میدهد، بنابراین زبانه Recent Deliveries در تنظیمات webhook با خطاها پر میشود در حالی که thread هیچ پاسخی نمیدهد. هیچکس تا یک هفته متوجه این موضوع نمیشود، زیرا یک webhook که هیچ کاری انجام نمیدهد، دقیقاً شبیه به یک بات است که کسی به آن اشاره نکرده است.
یک VPS آنچه را که خراب میشود، اصلاح میکند. نام DNS متعلق به شماست، بنابراین payload URL که یک بار وارد میکنید بدون وابستگی به ارائهدهنده تونل، صحیح باقی میماند. دستگاه به خواب نمیرود، بنابراین یک کامنت در ساعت 02:00 پاسخ دریافت میکند. ابتدا سرور را بهدرستی تنظیم کنید: ده دقیقه اول روی یک VPS جدید شامل کاربر ورود و فایروالی است که این راهنما فرض میکند.
Slack یک استثنا است. در حالت Socket Mode، این سرویس به سمت بیرون متصل میشود و نیازی به URL عمومی ندارد، بنابراین استقرار فقط برای Slack میتواند بسته باقی بماند. GitHub چنین قابلیتی ندارد. Webhookهای مخزن از نوع HTTP ورودی هستند، که به معنای داشتن یک endpoint عمومی، و در نتیجه نیاز به TLS (امنیت لایه انتقال) و بررسی امضا است.
میزبانی OpenTag روی Ubuntu از یک نسخه مشخص (Pinned Release)
نسخه v0.9.0 از OpenTag به Node.js 22 یا جدیدتر نیاز دارد و در نسخه v0.10.0 این حداقل به 22.14 افزایش یافته است. توزیع Ubuntu 24.04 بهصورت پیشفرض Node 18 را در مخازن خود ارائه میدهد، بنابراین آن را از طریق 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 پس از شروع کار با خطا مواجه شود.
برای این سرویس یک حساب کاربری اختصاصی ایجاد کنید. عامل (agent) با مجوزهای این کاربر اجرا میشود، بنابراین نباید از حساب کاربری شخصی خود یا 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 در لینوکس اهمیت دارد: OpenTag سرویس پسزمینه خود را از طریق systemd نصب میکند و یک سرویس کاربری بدون فعال بودن linger، بلافاصله پس از بستن نشست SSH متوقف میشود.
مراحل راهاندازی را با همان کاربر اجرا کنید.
sudo -iu opentag opentag setupمراحل راهاندازی شش مورد را میپرسد: زبان CLI، آدرس گوشدهی محلی، عامل کدنویسی (coding agent)، پروژه محلی برای کار، اعتبارنامههای پلتفرم برای ذخیرهسازی، و نحوه اجرا. آدرس گوشدهی را روی 127.0.0.1 نگه دارید، زیرا nginx عملیات TLS termination را انجام داده و درخواستها را به آن هدایت میکند، بنابراین نیازی نیست که این شنوندهها از خارج در دسترس باشند. برای GitHub، برنامه نام مخزن را به فرمت owner/repo، اجازه ایجاد pull request، پورت webhook (بهصورت پیشفرض 3050) و توکن را میپرسد. در پایان، حالت سرویس پسزمینه (background service) را انتخاب کنید. اگر از قبل فایل پیکربندی دارید و میخواهید سرویس بدون پرسش نصب شود، دستور 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، یعنی توکن bearer با دامنه محدود به runner، را به توکنهای اشتراکی قدیمیتر pairingToken ترجیح دهید. فایل پیکربندی اعتبارنامهها را بهصورت متن ساده (plain text) نگه میدارد، مگر اینکه آنها را با یک ارجاع به secret جایگزین کنید که مقدار را در زمان شروع از محیط یا فایلی روی دیسک میخواند. در هر صورت، این فایل حساسترین بخش سرور شماست: دسترسی آن را روی 600 تنظیم کنید، مالکیت آن را به opentag بدهید و هرگز آن را داخل مخزن git قرار ندهید. بحث مفصلتر در محافظت از اسرار در عاملهای هوش مصنوعی آمده است.
پیش از در معرض دید قرار دادن هر چیزی، نصب را بررسی کنید.
sudo -iu opentag opentag doctor
sudo -iu opentag opentag statusدستور opentag doctor وضعیت dispatcher، اتصالات (bindings)، checkouts و اجراکنندهها (executors) را بررسی میکند. دستور opentag status پیکربندی و وضعیت زمان اجرا را چاپ میکند و پس از ایجاد اولین اجراها، میتوان آن را به یک اجرای خاص محدود کرد. پیش از متصل کردن پلتفرم به این سرور، تمام مواردی که doctor گزارش میدهد را برطرف کنید.
قرار دادن TLS در لایه جلو و باز کردن تنها دو مسیر
Nginx عملیات TLS termination را انجام داده و دقیقاً دو مسیر را فوروارد میکند. هر درخواست دیگری با خطای 404 مواجه میشود، بنابراین اسکنری که میزبان را پیدا میکند، هیچ اطلاعاتی درباره سرویسهای پشت آن به دست نمیآورد.
یک بلاک server ساده برای پورت 80 در /etc/nginx/sites-available/opentag با دو location زیر بنویسید، سپس اجازه دهید 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.comnginx -t خروجی syntax is ok و test is successful را چاپ میکند و تنها مانع بین یک اشتباه تایپی و reload شدن سرویسی است که سایت را از دسترس خارج میکند. 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 یک تطابق دقیق (exact match) است و proxy_pass بدون هیچ عبارتی بعد از پورت، URI اصلی را بدون تغییر عبور میدهد. = را حذف کنید تا هر مسیری زیر /github/webhooks/ نیز فوروارد شود، که این کار سطح دسترسی بیشتری از نیاز listener ایجاد میکند.
فایروال باید محدود باقی بماند.
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw statusپورتهای 3030، 3040 و 3050 هرگز نباید باز شوند. تأیید کنید که آنها به جای تمام اینترفیسها، فقط روی loopback متصل (bind) شدهاند.
sudo ss -tlnpهر خط OpenTag باید به صورت 127.0.0.1:3030 یا مشابه آن باشد. خطی که 0.0.0.0:3050 را نشان میدهد به این معنی است که listener خود را به کل اینترنت عرضه کرده و تنها ufw جلوی آن را گرفته است؛ این وضعیت با یک اشتباه در تنظیمات فایروال، میتواند منجر به فعال شدن یک agent باز شود. اصول فایروال ufw توضیح میدهد که آن deny پیشفرض واقعاً چه کاری انجام میدهد.
دو بررسی، صحت درب ورودی را اثبات میکند. curl -I https://opentag.example.com/ باید 404 را از nginx برگرداند که نشاندهنده معتبر بودن گواهی و بسته بودن catch-all است. درخواستی به /slack/events یا /github/webhooks که فاقد امضا باشد، هرگز نباید کد 200 برگرداند.
تمام امضاها را تأیید کنید، زیرا URL عمومی است
هر کسی میتواند URL مربوط به payload را پیدا کند. این URL در تنظیمات مخزن شما، تاریخچه مرورگر یا اسکرینشاتی که در یک تیکت الصاق شده، وجود دارد. امضا تنها چیزی است که یک تحویل واقعی از GitHub را از درخواستی که شخصی بهصورت دستی تایپ کرده است، متمایز میکند.
GitHub هر تحویل را با webhook secret امضا کرده و نتیجه را در هدر x-hub-signature-256 ارسال میکند. OpenTag آن هدر را در برابر platforms.github.webhookSecret تأیید میکند. یادداشتهای امنسازی پروژه این قانون را مستقیماً بیان میکنند: رویدادهای منبع بدون امضا را در /github/webhooks نپذیرید. Slack هر درخواست را با SLACK_SIGNING_SECRET امضا کرده و یک timestamp در آن میگنجاند، بنابراین بدنه ضبطشده نمیتواند ساعتها بعد دوباره ارسال (replay) شود.
نادیده گرفتن این مورد ریسک کوچکی نیست. یک endpoint تأییدنشده، یک payload دستنویس issue_comment حاوی @opentag را میپذیرد و سپس OpenTag یک عامل کدنویسی را با توکن شما، در checkout شما و طبق دستورات یک غریبه اجرا میکند. پاسخ به هر رشتهای (thread) که payload جعلی نام ببرد، ارسال میشود.
OpenTag دو لایه در بالا اضافه میکند. تحویلهای منبع با delivery ID ردیابی میشوند، بنابراین تحویل مجدد همان رویداد، اجرای دومی را آغاز نمیکند. فراخوانیهای Runner کلیدهای idempotency را میپذیرند، بنابراین پخش مجدد یک مورد، بدون افزودن رویداد حسابرسی (audit event) دیگر، موفقیت را برمیگرداند.
محدودیتهای نرخ (Rate limits) قابل پیکربندی هستند و باید فعال باشند. OPENTAG_RATE_LIMIT_WINDOW_MS و OPENTAG_RATE_LIMIT_MAX_REQUESTS نرخ درخواست را محدود میکنند، OPENTAG_MAX_REQUEST_BODY_BYTES بدنه را محدود میکند و یک payload بیش از حد بزرگ با 413 request_body_too_large رد میشود. OPENTAG_RATE_LIMIT_DISABLED=true برای توسعه محلی وجود دارد و در یک سرور عمومی جایگاهی ندارد. یک قانون دیگر از همان یادداشتها: یک URL رله عمومی باید از HTTPS استفاده کند و CLI فقط برای localhost اجازه استفاده از HTTP ساده را میدهد.
این بات واقعاً به چه دامنههای دسترسی (Scope) نیاز دارد؟
در GitHub، ابزار OpenTag بهجای استفاده از GitHub App، از یک personal access token با دسترسی محدود (fine-grained) استفاده میکند. مستندات بیان میکنند که مسیر استفاده از App در برنامه است و در حال حاضر تنظیمات پیشفرض CLI نیست؛ این موضوع پیامدی دارد که کاربران اغلب از آن غافل میشوند: بات با نام کاربری انسانی که توکن را ایجاد کرده است، کامنت میگذارد. توکن را تحت حسابی ایجاد کنید که مایل هستید در تمام پاسخهای تریاژ (triage) به عنوان نویسنده دیده شود.
دامنههای دسترسی را دقیقاً مطابق راهنمای نصب محدود کنید. گزینه Only select repositories را انتخاب کرده و تنها یک مخزن را برگزینید. دسترسیهای Issues: Read and write و Pull requests: Read and write را اعطا کنید. این سطح دسترسی برای خواندن منشنها و پاسخ در رشته گفتگو کافی است.
به آنچه حذف شده دقت کنید: دسترسی نوشتن به کد (Contents). ابزار OpenTag تا زمانی که preparePullRequestBranch روی true تنظیم نشده باشد، هیچ branchای را push نمیکند و یک githubApplyToken مجزا وجود دارد تا توکنی که کد مینویسد، همان توکنی نباشد که کامنتها را ثبت میکند. این دو را از هم جدا نگه دارید و توکنِ دارای دسترسی نوشتن را تا زمانی که مسیر خواندن و کامنتگذاری برای چند هفته بهدرستی کار نکرده است، فعال نکنید.
پیکربندیای که باید از آن اجتناب کرد، توکنی با دسترسی Contents: Read and write برای All repositories است. در این حالت، هر کسی که بتواند در هر یک از آن مخازن کامنت بگذارد، میتواند عاملی (agent) را هدایت کند که دسترسی commit دارد و در لاگهای حسابرسی نیز نام مالک توکن به عنوان عامل ثبت میشود. پس از آنکه عامل اعتماد لازم را کسب کرد، دامنه دسترسی را مخزن به مخزن گسترش دهید.
در Slack، دامنههای دسترسی بات عبارتند از app_mentions:read، chat:write، reactions:write و channels:history. کانالهای خصوصی همچنین به groups:history به همراه اشتراک در رویداد message.groups نیاز دارند. حالت Socket Mode به یک توکن در سطح اپلیکیشن با connections:write نیاز دارد؛ همان توکنی که با xapp- شروع میشود. channels:history تاریخچه پیامها را در کانالهای عمومی که بات به آنها اضافه شده است میخواند، بنابراین بات را فقط به کانالهایی اضافه کنید که به آن نیاز دارید، نه در همه جا.
عیبیابی مسیر یک issue از ابتدا تا انتها
ابتدا باید webhook را تنظیم کنید. در مخزن (repository) به بخش Settings، سپس Webhooks و بعد Add webhook بروید. آدرس Payload URL برابر با https://opentag.example.com/github/webhooks، نوع محتوا (content type) برابر با application/json و secret همان مقداری است که در زمان راهاندازی ایجاد کردید. فقط گزینههای Issue comments و Pull request review comments را انتخاب کنید و سایر موارد را غیرفعال بگذارید.
به محض ذخیره، GitHub یک درخواست ping ارسال میکند. بخش Recent Deliveries را باز کنید و بررسی کنید که آیا درخواست به سرور رسیده است یا خیر. خطای 502 در اینجا به این معناست که nginx نمیتواند به listener متصل شود؛ این یک مشکل محلی است و به 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 را با پاسخ 2xx ثبت کند. dispatcher یک اجرا (run) ثبت میکند. runner آن را تحویل گرفته و شروع به ارسال heartbeat میکند. executor عملیات checkout را انجام داده و کار را شروع میکند. پاسخ در قالب یک کامنت در همان thread مربوط به issue ارسال میشود. sudo -iu opentag opentag status وضعیت اجرا را در حین انجام نشان میدهد، بنابراین میتوانید به جای حدس زدن، روند را مشاهده کنید.
پیش از اولین اجرای واقعی، approvalMode را روی ask تنظیم کنید. در حالت ask، اجرا متوقف شده و منتظر تأیید کاربر میماند تا هرگونه تغییری در وضعیت (state) ایجاد کند. حالتهای auto و autonomous نیز وجود دارند که پس از مطالعه یک ماه از گزارشهای عملکرد (transcripts) در مخزن، گزینههای معقولی برای استفاده هستند.
در سمت Slack، همان اجرا با /bind owner/repo در کانال شروع شده و سپس یک mention ارسال میشود. ربات همچنین به /help، /status، /doctor، /stop و /unbind confirm پاسخ میدهد. دسترسی به تغییر bindingها را با استفاده از OPENTAG_SLACK_BINDING_ADMIN_USER_IDS محدود کنید؛ این متغیر لیستی از Slack user IDها با جداکننده کاما است، زیرا binding نگاشت یک کانال عمومی به یک checkout روی سرور شماست.
Triage مسیر مناسبی برای شروع است، زیرا فقط خواندنی است و تغییری ایجاد نمیکند، همچنین ارزیابی پاسخ آن ساده است. گام بعدی Review است که در آن agent به جای issue، روی یک diff کامنت میگذارد: یک agent بررسی pull request خودمیزبان از همین معماری استفاده میکند که به سمت pull requestها هدایت شده است. اگر میخواهید agent در حین کار به سیستمهای داخلی شما دسترسی داشته باشد، این وظیفه سرورهای MCP روی یک VPS است. جستجوی وب قابلیت دیگری است که triage مرتباً به آن نیاز دارد و اتصال agent به نمونه SearXNG شخصی باعث میشود این جستجوها روی سختافزار تحت کنترل شما انجام شود، البته با پذیرش این نکته که یک کانال ارتباطی دیگر برای ورود متنهای خارجی به agent ایجاد شده است.
اگر عامل (agent) در مقابل همه اشتباه کند چه میشود؟
پاسخ اشتباه خواهد بود. مسئله این است که این اشتباه چه هزینهای دارد.
یک پاسخ نادرست در یک issue عمومی، کامنتی است که با نامی که تیم شما میشناسد ثبت میشود و GitHub بلافاصله پس از ارسال، آن را برای تمام مشترکین ایمیل میکند. حذف کردن کامنت، ایمیل ارسالشده را بازنمیگرداند. همین موضوع در مورد اعلانهای Slack نیز صادق است. به جای برنامهریزی برای درست بودن پاسخ در محیط خصوصی، برای اشتباه بودن آن در محیط عمومی برنامهریزی کنید.
چهار گزینه میزان خسارت را محدود میکنند و اهمیت آنها از هر پرامپتی که مینویسید بیشتر است:
- در حالت
askاجرا کنید تا عامل پیشنهاد دهد، یک انسان تأیید کند و هزینه یک طرح اشتباه تنها یک کلیک باشد. - مقدار
preparePullRequestBranchرا در حالت پیشفرض false نگه دارید تا بدترین نتیجهٔ یک اجرای ناموفق، یک کامنت اشتباه باشد، نه یک branch اشتباه. - برای شروع، یک مخزن (repository) و یک کانال را متصل کنید. runner هر اجرایی را که هدف پروژهٔ آن خارج از لیست مجاز محلی باشد رد میکند، بنابراین یک مخزن متصلنشده نمیتواند عامل را به درون خود بکشد.
- توکن کامنتگذاری را از هرگونه توکن اعمال (apply) جدا نگه دارید تا با لغو دسترسی نوشتن، قابلیت تریاژ (triage) از کار نیفتد.
Slack یک دستور /stop برای اجرایی که در مسیر اشتباه پیش میرود دارد. هر اجرا همچنین یک سابقهٔ بازرسی (audit record) باقی میگذارد که شامل منشنی است که آن را آغاز کرده و کارهایی که عامل انجام داده است؛ این همان چیزی است که بعداً برای فهمیدن علت بروز خطا مطالعه میکنید.
بخش اجتماعی به اندازهٔ پیکربندی اهمیت دارد. ربات را در کانالی قرار دهید که افراد در آن انتظار یک ماشین را دارند و میدانند که ممکن است اشتباه کند. یک پاسخ اشتباهِ متقاعدکننده در کانالی با چهل نفر که تصور میکنند یک انسان آن را بررسی کرده است، هزینهای بیش از صرفهجوییِ حاصل از تریاژ دارد. در توضیحات کانال بنویسید که چه کسی مالک ربات است و چه کسی خروجی آن را بررسی میکند.
پشتیبانگیری، ارتقا و پین کردن نسخه
همه چیز در دو مسیر ذخیره میشود: /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، نسخه را پین کنید. این نرمافزار یک عامل کدنویسی را با استفاده از یک توکن فعال روی مخزن شما اجرا میکند؛ بنابراین نسخهای که در طول شب منتشر میشود، تغییری بررسینشده در آن فرآیند است. سیاست امنیتی بیان میکند که اصلاحات برای آخرین نسخه منتشر شده و شاخه فعلی main ارائه میشوند و ممکن است نسخههای قدیمیتر، اصلاحات backport را دریافت نکنند. نسخه پینشده 0.9.0 هماکنون یک نسخه عقبتر از v0.10.0 است، بنابراین پین کردن به این معناست که شما changelog را میخوانید و آگاهانه ارتقا میدهید. این به معنای ماندن همیشگی روی v0.9.0 نیست. تاریخچه تا ژوئیه 2026 نشاندهنده چندین انتشار در ماه است و v0.10.0 در 17 اوت منتشر شد که دلیل خوبی برای مطالعه یادداشتهای انتشار پیش از هر ارتقا است. نسخه v0.10.0 همچنین تکمیل تحت نظارت (governed completion) را به حالت پیشفرض برای اجرای pull requestهای GitHub تبدیل کرده است و OPENTAG_GITHUB_DEFAULT_COMPLETION=compat رفتار قدیمی را بازیابی میکند.
از اینجا به بعد یادداشتها را با دقت بخوانید. از اکتبر 2026، بخش منتشرنشده changelog در main یک بازنشانی (reset) عمدی و ناسازگار پیش از نسخه 1.0 را توصیف میکند که GitHub را به عنوان یک منبع برنامه و همچنین dispatcher داخلی SQLite که این راهنما بر آن متکی است، حذف میکند. هنوز هیچ نسخه تگشدهای شامل این تغییرات نیست، اما به محض انتشار، مسیر webhook مربوط به GitHub که در بالا ذکر شد، پس از آن ارتقا دیگر کار نخواهد کرد.
FAQ
آیا برای اجرای OpenTag به VPS نیاز دارم یا لپتاپ کافی است؟
برای Slack بهتنهایی، لپتاپ کافی است؛ زیرا Socket Mode یک WebSocket خروجی باز میکند و نیازی به پورت ورودی ندارد. اما وضعیت GitHub متفاوت است. Webhookهای مخزن، درخواستهای HTTP ورودی را به آدرسی که یکبار ثبت کردهاید ارسال میکنند؛ بنابراین آدرس باید ثابت بماند و در زمانی که شما خواب هستید نیز پاسخگو باشد. حساب رایگان ngrok اکنون دامنه توسعهدهنده را در طول راهاندازی مجدد ثابت نگه میدارد، بنابراین آدرس حفظ میشود. اما تونل اینطور نیست، زیرا فقط زمانی پاسخ میدهد که لپتاپ روشن و agent در حال اجرا باشد. وقتی اینطور نباشد، تحویلهای GitHub با شکست مواجه میشوند که بهصورت ورودیهای ناموفق در تب Recent Deliveries مخزن و سکوت در thread نمایش داده میشود. یک VPS با نام DNS ثابت و گواهی معتبر، این مشکل را برطرف میکند.
OpenTag به چه مجوزهایی در GitHub نیاز دارد؟
یک personal access token با دسترسی محدود (fine-grained) که به Only select repositories محدود شده باشد، با مجوزهای Issues: Read and write و Pull requests: Read and write. این مجوزها برای خواندن منشنها و پاسخدهی در thread کافی است. دسترسی نوشتن به کد (code write) نیاز نیست، مگر اینکه preparePullRequestBranch را روی true تنظیم کنید تا OpenTag شاخهها (branches) را push کند. یک githubApplyToken جداگانه نیز وجود دارد تا توکنِ نوشتنِ کد از توکنِ کامنتگذاری جدا بماند. از توکنهایی که دسترسی all-repositories با مجوز contents write دارند اجتناب کنید، زیرا هر کسی که بتواند در هر یک از آن مخازن کامنت بگذارد، میتواند عاملی (agent) را هدایت کند که قابلیت commit کردن دارد.
چگونه اجرای اشتباه یک عملیات را متوقف کنم؟
Slack برای همین منظور یک دستور /stop دارد. روی سرور، opentag status نشان میدهد چه چیزی در حال اجراست و opentag service stop دیمون را متوقف میکند که باعث پایان کل pipeline میشود، نه فقط یک اجرا. برای جلوگیری از نیاز به هر دو، approvalMode را روی ask تنظیم کنید تا اجراها پیش از ایجاد هر تغییری منتظر تأیید انسان بمانند و preparePullRequestBranch را روی false بگذارید تا یک اجرای ناموفق بهجای ایجاد شاخه، فقط یک کامنت تولید کند.
چرا webhook من خطای 502 میدهد در حالی که thread ساکت است؟
خطای 502 از سمت nginx است، نه OpenTag، و به این معنی است که پروکسی نتوانسته به listener متصل شود. /var/log/nginx/error.log مقدار connect() failed (111: Connection refused) while connecting to upstream را نشان خواهد داد. یا listener متوقف شده است، یا روی پورتی متفاوت از آنچه در خط proxy_pass تعریف شده، قرار دارد. دستور sudo ss -tlnp را اجرا کنید و تأیید کنید که چیزی روی 127.0.0.1:3050 برای GitHub و 127.0.0.1:3040 برای Slack در حال گوش دادن است، سپس برای بررسی bindingها و executorها، opentag doctor را اجرا کنید.