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) করে, একটি রান দাবি করে, সেটির ওপর লিজ (lease) ধরে রাখে এবং রানটি সক্রিয় থাকা অবস্থায় ডিফল্টভাবে প্রতি 15 সেকেন্ডে একটি হার্টবিট পাঠায়। এটি এমন কোনো দাবি করা রান প্রত্যাখ্যান করে যার প্রজেক্ট টার্গেট অনুপস্থিত অথবা এর নিজস্ব কনফিগারেশনে থাকা অ্যালাউ-লিস্টের বাইরে। এই চেকের মাধ্যমেই GitHub ইভেন্টকে এমন কোনো রিপোজিটরিতে নির্দেশ করা থেকে আটকানো হয় যা আপনি বাইন্ড করেননি।
executor নিজেই coding agent। OpenTag এটি ACP (agent client protocol)-এর মাধ্যমে চালু করে। ACP হলো standard input ও output ব্যবহারকারী একটি JSON-RPC protocol। তাই OpenTag যে working directory দেয়, agent সেই directory-র ভেতরে child process হিসেবে চলে।
Built-in নামগুলোর মধ্যে echo, codex, claude-code, cursor, opencode, hermes এবং openclaw রয়েছে। echo দিয়ে শুরু করুন। উদাহরণ configuration-এ এটিই ব্যবহৃত executor। Model আপনার code পরিবর্তন করার আগে এটি পুরো workflow কাজ করছে কি না যাচাই করে।
Prompt পড়া, tools call করা এবং কাজ শেষ হয়েছে কি না নির্ধারণ করার loop এখনও যদি আপনার কাছে black box হয়, আগে নিজে একটি ছোট agent loop লিখলে এই pipeline-এর failure mode বোঝা অনেক সহজ হবে।
এই ক্রমটি কখনোই পরিবর্তিত হয় না: প্ল্যাটফর্ম ইভেন্ট, সিগনেচার চেক, রান রেকর্ড, ক্লেইম, এজেন্ট, থ্রেডে রিপ্লাই।
কেন ল্যাপটপ এবং টানেল যথেষ্ট নয়
GitHub সেটআপ গাইড আপনাকে ngrok http 3050 চালাতে এবং টানেল হোস্টটিকে রিপোজিটরি ওয়েবহুকে পেস্ট করতে বলে। এটি প্রথম দশ মিনিটের জন্য কাজ করে। একটি ফ্রি টানেল হোস্ট প্রতিবার প্রসেস রিস্টার্ট হওয়ার সময় পরিবর্তিত হয় এবং ল্যাপটপ স্লিপ মোডে গেলে এটি আর কাজ করে না। GitHub পুরনো payload URL-টি মনে রাখে এবং বারবার সেখানে অনুরোধ পাঠাতে থাকে, ফলে ওয়েবহুক সেটিংসের Recent Deliveries ট্যাবে ব্যর্থতার তালিকা ভরে যায় এবং থ্রেডটি নিষ্ক্রিয় হয়ে পড়ে। এক সপ্তাহ পর্যন্ত কেউ এটি লক্ষ্য করে না, কারণ একটি ওয়েবহুক যা কোনো কাজ করছে না, তা দেখতে এমন একটি বটের মতোই লাগে যার কথা কেউ উল্লেখ করেনি।
একটি VPS এই দুটি সমস্যার সমাধান করে। DNS নাম পরিবর্তিত হয় না, তাই একবার পেস্ট করা payload URL সবসময় সঠিক থাকে। মেশিনটি স্লিপ মোডে যায় না, তাই রাত 02:00 টায় আসা কোনো কমেন্টের উত্তরও পাওয়া যায়। প্রথমে সার্ভারটি সঠিকভাবে সেটআপ করুন: নতুন VPS-এ প্রথম দশ মিনিট গাইডে লগইন ইউজার এবং ফায়ারওয়াল সম্পর্কে আলোচনা করা হয়েছে যা এই গাইডের জন্য প্রয়োজনীয়।
Slack এক্ষেত্রে ব্যতিক্রম। Socket Mode-এ এটি বাইরের দিকে সংযোগ স্থাপন করে এবং কোনো public URL-এর প্রয়োজন হয় না, তাই শুধুমাত্র Slack-এর জন্য তৈরি ডিপ্লয়মেন্ট ক্লোজড রাখা সম্ভব। GitHub-এর এমন কোনো বিকল্প নেই। রিপোজিটরি ওয়েবহুকগুলো হলো ইনবাউন্ড HTTP, যার অর্থ একটি public endpoint প্রয়োজন, আর তার মানে হলো 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 প্রিন্ট করে, এবং এটিই টাইপো এবং সাইট ডাউন করে দেওয়া রিলোডের মধ্যে একমাত্র রক্ষাকবচ। Certbot on Ubuntu 24.04 with nginx রিনিউয়াল এবং 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 firewall basics ব্যাখ্যা করে যে ডিফল্ট ডিনাই (default 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 হবে সেটআপের সময় তৈরি করা সেই সিক্রেটটি। শুধুমাত্র 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) ওপর কমেন্ট করে: একটি সেলফ-হোস্টেড পুল রিকোয়েস্ট রিভিউ এজেন্ট হলো একই আর্কিটেকচার যা পুল রিকোয়েস্টের দিকে নির্দেশ করা থাকে। আপনি যদি চান এজেন্ট কাজ করার সময় আপনার নিজস্ব সিস্টেমে পৌঁছাক, তবে সেটি MCP servers on a VPS-এর কাজ। ওয়েব সার্চ হলো অন্য একটি সক্ষমতা যা Triage সবসময় চেয়ে থাকে, এবং এজেন্টকে আপনার নিজস্ব SearXNG ইনস্ট্যান্সের সাথে যুক্ত করা সেই লুকআপগুলোকে আপনার নিজস্ব হার্ডওয়্যারে সীমাবদ্ধ রাখে, তবে এর বিনিময়ে একটি অতিরিক্ত চ্যানেল তৈরি হয় যার মাধ্যমে অপরিচিত কারো টেক্সট এজেন্টের কাছে পৌঁছাতে পারে।
সবার সামনে এজেন্ট ভুল করলে কী হয়?
এটি ভুল করবেই। আসল প্রশ্ন হলো এর মাশুল কত।
একটি পাবলিক ইস্যুতে ভুল উত্তর দেওয়া মানে এমন একটি মন্তব্য যা আপনার দলের পরিচিত নামে পোস্ট হয় এবং পোস্ট হওয়ার সাথে সাথেই 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 সুবিধা থাকতে হবে। এটি উল্লেখ (mention) পড়া এবং থ্রেডে উত্তর দেওয়ার জন্য যথেষ্ট। যদি আপনি preparePullRequestBranch-কে true না করেন, তবে কোড লেখার জন্য write access-এর প্রয়োজন নেই। কোড পুশ করার জন্য একটি আলাদা githubApplyToken রয়েছে, যাতে কোড লেখার token এবং মন্তব্য করার token আলাদা থাকে। সব repository-তে write access আছে এমন token ব্যবহার করা এড়িয়ে চলুন, কারণ সেক্ষেত্রে যে কেউ ওই repository-গুলোতে মন্তব্য করতে পারলে এমন একটি এজেন্টকে নিয়ন্ত্রণ করতে পারবে যা commit করতে সক্ষম।
ভুল পথে চলা একটি run আমি কীভাবে থামাব?
Slack-এ ঠিক এই কাজের জন্য একটি /stop কমান্ড রয়েছে। সার্ভারে, opentag status কমান্ডটি বর্তমানে কী চলছে তা দেখায় এবং opentag service stop কমান্ডটি daemon-কে থামিয়ে দেয়, যা একটি নির্দিষ্ট run-এর পরিবর্তে পুরো pipeline-টি বন্ধ করে দেয়। এই কমান্ডগুলোর প্রয়োজন এড়াতে, approvalMode-কে ask-এ সেট করুন যাতে কোনো কিছু পরিবর্তনের আগে run-টি মানুষের অনুমোদনের জন্য অপেক্ষা করে। এছাড়া preparePullRequestBranch-কে false রাখুন, যাতে কোনো ভুল run হলে তা branch তৈরির পরিবর্তে একটি মন্তব্য তৈরি করে।
আমার webhook কেন 502 error দেখাচ্ছে এবং থ্রেড কেন নীরব থাকছে?
502 error-টি OpenTag থেকে নয়, বরং nginx থেকে আসে। এর অর্থ হলো proxy-টি listener-এর সাথে যোগাযোগ করতে পারছে না। /var/log/nginx/error.log কমান্ডটি চালালে connect() failed (111: Connection refused) while connecting to upstream দেখা যাবে। এর মানে হয় listener বন্ধ আছে, অথবা এটি proxy_pass লাইনে উল্লিখিত port থেকে ভিন্ন কোনো port-এ চলছে। sudo ss -tlnp কমান্ডটি চালিয়ে নিশ্চিত করুন যে GitHub-এর জন্য 127.0.0.1:3050 এবং Slack-এর জন্য 127.0.0.1:3040 port-এ কোনো সার্ভিস লিসেন করছে কি না। এরপর binding এবং executor-এর জন্য opentag doctor কমান্ডটি চালান।