OpenTag সেলফ-হোস্ট করার নিয়ম ও গাইড
আপনার VPS-এ OpenTag সেটআপ করে Slack ও GitHub মেনশন সরাসরি কোডিং এজেন্টে পাঠান। TLS ইনগ্রেস, ওয়েবহুক সিগনেচার যাচাই এবং টোকেন স্কোপ কনফিগার করার পূর্ণাঙ্গ নির্দেশিকা এখানে দেখুন।
যখন আপনি কোনো এজেন্টকে মেনশন করেন তখন OpenTag যা করে
OpenTag একটি Slack থ্রেড বা GitHub ইস্যু-তে করা @mention-কে আপনার নিজস্ব মেশিনে চলমান একটি কোডিং এজেন্ট রান-এ রূপান্তরিত করে। কেউ যখন কোনো ইস্যু-তে @opentag investigate this কমেন্ট করে, তখন একটি লিসেনার প্ল্যাটফর্ম ইভেন্টটি গ্রহণ করে, এর সিগনেচার যাচাই করে, মেনশনটিকে একটি বাউন্ড প্রজেক্টের সাথে মিলিয়ে নেয়, লোকাল চেকআউটের বিপরীতে একটি কোডিং এজেন্ট চালু করে এবং ফলাফলটি একই থ্রেডে পোস্ট করে।
প্রজেক্টটি MIT লাইসেন্সভুক্ত এবং amplifthq/opentag-এ রয়েছে। আগস্ট 2026 অনুযায়ী সর্বশেষ ট্যাগ করা রিলিজটি হলো v0.9.0, যা 28 জুলাই 2026-এ প্রকাশিত হয়েছে এবং এটি একটি npm প্যাকেজ হিসেবে রিলিজ হয়। এর কোনো অফিসিয়াল কন্টেইনার ইমেজ নেই, তাই আপনি যে ভার্সনটি পিন করবেন তা হলো npm ভার্সন। নিচের প্রতিটি কমান্ড এটিকেই পিন করে।
GitHub-এর দিকের বিষয়গুলোর কারণে এটি ল্যাপটপ প্রজেক্টের চেয়ে একটি VPS প্রজেক্ট হিসেবে বেশি কার্যকর। GitHub আপনার রেজিস্টার করা একটি URL-এ HTTP রিকোয়েস্ট পাঠানোর মাধ্যমে রিপোজিটরি ইভেন্ট ডেলিভার করে, তাই সেই URL-টিকে পরবর্তী দিনগুলোতেও একই ঠিকানায় সচল থাকতে হয়।
চারটি চলমান অংশ
লিসেনার (The listener) প্ল্যাটফর্ম ইভেন্ট গ্রহণ করে এবং প্রতিটি প্ল্যাটফর্মের নিজস্ব লিসেনার থাকে। GitHub লিসেনার হলো পোর্ট 3050-এ অবস্থিত একটি HTTP এন্ডপয়েন্ট, যার পাথ হলো /github/webhooks। Slack Events API লিসেনার পোর্ট 3040-এ /slack/events পাথে থাকে। Slack-কে Socket Mode-এও চালানো যায়, যেখানে অ্যাপটি একটি আউটবাউন্ড WebSocket খোলে এবং কোনো ইনবাউন্ড পোর্টের প্রয়োজন হয় না।
ডিসপ্যাচার (The dispatcher) হলো কোঅর্ডিনেটর। এটি ডিফল্টভাবে পোর্ট 3030-এ লিসেন করে, OPENTAG_DATABASE_PATH দ্বারা নির্ধারিত লোকাল ডাটাবেস ফাইলে রান স্টেট বজায় রাখে এবং প্রতিটি রানের জন্য একটি অডিট ট্রেইল রেকর্ড করে। বক্সের বাইরের কোনো কিছুরই এই পোর্টে পৌঁছানো উচিত নয়।
রানার (The runner) হলো লোকাল ডেমোন। এটি কাজের জন্য পোল (poll) করে, একটি রান দাবি করে, সেটির ওপর লিজ ধরে রাখে এবং রানটি সক্রিয় থাকা অবস্থায় ডিফল্টভাবে প্রতি 15 সেকেন্ডে একটি হার্টবিট পাঠায়। এটি এমন কোনো দাবি করা রান প্রত্যাখ্যান করে যার প্রজেক্ট টার্গেট অনুপস্থিত অথবা এর নিজস্ব কনফিগারেশনে থাকা অ্যালাউ-লিস্টের বাইরে। এই চেকের মাধ্যমেই GitHub ইভেন্টকে আপনার এজেন্ট এমন কোনো রিপোজিটরিতে নির্দেশ করা থেকে আটকানো হয় যা আপনি বাইন্ড করেননি।
এক্সিকিউটর (The executor) হলো স্বয়ংক্রিয় কোডিং এজেন্ট। OpenTag এটিকে ACP (agent client protocol)-এর মাধ্যমে চালু করে, যা স্ট্যান্ডার্ড ইনপুট এবং আউটপুটের মাধ্যমে পরিচালিত একটি JSON-RPC প্রোটোকল। ফলে এজেন্টটি OpenTag-এর দেওয়া একটি ওয়ার্কিং ডিরেক্টরির ভেতরে চাইল্ড প্রসেস হিসেবে চলে। বিল্ট-ইন নামগুলোর মধ্যে রয়েছে echo, codex, claude-code, cursor, opencode, hermes এবং openclaw। echo দিয়ে শুরু করুন, যা হলো এক্সাম্পল কনফিগারেশনের সাথে আসা এক্সিকিউটর। কারণ কোনো মডেল আপনার কোড স্পর্শ করার আগেই এটি নিশ্চিত করে যে পুরো পাথটি সঠিকভাবে কাজ করছে।
এই ক্রমটি কখনোই পরিবর্তিত হয় না: প্ল্যাটফর্ম ইভেন্ট, সিগনেচার চেক, রান রেকর্ড, ক্লেইম, এজেন্ট, এবং থ্রেডে রিপ্লাই।
কেন শুধু একটি ল্যাপটপ এবং একটি টানেল যথেষ্ট নয়
GitHub সেটআপ গাইড আপনাকে ngrok http 3050 কমান্ডটি চালাতে এবং টানেল হোস্টটিকে রিপোজিটরি ওয়েবহুকে পেস্ট করতে বলে। এটি প্রথম দশ মিনিটের জন্য কাজ করে। একটি ফ্রি টানেল হোস্ট প্রতিবার প্রসেস রিস্টার্ট হওয়ার সাথে সাথে পরিবর্তিত হয় এবং ল্যাপটপ স্লিপ মোডে গেলে এটি আর কাজ করে না। GitHub পুরনো পেলোড URL-টি ধরে রাখে এবং বারবার সেটি ব্যবহারের চেষ্টা করে, ফলে ওয়েবহুক সেটিংসের Recent Deliveries ট্যাবে ব্যর্থতার তালিকা জমা হতে থাকে অথচ থ্রেডটি নীরব থাকে। এক সপ্তাহ পর্যন্ত কেউ এটি লক্ষ্য করে না, কারণ কোনো কাজ না করা ওয়েবহুক দেখতে অনেকটা এমন একটি বটের মতো যার কথা কেউ উল্লেখই করেনি।
একটি VPS এই দুটি সমস্যার সমাধান করে। এর DNS নাম পরিবর্তিত হয় না, তাই একবার পেস্ট করা পেলোড URL-টি সবসময় সঠিক থাকে। মেশিনটি স্লিপ মোডে যায় না, তাই রাত 02:00 টায় আসা কোনো কমেন্টের উত্তরও পাওয়া সম্ভব। প্রথমে সার্ভারটি সঠিকভাবে সেটআপ করুন: নতুন VPS-এ প্রথম দশ মিনিট গাইডটিতে লগইন ইউজার এবং ফায়ারওয়াল সম্পর্কে আলোচনা করা হয়েছে যা এই গাইডের জন্য প্রয়োজনীয়।
Slack এক্ষেত্রে ব্যতিক্রম। Socket Mode-এ এটি বাইরের দিকে সংযোগ স্থাপন করে এবং কোনো পাবলিক URL-এর প্রয়োজন হয় না, তাই শুধুমাত্র Slack-ভিত্তিক ডিপ্লয়মেন্ট ক্লোজড রাখা সম্ভব। GitHub-এর এমন কোনো বিকল্প নেই। রিপোজিটরি ওয়েবহুকগুলো হলো ইনবাউন্ড HTTP, যার অর্থ একটি পাবলিক এন্ডপয়েন্ট প্রয়োজন, আর তার মানে হলো TLS (transport layer security) এবং একটি সিগনেচার চেক থাকা আবশ্যক।
Ubuntu-তে pinned release থেকে OpenTag self-host করা
OpenTag v0.9.0-এর জন্য Node.js 22 বা তার পরবর্তী সংস্করণ প্রয়োজন। 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 -vnode -v কমান্ডটি অবশ্যই v22 বা তার চেয়ে বেশি সংস্করণ প্রদর্শন করবে। Node 20-এ ইনস্টল করলে এটি একটি EBADENGINE সতর্কবার্তা দেয় এবং CLI চালু হওয়ার পর ব্যর্থ হতে পারে।
সার্ভিসটির জন্য একটি আলাদা অ্যাকাউন্ট তৈরি করুন। এজেন্ট এই ইউজারের অনুমতি নিয়ে চলে, তাই এটি আপনার লগইন ইউজার হওয়া উচিত নয় এবং root ইউজারও হওয়া উচিত নয়। VPS-এ Least privilege ইউজার অংশে কেন এই পৃথকীকরণ গুরুত্বপূর্ণ তা আলোচনা করা হয়েছে।
sudo adduser --disabled-password --gecos "" opentag
sudo loginctl enable-linger opentag
sudo npm install -g @opentag/cli@0.9.0
command -v opentagcommand -v opentag কমান্ডটি /usr/bin/opentag-এর মতো একটি পাথ প্রদর্শন করবে। Linux-এ linger সেটিংটি গুরুত্বপূর্ণ: OpenTag তার ব্যাকগ্রাউন্ড সার্ভিস systemd-এর মাধ্যমে ইনস্টল করে, এবং linger ছাড়া কোনো ইউজার সার্ভিস আপনার SSH সেশন বন্ধ হওয়ার সাথে সাথেই বন্ধ হয়ে যায়।
সেই ইউজারের অধীনে সেটআপ চালান।
sudo -iu opentag opentag setupসেটআপ ছয়টি বিষয় জানতে চাইবে: CLI ভাষা, লোকাল লিসেনিং অ্যাড্রেস, কোডিং এজেন্ট, কাজ করার জন্য লোকাল প্রজেক্ট, সেভ করার জন্য প্ল্যাটফর্ম ক্রেডেনশিয়াল এবং কীভাবে চালাতে হবে। লিসেনিং অ্যাড্রেস 127.0.0.1-এ রাখুন, কারণ nginx TLS টার্মিনেট করে সেখানে ফরোয়ার্ড করে, তাই লিসেনারদের বাইরে থেকে সরাসরি অ্যাক্সেসযোগ্য হওয়ার প্রয়োজন নেই। GitHub-এর জন্য এটি owner/repo ফরম্যাটে রিপোজিটরির নাম, pull request খোলার অনুমতি, ওয়েবহুক পোর্ট (ডিফল্ট 3050) এবং টোকেন জানতে চাইবে। শেষে ব্যাকগ্রাউন্ড সার্ভিস মোড নির্বাচন করুন। যদি আপনার কাছে আগে থেকেই কনফিগারেশন থাকে এবং প্রম্পট ছাড়াই সার্ভিস ইনস্টল করতে চান, তবে opentag setup --service কমান্ডটি ব্যবহার করুন।
কনফিগারেশন /home/opentag/.config/opentag/config.json-এ এবং রানটাইম স্টেট /home/opentag/.local/state/opentag-এ জমা হয়। সেটআপ ফাইলটি লেখার পর এই কি (key) গুলো হাতে যাচাই করে নেওয়া ভালো।
{
"runnerId": "runner_local",
"dispatcherUrl": "http://localhost:3030",
"runnerToken": "...",
"approvalMode": "ask",
"repositories": []
}পুরানো শেয়ারড pairingToken-এর পরিবর্তে runner-scoped bearer টোকেন runnerToken ব্যবহার করা শ্রেয়। কনফিগারেশন ফাইলে ক্রেডেনশিয়ালগুলো প্লেইন টেক্সট হিসেবে থাকে, যদি না আপনি সেগুলোকে secret reference দিয়ে প্রতিস্থাপন করেন, যা স্টার্টআপের সময় এনভায়রনমেন্ট বা ডিস্কের কোনো ফাইল থেকে মান পড়ে নেয়। যেকোনো ক্ষেত্রেই, এই ফাইলটি সার্ভারের সবচেয়ে সংবেদনশীল অংশ: এর মোড 600 রাখুন, মালিকানা opentag-এর অধীনে রাখুন এবং কখনোই কোনো git রিপোজিটরির ভেতরে রাখবেন না। এ বিষয়ে বিস্তারিত আলোচনা AI এজেন্ট থেকে সিক্রেট দূরে রাখা অংশে রয়েছে।
কোনো কিছু এক্সপোজ করার আগে ইনস্টলেশন যাচাই করুন।
sudo -iu opentag opentag doctor
sudo -iu opentag opentag statusopentag doctor কমান্ডটি ডিসপ্যাচার, বাইন্ডিং, চেকআউট এবং এক্সিকিউটরগুলো পরীক্ষা করে। opentag status কনফিগারেশন এবং রানটাইম স্টেট প্রিন্ট করে, এবং রান তৈরি হয়ে গেলে এটি একটি নির্দিষ্ট রানের জন্য স্কোপ করা যায়। কোনো প্ল্যাটফর্মকে এই সার্ভারের সাথে যুক্ত করার আগে doctor যা রিপোর্ট করে তা ঠিক করুন।
TLS-কে সামনে রাখুন এবং কেবল দুটি পাথ উন্মুক্ত করুন
Nginx TLS টার্মিনেট করে এবং সুনির্দিষ্টভাবে দুটি পাথ ফরোয়ার্ড করে। অন্য সবকিছু 404 রিটার্ন করে, তাই কোনো স্ক্যানার যদি হোস্টটিকে খুঁজেও পায়, তবে এর পেছনে কী চলছে তা জানতে পারবে না।
/etc/nginx/sites-available/opentag-এ একটি সাধারণ port 80 সার্ভার ব্লক লিখুন যেখানে নিচের দুটি লোকেশন থাকবে, এরপর 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 প্রিন্ট করে, এবং এটিই টাইপো এবং রিলোডের মাঝে একমাত্র সুরক্ষা যা সাইটটিকে ডাউন হওয়া থেকে বাঁচায়। Ubuntu 24.04-এ Nginx সহ Certbot রিনিউয়াল এবং ACME (automatic certificate management environment) চ্যালেঞ্জ কেন ব্যর্থ হয় তা নিয়ে আলোচনা করে। সম্পন্ন ব্লকটি দেখতে এমন হয়।
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/-এর নিচের প্রতিটি পাথ ফরোয়ার্ড হয়ে যাবে, যা লিসেনারের প্রয়োজনের তুলনায় অনেক বেশি সারফেস এরিয়া উন্মুক্ত করে।
ফায়ারওয়ালটি সংকীর্ণ রাখুন।
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw status3030, 3040 এবং 3050 পোর্টগুলো কখনোই খুলবেন না। নিশ্চিত করুন যে এগুলো প্রতিটি ইন্টারফেসের পরিবর্তে শুধুমাত্র loopback-এ বাইন্ড করা আছে।
sudo ss -tlnpপ্রতিটি OpenTag লাইন 127.0.0.1:3030 বা অনুরূপ হওয়া উচিত। যদি কোনো লাইনে 0.0.0.0:3050 থাকে, তবে এর অর্থ লিসেনারটি পুরো ইন্টারনেটের জন্য উন্মুক্ত এবং শুধুমাত্র ufw একে আটকে রেখেছে, যা একটি ফায়ারওয়াল ভুলের কারণে বড় নিরাপত্তা ঝুঁকি তৈরি করতে পারে। ufw ফায়ারওয়াল পরিচিতি ব্যাখ্যা করে যে ডিফল্ট ডিনাই (deny) আসলে কী কাজ করে।
দুটি চেক সামনের দরজার নিরাপত্তা নিশ্চিত করে। curl -I https://opentag.example.com/ কমান্ডটি Nginx থেকে 404 রিটার্ন করে, যা প্রমাণ করে যে সার্টিফিকেটটি বৈধ এবং ক্যাচ-অল (catch-all) বন্ধ আছে। কোনো সিগনেচার ছাড়া /slack/events বা /github/webhooks-এ করা অনুরোধ কখনোই 200 রিটার্ন করা উচিত নয়।
প্রতিটি স্বাক্ষর যাচাই করুন, কারণ URL-টি পাবলিক
যেকোনো ব্যক্তিই এই পেলোড URL খুঁজে পেতে পারে। এটি আপনার রিপোজিটরি সেটিংস, ব্রাউজার হিস্ট্রি বা কোনো টিকিটে পেস্ট করা স্ক্রিনশটে থাকতে পারে। স্বাক্ষরই একমাত্র মাধ্যম যা একটি আসল GitHub ডেলিভারিকে অন্য কারো হাতে টাইপ করা অনুরোধ থেকে আলাদা করে।
GitHub প্রতিটি ডেলিভারিকে webhook secret দিয়ে স্বাক্ষর করে এবং ফলাফলটি x-hub-signature-256 হেডারে পাঠায়। OpenTag সেই হেডারটিকে platforms.github.webhookSecret-এর বিপরীতে যাচাই করে। প্রজেক্টের হার্ডেনিং নোটগুলোতে সরাসরি এই নিয়মটি উল্লেখ করা হয়েছে: /github/webhooks-এ স্বাক্ষরবিহীন সোর্স ইভেন্ট গ্রহণ করবেন না। Slack প্রতিটি অনুরোধকে SLACK_SIGNING_SECRET দিয়ে স্বাক্ষর করে এবং একটি টাইমস্ট্যাম্প অন্তর্ভুক্ত করে, যাতে কোনো ক্যাপচার করা বডি কয়েক ঘণ্টা পরে পুনরায় প্লে (replay) করা না যায়।
এটি এড়িয়ে যাওয়া ছোট কোনো ঝুঁকি নয়। একটি যাচাইহীন এন্ডপয়েন্ট হাতে লেখা issue_comment পেলোড গ্রহণ করতে পারে যাতে @opentag থাকে, এবং তখন OpenTag আপনার টোকেন ব্যবহার করে, আপনার চেকআউটে, একজন অপরিচিত ব্যক্তির নির্দেশনায় একটি কোডিং এজেন্ট চালিয়ে দেবে। এর উত্তর সেই থ্রেডেই চলে যাবে যা নকল পেলোডটিতে উল্লেখ করা হয়েছে।
OpenTag এর উপরে দুটি স্তর যুক্ত করে। সোর্স ডেলিভারিগুলো delivery ID দ্বারা ট্র্যাক করা হয়, তাই একই ইভেন্ট পুনরায় ডেলিভারি করলে দ্বিতীয়বার রান শুরু হয় না। রানার কলগুলো idempotency key গ্রহণ করে, তাই একটি অনুরোধ পুনরায় প্লে করলে অন্য কোনো অডিট ইভেন্ট যুক্ত না করেই সেটি সফল হিসেবে ফিরে আসে।
রেট লিমিটগুলো কনফিগারযোগ্য এবং এগুলো চালু রাখা উচিত। 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 শুধুমাত্র localhost-এর জন্য plain HTTP ব্যবহারের অনুমতি দেয়।
বটটির আসলে কোন কোন টোকেন স্কোপ প্রয়োজন?
GitHub-এ, OpenTag একটি GitHub App-এর পরিবর্তে fine-grained personal access token ব্যবহার করে। ডকুমেন্টেশনে বলা হয়েছে যে App পাথটি বর্তমানে পরিকল্পনার পর্যায়ে রয়েছে এবং এটি ডিফল্ট CLI সেটআপ নয়। এর একটি পরিণাম রয়েছে যা অনেকেই এড়িয়ে যান: বটটি সেই ব্যক্তির নামে মন্তব্য করে যিনি টোকেনটি তৈরি করেছেন। তাই এমন একটি অ্যাকাউন্টের অধীনে এটি তৈরি করুন যেটির নাম প্রতিটি ট্রায়াজ রিপ্লাইতে দেখতে আপনার আপত্তি নেই।
সেটআপ গাইড অনুযায়ী যতটা সম্ভব সীমিত স্কোপ নির্ধারণ করুন। Only select repositories নির্বাচন করুন এবং একটি রিপোজিটরি বেছে নিন। Issues: Read and write এবং Pull requests: Read and write অনুমতি প্রদান করুন। একটি মেনশন পড়ার জন্য এবং থ্রেডে উত্তর দেওয়ার জন্য এটুকুই যথেষ্ট।
কী কী বাদ দেওয়া হয়েছে তা লক্ষ্য করুন: কোডে রাইট অ্যাক্সেস। preparePullRequestBranch ট্রু (true) সেট করা না থাকলে OpenTag কোনো ব্রাঞ্চ পুশ করে না। এছাড়া একটি আলাদা githubApplyToken রয়েছে, যাতে কোড লেখার টোকেন এবং মন্তব্য করার টোকেন একই না হয়। এগুলোকে আলাদা রাখুন এবং রিড-অ্যান্ড-কমেন্ট পাথ কয়েক সপ্তাহ ধরে চলার আগে রাইট টোকেনটি সক্রিয় করবেন না।
যে কনফিগারেশনটি এড়িয়ে চলতে হবে তা হলো All repositories-এর ওপর Contents: Read and write স্কোপসহ একটি টোকেন। এর ফলে ওই রিপোজিটরিগুলোতে মন্তব্য করতে পারে এমন যে কেউ এখন এমন একটি এজেন্টকে নিয়ন্ত্রণ করতে পারবে যার কমিট করার অধিকার রয়েছে, এবং অডিট ট্রেইলে দেখা যাবে যে টোকেনের মালিক এটি করেছেন। এজেন্টটি নির্ভরযোগ্য হয়ে ওঠার পর, প্রতিটি রিপোজিটরির জন্য আলাদাভাবে স্কোপ বাড়ান।
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 URL হবে https://opentag.example.com/github/webhooks, content type হবে application/json এবং secret হবে সেটআপের সময় তৈরি করা সেই secret-টি। শুধুমাত্র Issue comments এবং Pull request review comments সাবস্ক্রাইব করুন, অন্য কিছু নয়।
সেভ করার সাথে সাথেই GitHub একটি ping delivery পাঠাবে। Recent Deliveries ওপেন করে দেখুন অনুরোধটি সার্ভারে পৌঁছেছে কি না। যদি 502 error দেখেন, তার মানে Nginx লিসেনার পর্যন্ত পৌঁছাতে পারছে না; এটি একটি লোকাল সমস্যা, GitHub-এর কোনো সমস্যা নয়।
এখন এটি ব্যবহার করে দেখুন। একটি ইস্যু ওপেন করুন যেখানে কোনো বাগ বর্ণনা করা হয়েছে এবং নিচের কমেন্টটি করুন:
@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 রেসপন্সসহ রেকর্ড হবে। ডিসপ্যাচার একটি রান রেকর্ড করবে। রানার সেটি গ্রহণ করবে এবং হার্টবিট পাঠানো শুরু করবে। এক্সিকিউটর চেকআউট ওপেন করে কাজ শুরু করবে। উত্তরটি একই ইস্যু থ্রেডে কমেন্ট হিসেবে আসবে। sudo -iu opentag opentag status রান চলাকালীন সেটি প্রদর্শন করে, তাই অনুমান না করে আপনি সরাসরি তা পর্যবেক্ষণ করতে পারবেন।
প্রথমবার আসল রান চালানোর আগে approvalMode-কে ask-তে সেট করুন। ask মোডে রানটি পজ হয়ে থাকে এবং কোনো স্টেট পরিবর্তনের আগে মানুষের অনুমোদনের জন্য অপেক্ষা করে। auto এবং autonomous মোডগুলোও রয়েছে, যা পরবর্তীতে ব্যবহার করা যেতে পারে, বিশেষ করে এমন কোনো রিপোজিটরিতে যেখানে আপনি এক মাস ধরে ট্রান্সক্রিপ্টগুলো পড়েছেন।
Slack-এর দিকে, একই রান চ্যানেলে /bind owner/repo দিয়ে শুরু হয়, তারপর একটি মেনশন আসে। বটটি /help, /status, /doctor, /stop এবং /unbind confirm-এরও উত্তর দেয়। OPENTAG_SLACK_BINDING_ADMIN_USER_IDS ব্যবহার করে কারা বাইন্ডিং পরিবর্তন করতে পারবে তা সীমাবদ্ধ করুন; এটি Slack ইউজার আইডিগুলোর একটি কমা-সেপারেটেড তালিকা। কারণ বাইন্ডিং হলো একটি পাবলিক চ্যানেল থেকে আপনার সার্ভারের চেকআউটের ম্যাপিং।
Triage হলো রাউটিংয়ের জন্য একটি ভালো প্রাথমিক ধাপ কারণ এটি শুধুমাত্র রিড করে, কোনো কিছু রাইট করে না এবং এর উত্তর যাচাই করা সহজ। এর পরের ধাপ হলো Review, যেখানে এজেন্ট ইস্যুর পরিবর্তে একটি diff-এ কমেন্ট করে: একটি সেলফ-হোস্টেড পুল রিকোয়েস্ট রিভিউ এজেন্ট হলো একই আর্কিটেকচার যা পুল রিকোয়েস্টের দিকে নির্দেশ করা থাকে। আপনি যদি চান এজেন্ট কাজ করার সময় আপনার নিজস্ব সিস্টেমে অ্যাক্সেস করুক, তবে সেটি একটি VPS-এ MCP সার্ভার-এর কাজ।
সবার সামনে এজেন্ট ভুল করলে কী হয়?
এটি ভুল করবেই। আসল প্রশ্ন হলো এর মাশুল কতটুকু।
একটি পাবলিক ইস্যুতে ভুল উত্তর দেওয়া মানে আপনার দলের পরিচিত কোনো নামের অধীনে মন্তব্য করা, এবং পোস্ট হওয়ার সাথে সাথেই GitHub তা সাবস্ক্রাইব করা সবাইকে ইমেইল করে দেয়। মন্তব্য মুছে ফেললেও ইমেইলটি আর ফেরত আনা যায় না। Slack নোটিফিকেশনের ক্ষেত্রেও একই কথা প্রযোজ্য। তাই উত্তরের জন্য ব্যক্তিগতভাবে সঠিক হওয়ার চেয়ে প্রকাশ্যে ভুল হওয়ার বিষয়টি মাথায় রেখে পরিকল্পনা করুন।
চারটি উপায় ক্ষতির পরিমাণ সীমিত রাখে, এবং আপনি কী প্রম্পট লিখছেন তার চেয়ে এগুলো বেশি গুরুত্বপূর্ণ।
askমোডে চালান, যাতে এজেন্ট প্রস্তাব দেয়, একজন মানুষ অনুমোদন দেয়, এবং একটি ভুল পরিকল্পনার মাশুল হয় মাত্র একটি ক্লিক।preparePullRequestBranch-কে এর ডিফল্ট মান false-এ রাখুন, যাতে একটি ভুল রানের সবচেয়ে খারাপ ফলাফল হয় একটি ভুল মন্তব্য, কোনো ভুল ব্রাঞ্চ নয়।- শুরুতে একটি রিপোজিটরি এবং একটি চ্যানেল যুক্ত করুন। রানার এমন যেকোনো রান প্রত্যাখ্যান করে যার প্রজেক্ট টার্গেট তার লোকাল অ্যালাউ-লিস্টের বাইরে থাকে, তাই একটি আনবাউন্ড রিপোজিটরি এজেন্টকে নিজের ভেতর টেনে নিতে পারে না।
- কমেন্টিং টোকেনকে যেকোনো অ্যাপ্লাই টোকেন থেকে আলাদা রাখুন, যাতে রাইট অ্যাক্সেস বাতিল করলে ট্রায়াজ (triage) ব্যবস্থা অকেজো না হয়ে যায়।
ভুল পথে যাওয়া কোনো রানের জন্য Slack-এ একটি /stop কমান্ড রয়েছে। প্রতিটি রান একটি অডিট রেকর্ড রেখে যায় যাতে সেই মেনশনটি থাকে যা রানটি শুরু করেছিল এবং এজেন্ট কী করেছিল তা লেখা থাকে; রানটি কোথায় ভুল হয়েছে তা বোঝার জন্য পরে এটিই পড়তে হয়।
কনফিগারেশনের মতোই সামাজিক দিকটিও গুরুত্বপূর্ণ। বটটিকে এমন একটি চ্যানেলে রাখুন যেখানে মানুষ একটি মেশিনের উপস্থিতি আশা করে এবং জানে যে এটি ভুল করতে পারে। চল্লিশজন মানুষের চ্যানেলে আত্মবিশ্বাসের সাথে একটি ভুল উত্তর দেওয়া, যারা মনে করছে এটি কোনো মানুষ যাচাই করেছে, তা ট্রায়াজ থেকে পাওয়া সুবিধার চেয়ে বেশি ক্ষতির কারণ হতে পারে। চ্যানেলের ডেসক্রিপশনে লিখে রাখুন বটের মালিক কে এবং কে এর আউটপুট যাচাই করে।
ব্যাকআপ, আপগ্রেড এবং পিন করা
দুটি পাথ সবকিছু ধারণ করে: /home/opentag/.config/opentag/config.json এবং /home/opentag/.local/state/opentag। প্রথমটিতে আপনার ক্রেডেনশিয়াল থাকে, দ্বিতীয়টিতে রান হিস্ট্রি এবং ডাটাবেস ফাইল থাকে। উভয়কেই mode 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 ভার্সনে থাকতে হবে। জুলাই 2026 পর্যন্ত ইতিহাস দেখলে বোঝা যায় মাসে বেশ কয়েকটি রিলিজ আসে, তাই প্রতিটি আপগ্রেডের আগে রিলিজ নোট পড়া জরুরি।
FAQ
OpenTag চালানোর জন্য কি আমার একটি VPS প্রয়োজন, নাকি ল্যাপটপই যথেষ্ট?
শুধুমাত্র Slack-এর জন্য ল্যাপটপই যথেষ্ট, কারণ Socket Mode একটি outbound WebSocket খোলে এবং এর জন্য কোনো inbound port-এর প্রয়োজন হয় না। GitHub-এর ক্ষেত্রে বিষয়টি ভিন্ন। Repository webhook একটি নির্দিষ্ট URL-এ inbound HTTP-এর মাধ্যমে ডেটা পাঠায়, তাই ঠিকানাটি সবসময় একই থাকতে হয় এবং আপনার অনুপস্থিতিতেও সেটিকে সাড়া দিতে হয়। ফ্রি অ্যাকাউন্টের tunnel host প্রতিবার রিস্টার্টের পর পরিবর্তিত হয়ে যায়, ফলে GitHub পুরনো ঠিকানাতেই ডেটা পাঠাতে থাকে। এতে repository-এর Recent Deliveries ট্যাবে ব্যর্থ এন্ট্রি দেখা যায় এবং থ্রেডে কোনো সাড়া পাওয়া যায় না। একটি ফিক্সড DNS নাম এবং certificate-সহ একটি VPS এই উভয় সমস্যার সমাধান করে।
OpenTag-এর জন্য GitHub-এর কোন কোন permission প্রয়োজন?
Only select repositories-এ সীমাবদ্ধ একটি fine-grained personal access token প্রয়োজন, যার সাথে Issues: Read and write এবং Pull requests: Read and write পারমিশন থাকতে হবে। এটি মেনশন পড়া এবং থ্রেডে উত্তর দেওয়ার জন্য যথেষ্ট। যদি আপনি preparePullRequestBranch-কে true সেট না করেন, তবে কোড লেখার জন্য কোনো write access-এর প্রয়োজন নেই। কোড লেখার টোকেন এবং কমেন্ট করার টোকেন আলাদা রাখার জন্য একটি পৃথক githubApplyToken রয়েছে। সব repository-তে write access আছে এমন টোকেন ব্যবহার করা থেকে বিরত থাকুন, কারণ সেক্ষেত্রে যে কেউ ওই repository-গুলোতে কমেন্ট করে এমন একটি এজেন্টকে নিয়ন্ত্রণ করতে পারে যা কোড কমিট করতে সক্ষম।
ভুল পথে চলা কোনো রান (run) আমি কীভাবে থামাব?
Slack-এ ঠিক এই কাজের জন্য একটি /stop কমান্ড রয়েছে। সার্ভারে, opentag status কমান্ডটি বর্তমানে কী চলছে তা দেখায় এবং opentag service stop কমান্ডটি ডেমোন (daemon) বন্ধ করে দেয়, যা একটি নির্দিষ্ট রান নয় বরং পুরো পাইপলাইনটিই বন্ধ করে দেয়। এই কমান্ডগুলোর প্রয়োজন এড়াতে, approvalMode-কে ask-এ সেট করুন যাতে কোনো কিছু পরিবর্তন করার আগে রানগুলো মানুষের অনুমোদনের জন্য অপেক্ষা করে। এছাড়া preparePullRequestBranch-কে false রাখুন, যাতে কোনো ভুল রান হলে তা ব্রাঞ্চ তৈরি না করে শুধুমাত্র একটি কমেন্ট তৈরি করে।
আমার webhook কেন 502 এরর দেয় এবং থ্রেড কেন নীরব থাকে?
502 এররটি nginx থেকে আসে, OpenTag থেকে নয়। এর অর্থ হলো প্রক্সি লিসেনার (listener)-এর সাথে সংযোগ স্থাপন করতে পারছে না। /var/log/nginx/error.log কমান্ডটি connect() failed (111: Connection refused) while connecting to upstream প্রদর্শন করবে। এর মানে হয় লিসেনারটি বন্ধ আছে, অথবা এটি proxy_pass লাইনে উল্লিখিত পোর্ট থেকে ভিন্ন কোনো পোর্টে চলছে। sudo ss -tlnp কমান্ডটি চালান এবং নিশ্চিত করুন যে GitHub-এর জন্য 127.0.0.1:3050 এবং Slack-এর জন্য 127.0.0.1:3040 পোর্টে কিছু লিসেন করছে কি না। এরপর বাইন্ডিং এবং এক্সিকিউটরগুলোর জন্য opentag doctor কমান্ডটি চালান।