استفادهٔ تیمی و گروه

‏aipager به‌طور پیش‌فرض یک ربات خصوصی است: شما و ربات در یک چت خصوصی، هیچ‌کس دیگر. استفادهٔ تیمی آن را به روی آدم‌های بیشتری باز می‌کند: یک گروه تلگرام که چند برنامه‌نویس در آن سشن‌ها را می‌گردانند، چت خصوصی آدم‌های دیگر با ربات، یا هر دو. هر چت اعضای خودش را دارد و هر عضو نقشی دارد که تعیین می‌کند آنجا چه کاری می‌تواند بکند: پیام بفرستد، به سؤال‌ها و درخواست‌های اجازهٔ Claude جواب بدهد، سشن‌ها را مدیریت کند، یا فقط نگاه کند.

سورس در GitHub ↖این صفحه ترجمهٔ صفحهٔ انگلیسی است؛ اگر جایی با هم فرق داشتند، صفحهٔ انگلیسی درست است. انگلیسی

‏aipager به‌طور پیش‌فرض یک ربات خصوصی است: شما و ربات در یک چت خصوصی، هیچ‌کس دیگر. استفادهٔ تیمی آن را به روی آدم‌های بیشتری باز می‌کند: یک گروه تلگرام که چند برنامه‌نویس در آن سشن‌ها را می‌گردانند، چت خصوصی آدم‌های دیگر با ربات، یا هر دو. هر چت اعضای خودش را دارد و هر عضو نقشی دارد که تعیین می‌کند آنجا چه کاری می‌تواند بکند: پیام بفرستد، به سؤال‌ها و درخواست‌های اجازهٔ Claude جواب بدهد، سشن‌ها را مدیریت کند، یا فقط نگاه کند.

استفادهٔ تیمی اختیاری است. نصبی که فقط چت خصوصی خودتان را دارد مثل قبل کار می‌کند.

با دقت تصمیم بگیرید#

اضافه کردن یک کاربر تلگرام به یک چت به او اجازهٔ اجرای کد روی کامپیوتری که aipager رویش اجرا می‌شود را می‌دهد. بسته به نقشش می‌تواند:

  • پیام‌هایی بفرستد که Claude آن‌ها را به دستورهای shell، ویرایش فایل و درخواست‌های شبکه تبدیل می‌کند؛
  • به درخواست‌های اجازه جواب بدهد (اجازه بده / رد کن). ‎~/.claude/settings.json شما هنوز تعیین می‌کند Claude دربارهٔ کدام ابزارها بپرسد، ولی هر کسی که نقشش اجازهٔ تأیید می‌دهد می‌تواند «اجازه بده» را بزند؛
  • سشن‌ها را شروع، متوقف، بسته و عوض کند.

با فهرست اعضا همان‌طور رفتار کنید که با دسترسی SSH به کامپیوتر. لاگ ممیزی (‎~/.claude/aipager-audit.jsonl) ثبت می‌کند چه کسی چه کرد، ولی فقط بعد از اینکه اتفاق افتاده.

راه‌اندازی#

همه‌چیز با aipager config تنظیم می‌شود. لازم نیست هیچ فایلی را دستی ویرایش کنید.

اولین اجرا (هنوز تنظیماتی نیست). ویزارد در چهار قدم می‌پرسد:

  1. توکن ربات؛
  2. چت خصوصی خودتان با ربات (خودکار پیدا می‌شود، یا پیستش می‌کنید)؛
  3. اینکه حساب شما owner است یا نه (پیش‌فرض؛ اگر نه بگویید admin می‌شوید که کف ایمنی را برای خودتان روشن نگه می‌دارد)؛
  4. وابستگی‌ها را چک می‌کند و هوک‌های Claude Code را نصب می‌کند.

چت خصوصی شما را به‌عنوان اولین چت می‌نویسد. مود پیش‌فرضی نمی‌پرسد: خلاصه‌اش می‌گوید «New sessions start in Auto mode; owners and admins can choose Full access in Telegram under /settings → New sessions.» (سشن‌های جدید در مود خودکار شروع می‌شوند؛ مالک‌ها و ادمین‌ها می‌توانند در تلگرام زیر ‎/settings ← سشن‌های جدید دسترسی کامل را انتخاب کنند). بعد می‌پرسد «Connected. Add a team group or other people now?» با گزینه‌های Add a group،‏ Add a person (DM) و I'm done.

اجراهای بعدی منوی ویرایش را باز می‌کنند. این منو چت‌هایی را که دارید نشان می‌دهد و این‌ها را پیشنهاد می‌کند:

  • ‏Add a group scope: یک گروه جدید با اعضایش (پایین).
  • ‏Add a DM scope: چت خصوصی یک نفر دیگر با ربات. چت خصوصی یک عضو دارد؛ نقشش را انتخاب می‌کنید (پیش‌فرض user؛‏ owner را فقط برای نصبی یک‌نفره انتخاب کنید، مثل کانتینر شخصی یک دوست). برای نقشی بدون can_manage (مثل user) بعد پوشهٔ root خودش را می‌پرسد، با مقدار پیش‌فرض (‎~/aipager-users/<label>‎). برای کسی که از قبل چت خصوصی‌اش تنظیم شده، ویزارد همین را می‌گوید و چیزی را عوض نمی‌کند: برای عوض کردن نقشش از Edit a member استفاده کنید.
  • ‏Edit a scope: برای یک گروه Add a member؛ برای هر چتی Rename،‏ Edit scope deny_tools،‏ Set the members' root folder (پوشه‌های root را ببینید) و Remove this scope (آخرین چت را نمی‌شود حذف کرد). قبل از حذف یک چت، سشن‌هایش را ببندید: سشن‌های در حال اجرایش همچنان آنجا پیام می‌فرستند و دیگر هیچ چتی از تلگرام به آن‌ها دسترسی ندارد (از خود کامپیوتر، aipager session ls و aipager session kill <name>‎ هنوز می‌توانند).
  • ‏Edit a member:‏ Set role،‏ Edit member deny_tools،‏ Remove member (نه در چت خصوصی، و نه برای آخرین عضو یک گروه). برای یک مالک یا ادمین (یا نقشی از شما با bypass_role_denies)، Edit member deny_tools فقط می‌گوید ابزارهای مسدود روی آن نقش اعمال نمی‌شوند.
  • ‏Test bot reachability،‏ View policy،‏ Re-install Claude Code hooks و Refresh bot token.

اضافه کردن یک گروه#

  1. ربات را به گروه اضافه کنید، بعد Add a group scope (یا در اولین اجرا Add a group) را انتخاب کنید.
  2. آیدی گروه. پیدا کردن خودکار را انتخاب کنید و در گروه ‎/start را بفرستید، یا آیدی را پیست کنید (یک عدد منفی). ویزارد یک پیام آزمایشی می‌فرستد و می‌پرسد رسید یا نه. گروهی که از قبل تنظیم شده همین‌جا با «This group is already set up. Use Edit a scope → Add a member.» می‌ایستد و چیزی عوض نمی‌شود.
  3. یک برچسب برای گروه (در ویزارد و Mini App نشان داده می‌شود).
  4. اول خودتان. وقتی مالک چت خصوصی خودتان هستید، ویزارد می‌پرسد شما را به‌عنوان اولین عضو گروه با نقش owner اضافه کند یا نه (پیش‌فرض بله؛ می‌توانید رد کنید). بدون یک مالک یا ادمین در گروه، هیچ‌کس آنجا نمی‌تواند از دسترسی کامل، ‎/settings یا ‎/update استفاده کند.
  5. بقیهٔ اعضا، یکی‌یکی: چطور پیدایشان کند (پیدا کردن خودکار، یا پیست کردن یک آیدی یا ‎@handle)، یک برچسب (در چت به‌شکل ‎@label نشان داده می‌شود)، و یک نقش (پیش‌فرض user). فهرست نقش‌ها owner را هم دارد، با یک هشدار: مالک کنترل کامل این کامپیوتر را دارد، از جمله تنظیمات aipager، توکن ربات و اطلاعات ورود Claude. فقط به خودتان بدهیدش. admin را به کسانی بدهید که باید در گروه از دسترسی کامل، ‎/settings و ‎/update استفاده کنند. (در چت خصوصی خودش با ربات، هر کسی که می‌تواند پیام بفرستد و به Claude جواب بدهد می‌تواند برای سشن‌های خودش از دسترسی کامل استفاده کند، هر نقشی داشته باشد.)
  6. یک قانون اختیاری: «Block file edits (Write, Edit) for user members in this group? Admins and the owner are not affected.» (ویرایش فایل برای اعضای user این گروه بسته شود؟ ادمین‌ها و مالک تحت تأثیر نیستند.) پیش‌فرض نه است: یک user از قبل فقط داخل پوشهٔ پروژهٔ سشن می‌نویسد. با بله، هر Write و Edit در کار عضوی که نقشش از قانون‌های نقش معاف نیست (user،‏ read_only و نقش‌هایی که بدون bypass_role_denies تعریف می‌کنید) بدون پرسیدن رد می‌شود و کار متوقف می‌شود. آن‌وقت یک ادمین یا مالک باید آن کار را بفرستد.
  7. پوشهٔ root اعضا، با مقدار پیش‌فرض ‎~/aipager-users/group-<label>‎: جایی که اعضای user و read_only گروه سشن‌هایشان را شروع می‌کنند و کار می‌کنند (پوشه‌های root را ببینید).

برای اضافه کردن کسی به گروهی که از قبل تنظیم شده، از Edit a scope ← همان گروه ← Add a member استفاده کنید. همهٔ کسانی که از قبل در گروه‌اند جا و نقششان را نگه می‌دارند.

پیدا کردن آیدی‌ها (خودکار)#

پیدا کردن خودکار یک عضو، جدیدترین پیام از کسی را که هنوز اضافه نشده برمی‌دارد و قبل از استفاده می‌پرسد «Is this the person to add?» (همین کسی است که باید اضافه شود؟) (اگر نه بگویید، از او رد می‌شود). یوزرنیم تلگرامش را به‌عنوان برچسب پیشنهاد می‌کند. در گروه، آن شخص باید ربات را خطاب کند: منشنش کند یا ‎/start بفرستد (ربات در گروه چه پیام‌هایی را می‌خواند را ببینید). ویزارد می‌گوید کجا را نگاه می‌کند:

  • ‏«Watching through the running daemon» (از طریق aipager در حال اجرا): تا وقتی aipager start اجرا می‌شود، aipager همهٔ پیام‌های ربات را می‌گیرد، پس ویزارد چیزی را می‌خواند که aipager در ‎~/.claude/aipager-pending-users.json یادداشت کرده. aipager یادداشت می‌کند چه کسی در گروهی که هنوز در آن کار نمی‌کند ربات را خطاب کرده (آیدی، عنوان و نوع گروه، و آیدی، یوزرنیم و اسم آن شخص)، و هر کسی را که عضو گروهی که در آن کار می‌کند نیست. هیچ‌وقت در گروهی که در آن کار نمی‌کند جواب نمی‌دهد. پیام خصوصی کسی که تنظیم نشده جواب می‌گیرد و یادداشت نمی‌شود، پس برای اضافه کردن چت خصوصی یک نفر وقتی aipager اجرا می‌شود، آیدی‌اش را پیست کنید (یا اول aipager را متوقف کنید).
  • ‏«Watching Telegram directly» (مستقیم از تلگرام): وقتی aipager متوقف است، ویزارد خودش پیام‌های اخیر ربات را از تلگرام می‌گیرد.

چت خصوصی خود شما در اولین اجرا همیشه از تلگرام خوانده می‌شود. پیام یک ادمین ناشناس گروه، یا پیامی که به اسم گروه یا یک کانال فرستاده شده، حساب نمی‌شود: آیدی فرستنده‌اش (1087968824، 136817688 یا 777000) بین همهٔ کسانی که این‌طور پیام می‌فرستند مشترک است، پس ویزارد ردش می‌کند، چه تایپ شده باشد چه پیدا شده. از آن شخص بخواهید با نام خودش پیام بفرستد.

تنظیمات کجاست#

ویزارد ‎~/.config/aipager/aipager.yaml را می‌نویسد (حالت دسترسی 0600): توکن ربات، چت‌هایی که ربات در آن‌ها کار می‌کند، و اعضای هر چت با نقش‌هایشان. اینکه هر نقش چه کاری می‌تواند بکند در ‎~/.config/aipager/policy.yaml است که مال خود شماست: ویزارد هیچ‌وقت آن را نمی‌نویسد (قانون‌ها چطور کار می‌کنند را ببینید). نصب‌هایی که با قالب قدیمی team.yaml راه افتاده‌اند خودکار منتقل می‌شوند، یا با شروع aipager یا با اجرای بعدی ویزارد.

خواندن دوبارهٔ تنظیمات بدون ری‌استارت#

بعد از هر تغییر چت یا عضو در منوی ویرایش (اضافه یا حذف یک گروه یا چت خصوصی، اضافه یا حذف یک عضو، تنظیم نقش، ویرایش deny_tools، تغییر اسم یک چت)، و بعد از یک گروه یا شخصی که در پایان اولین اجرا اضافه شده یا گروه نیمه‌کاره‌ای که ادامه می‌دهید (یک بار برای همهٔ چیزهایی که آنجا اضافه کردید)، aipager config به aipager در حال اجرا سیگنال خواندن دوباره (SIGUSR1) می‌فرستد و می‌گوید «Scopes reloaded live (no daemon restart needed)». خواندن دوباره aipager.yaml و policy.yaml را از نو می‌خواند. اگر تنظیمات روی دیسک رد شوند، ویزارد «Not applied» را با دلیلش می‌گوید و aipager تا وقتی درستش کنید تنظیمات قبلی‌اش را نگه می‌دارد. اگر ویزارد مطمئن نباشد کدام پروسه aipager است، می‌گوید به جایش ری‌استارتش کنید.

آنچه خواندن دوباره فوراً اعمال می‌کند:

  • چه کسی در هر چت می‌تواند از ربات استفاده کند، با چه نقش و قانون‌هایی؛
  • یک گروه یا چت خصوصی جدید شروع به گرفتن پیام‌ها می‌کند و منوی / خودش را می‌گیرد؛ یکی که حذف شده متوقف می‌شود (سشن‌هایش تا وقتی ببندیدشان به کار ادامه می‌دهند)؛
  • پیام نگه‌داشته‌شده (پیامی که منتظر جواب یک درخواست یا تمام شدن کار کس دیگری است) از کسی که دیگر نمی‌تواند در آن چت پیام بفرستد دور ریخته می‌شود: یک 🤷 می‌گیرد و ربات جواب می‌دهد «به Claude ارسال نشد: ‎@bob دیگر اجازه ندارد اینجا پیام بفرستد.»؛
  • کار در جریان کسی که حذف شده یا اختیاراتی از دست داده، برای بقیهٔ آن کار فقط سخت‌ترینِ قانون‌های قبلی و جدیدش را نگه می‌دارد (برای کسی که حذف شده، کف محدود). کاری که در ترمینال تایپ شده عوض نمی‌شود، مگر اینکه یک پیام تلگرام به آن اضافه شده باشد: aipager ثبت نمی‌کند مال چه کسی، پس چنین کاری وقتی محدود می‌شود که هر مالکی از آن چت (یا، در چت خصوصی، عضو آن) اختیاراتی از دست بدهد. کاری که وقتی aipager ری‌استارت شد از قبل در جریان بود (هنوز در حال کار، یا منتظر یک سؤال یا اجازه) برای هر عضوی از چتش که اختیاراتی از دست داده محدود می‌شود. ترفیع هیچ‌وقت یک کار در جریان را بازتر نمی‌کند: اختیارات جدید از کار بعدی آن شخص اعمال می‌شود.

فقط یک توکن ربات جدید ری‌استارت لازم دارد (aipager config بعد از Refresh bot token همین را می‌گوید). وقتی aipagerی اجرا نمی‌شود، سیگنالی فرستاده نمی‌شود: aipager start بعدی تنظیمات جدید را می‌خواند.

برای خواندن دوبارهٔ دستی (مثلاً بعد از ویرایش policy.yaml)، فقط به پروسهٔ aipager سیگنال بدهید. زیر سرویس پس‌زمینه:

sh
pid=$(systemctl --user show -p MainPID --value aipager.service)
[ "${pid:-0}" -gt 0 ] && kill -USR1 "$pid"

(این چک مهم است: وقتی سرویس اجرا نمی‌شود، MainPID برابر 0 است و kill -USR1 0 به پروسه‌های shell خود شما سیگنال می‌دهد.)

برای aipagerی که خودتان با aipager start اجرا کرده‌اید، kill -USR1 <pid>‎ را به همان پروسه بفرستید. به هر چیزی که با pgrep -f 'aipager start'‎ جور می‌شود سیگنال ندهید (shell یا کانتینری که aipager را اجرا می‌کند هم جور می‌شود، و SIGUSR1 پروسه‌ای را که آن را نمی‌شناسد متوقف می‌کند)، و از systemctl --user kill بدون ‎--kill-whom=main استفاده نکنید (سشن‌های سرویس در همان گروه پروسه‌اند و متوقف می‌شدند).

اگر aipager.yaml یا policy.yaml موقع خواندن دوباره خراب باشد، یا aipager.yaml نباشد، aipager یک هشدار در لاگ می‌نویسد و تنظیمات قبلی را در حافظه نگه می‌دارد. یک غلط تایپی یا فایلی که کنار گذاشته شده نه می‌تواند شما را بیرون بیندازد و نه کسی را راه بدهد: خواندن دوباره هیچ‌وقت aipagerی را که چت تنظیم‌شده دارد به استفادهٔ شخصی برنمی‌گرداند (فقط ری‌استارت این کار را می‌کند).

دسترسی ادمین ربات و مود حریم خصوصی#

ربات را ادمین گروه کنید، با اجازهٔ سنجاق کردن پیام‌ها. برای سنجاق کردن نوار وضعیت گروه به آن نیاز دارد (آنچه همه می‌بینند را ببینید). بدون آن، گروه کار می‌کند ولی نوار وضعیت ندارد؛ اگر بعداً این اجازه را به ربات بدهید، برای اینکه نوار بیاید aipager را ری‌استارت کنید.

رباتی که ادمین گروه است، مود حریم خصوصی (privacy mode) آن در BotFather هر چه باشد، همهٔ پیام‌های گروه را می‌گیرد. این بی‌خطر است: aipager فقط روی پیام‌هایی که در ربات در گروه چه پیام‌هایی را می‌خواند آمده کاری می‌کند و بقیه را نادیده می‌گیرد، پس حرف‌های گروه هیچ‌وقت به یک سشن نمی‌رسد. در رباتی که ادمین نیست، مود حریم خصوصی به‌طور پیش‌فرض روشن است (روشن نگهش دارید) و تلگرام فقط بعضی پیام‌های گروه را به آن می‌دهد؛ اگر پیامی از شما نرسید، به یکی از پیام‌های ربات جواب بدهید یا از یک فرمان استفاده کنید. تنظیم حریم خصوصی چیزی را در اینکه aipager روی چه چیزی کار می‌کند عوض نمی‌کند.

ادمین تلگرامی گروه بودن در aipager چیزی به کسی نمی‌دهد. کاری که هر کس می‌تواند بکند فقط از نقشش در aipager.yaml می‌آید.

وقتی تلگرام گروه را آپگرید می‌کند#

تلگرام یک گروه معمولی را وقتی عمومی‌اش کنید، تاپیک‌ها را روشن کنید، از ۲۰۰ عضو بگذرد یا بعضی دسترسی‌های ادمین را عوض کنید، به سوپرگروه تبدیل می‌کند، و این آپگرید آیدی چت جدیدی به گروه می‌دهد. aipager خودش دنبالش می‌رود: وقتی آپگرید را می‌بیند (اعلان تلگرام در گروه، یا اولین ارسال به آیدی قدیمی)، بخش آن گروه در aipager.yaml را به آیدی جدید منتقل می‌کند، سشن‌ها، مقصد پیام‌ها و ‎/settings گروه را هم با آن می‌برد، و یک خط در گروه می‌گذارد: «Telegram این گروه را آپگرید کرد. aipager هم همراهش آمد؛ لازم نیست کاری بکنید.» نوار وضعیت سنجاق‌شده در گروه آپگریدشده از نو شروع می‌شود. لاگ aipager یک هشدار با هر دو آیدی دارد.

اسم سشن‌ها داخل aipager آیدی قدیمی را نگه می‌دارند (هیچ‌وقت آن‌ها را نمی‌بینید)، و aipager.yaml یک سابقهٔ کوتاه chat_migrations از این جابه‌جایی نگه می‌دارد، تا سشنی که قبل از آپگرید شروع شده، حتی بعد از ری‌استارت، مال گروه آپگریدشده بماند. اسم داخلی یک سشن با آیدی قدیمی (‎/name__g<old id>‎) در گروه آپگریدشده کار می‌کند و هیچ جای دیگر. اگر aipager در زمان آپگرید متوقف بوده، در شروع بعدی متوجه می‌شود. کاری که در لحظهٔ آپگرید در جریان است تمام می‌شود و جوابش به گروه آپگریدشده می‌رسد، ولی کارت در حال کارش برای بقیهٔ آن کار دوباره نشان داده نمی‌شود. اگر آیدی جدید از قبل یک چت جداگانه در تنظیمات باشد، چیزی جابه‌جا نمی‌شود و لاگ همین را می‌گوید؛ با aipager config یکی از آن دو را حذف کنید. «Test bot reachability» در aipager config وقتی به گروهی آپگریدشده برمی‌خورد آیدی جدید را نشان می‌دهد.

در هر شروع، aipager هر گروه را یک بار نگاه می‌کند. اگر تلگرام جواب بدهد که گروه پیدا نمی‌شود یا ربات نمی‌تواند از آن استفاده کند (گروه پاک شده، ربات حذف شده، یا گروه وقتی aipager متوقف بوده آپگرید شده و تلگرام نگفته به چه آیدی‌ای)، لاگ aipager یک هشدار با اسم آن چت دارد: چک کنید ربات هنوز در گروه هست یا نه، و اگر آپگرید شده، گروه را دوباره با Add a group scope در aipager config اضافه کنید (آیدی جدید را می‌گیرد؛ اعضایش را دوباره اضافه کنید) و بعد قدیمی را با Edit a scope ← Remove this scope حذف کنید (آیدی قدیمی دیگر کار نمی‌کند). aipager چیزی نمی‌فرستد و دوباره امتحان نمی‌کند.

تاپیک‌های فروم پشتیبانی نمی‌شوند#

برای هر تیم یک گروه معمولی (بدون تاپیک) استفاده کنید. در گروهی که تاپیک‌هایش روشن است، aipager باز هم کار می‌کند، ولی به یک تاپیک پایبند نمی‌ماند:

  • جواب یک فرمان یا پیام (مثلاً ‎/status، یا جواب «کدام سشن؟») در همان تاپیکی می‌ماند که فرستاده شده؛
  • اعلان‌ها، کارت‌های در حال کار، جواب‌ها، درخواست‌های اجازه و نوار وضعیت سنجاق‌شده بدون تاپیک به گروه فرستاده می‌شوند، پس ممکن است در General بیفتند؛
  • هر نفر برای کل گروه یک سشن فعلی دارد، نه برای هر تاپیک.

روشن کردن تاپیک‌ها گروه معمولی را هم به سوپرگروه آپگرید می‌کند که aipager دنبالش می‌رود (بالا).

نقش‌ها#

چهار نقش داخلی (aipager/safety.py را ببینید). نقشی که حساب می‌شود نقش آن شخص در چتی است که در آن کار می‌کند. هیچ‌کس نمی‌تواند اعضا یا نقش‌ها را از تلگرام یا Mini App عوض کند: فقط aipager config روی خود کامپیوتر این کار را می‌کند، و همین آن را در دست مالک نگه می‌دارد.

owneradminuserread_only
فرستادن پیام (can_prompt)✅✅✅❌
جواب دادن به Claude: اجازه بده، رد کن، سؤال‌ها (can_approve)✅✅✅❌
مدیریت: دسترسی کامل، ‎/settings یک گروه، ‎/update، نصب ویس (can_manage)✅✅❌ (دسترسی کامل: ✅ در چت خصوصی خودش)❌
عوض کردن اعضا و نقش‌ها از تلگرام یا Mini App❌❌❌❌
معافیت از قانون‌های رد نقش (bypass_role_denies)✅✅❌❌
معافیت از کف ایمنی (bypass_safety)✅❌❌❌
Bash و بقیهٔ ابزارهای اجرای کد✅✅ (قانون‌های در حد تلاش)❌❌
هر فرمان اسلشی✅✅فقط فرمان‌های کیبورد «فرمان‌ها»، ‎/compact و تعویض مدلمثل user
جای شروع سشن‌ها (‎/new، ادامه، ری‌استارت، تعویض مود)هر جاهر جافقط داخل پوشهٔ root چتمثل user
جای نوشتن فایل‌هاهر جاهر جا که کف ایمنی اجازه دهدپوشهٔ پروژهٔ سشن (وقتی داخل پوشهٔ root است) و scratchpad آن، هیچ‌وقت پوشهٔ خانهمثل user
خواندن در پوشهٔ خانهٔ شماهر جا که کف ایمنی اجازه دهدهر جا که کف ایمنی اجازه دهدفقط داخل پوشهٔ root (پوشه‌های دیگر کامپیوتر مثل قبل، پوشه‌های root اعضای دیگر هیچ‌وقت)مثل user
فایل‌های اطلاعات ورود (‎~/.ssh،‏ ‎~/.git-credentials، ...)خواندنیخواندنیهیچ‌وقت (به‌طور پیش‌فرض)هیچ‌وقت (به‌طور پیش‌فرض)
Grep/Globهر جاهر جا جز پوشه‌های محافظت‌شدهٔ aipager (نه پوشه‌ای که یکی از آن‌هاست، داخل یکی است یا یکی را در خود دارد)پوشهٔ پروژهٔ سشن و scratchpad آنمثل user
  • ‏owner: کنترل کامل، از جمله کف ایمنی داخلی. باید دقیقاً یک نفر باشد: کسی که کامپیوتر را اداره می‌کند.
  • ‏admin: هر کاری که یک مالک در تلگرام و Mini App می‌تواند: بردن سشن‌ها به مود دسترسی کامل (و شروعشان در آن)، ادامهٔ یک سشن در دسترسی کامل، عوض کردن ‎/settings یک گروه، اجرای ‎/update، نصب قابلیت ویس، فرستادن هر فرمان اسلشی. ادمین از قانون‌های رد نقش هم معاف است (deny_tools چت و عضو روی او اعمال نمی‌شود). دو چیز مال مالک می‌ماند:
    • عوض کردن اعضا و نقش‌ها: فقط aipager config روی خود کامپیوتر این کار را می‌کند، و هیچ چیزی در تلگرام یا Mini App نمی‌تواند؛
    • معافیت از کف ایمنی (تنظیمات و توکن ربات aipager، اطلاعات ورود Claude Code، فایل‌های کنترلی aipager). Grep و Glob یک ادمین می‌تواند هر جای دیگری را بگردد، ولی نه پوشه‌ای که یکی از این‌هاست، داخل یکی است یا یکی را در خود دارد: Grep روی ~، / یا ‎/tmp (یا بدون پوشه، از سشنی در پوشهٔ خانه) رد می‌شود، و همین‌طور Globی که الگویش در یکی از این‌ها شروع شود (مثل ‎/home/you/.config/aipager/*‎). به جایش داخل پوشهٔ یک پروژه بگردید. در نسخه‌هایی از Claude Code که ابزار Grep ندارند، Claude از طریق Bash می‌گردد؛ آنجا جست‌وجو یا فهرست گرفتن بازگشتی از کل پوشهٔ خانه یا / (grep -rn x ~‎،‏ rg x $HOME،‏ find / -name x) هم رد می‌شود، در حد تلاش (جست‌وجوی بدون پوشه، یا با ..، که از پوشهٔ خانه یا زیر آن اجرا شود دیده نمی‌شود)، و جست‌وجوهای پروژه رد نمی‌شوند، از جمله جست‌وجو برای یک مسیر خانه (grep -rn "$HOME" src) (مدل امنیتی).

ادمین Bash را نگه می‌دارد، و با یک shell، الگوهای دستور کف در حد تلاش‌اند، نه یک مرز: کسی را فقط وقتی ادمین کنید که حاضرید یک shell روی کامپیوتر به او بدهید.

  • ‏user: قانون‌های رد اعمال می‌شوند. نه Bash، نه هیچ ابزار دیگری که کد اجرا می‌کند (PowerShell،‏ Monitor، پیام‌های زمان‌بندی‌شده، workflowها؛ فهرستش safety.CODE_EXECUTION_TOOLS است)، نه SendMessage به سشن‌های دیگر، نه عوض کردن worktree. نوشتن فایل‌ها فقط داخل پوشهٔ سشن و scratchpad آن در Claude Code انجام می‌شود، و هیچ‌وقت در ‎.claude/‎،‏ ‎.git/‎ یا ‎.mcp.json آن پوشه (هر کدام دستور اجرا می‌کنند). Grep و Glob فقط داخل همین پوشه‌ها و با globهای نسبی ساده می‌گردند. یک user فقط داخل پوشهٔ root چت سشن شروع، ادامه، ری‌استارت و عوض می‌کند و هیچ چیزی در پوشهٔ خانهٔ شما بیرون از آن نمی‌خواند. پوشهٔ سشنی که پوشهٔ خانهٔ شما، / یا پوشه‌ای بالاتر از آن است، یا بیرون از پوشهٔ root است (سشنی که قبل از پوشه‌های root یا توسط کس دیگری شروع شده)، حساب نمی‌شود: آنجا یک user فقط در scratchpad می‌تواند بنویسد و بگردد. خواندن از قانون‌های مسیرهای محافظت‌شده پیروی می‌کند و فایل‌های اطلاعات ورود شما هیچ‌وقت خواندنی نیستند: ‎~/.ssh،‏ ‎~/.gnupg،‏ ‎~/.aws،‏ ‎~/.config/gh،‏ ‎~/.git-credentials،‏ ‎~/.netrc،‏ ‎~/.docker/config.json،‏ ‎~/.kube،‏ ‎~/.config/gcloud،‏ ‎~/.azure،‏ ‎~/.password-store،‏ ‎~/.pgpass،‏ ‎~/.npmrc و ‎~/.pypirc. فرمان‌های اسلش: فقط آن‌هایی که در کیبورد «فرمان‌ها» هستند، ‎/compact و تعویض مدل (پیام با اختیارات چه کسی اجرا می‌شود را ببینید).
  • ‏read_only: ناظرها. همه‌چیز را در گروه می‌بینند و می‌توانند از ‎/status،‏ ‎/diff،‏ ‎/whoami،‏ ‎/help،‏ ‎/start و ‎/app استفاده کنند، ‎/settings را نگاه کنند و فهرست ‎/resume را که کسی باز کرده ورق بزنند. پیام‌های متنی، ویس و فایل خودشان به جایی فرستاده نمی‌شوند. اولین پیامی که در یک چت می‌فرستند یک جواب می‌گیرد که می‌گوید نقششان read_only است؛ بعد از آن ربات تا ری‌استارت aipager در آن چت برایشان ساکت می‌ماند (نه جوابی، نه ری‌اکشنی). همان محدودیت‌های ابزار و نوشتن user را دارند، برای حالتی که روزی پیامی از آن‌ها به یک سشن برسد.

نقش‌های سفارشی#

‏policy.yaml می‌تواند هر فیلدی از یک نقش داخلی را عوض کند یا نقش‌های جدید تعریف کند. فیلدی که تنظیم کنید جای مقدار داخلی را می‌گیرد. فیلدها:

  • ‏can_prompt،‏ can_approve: فرستادن پیام؛ جواب دادن به Claude.
  • ‏can_manage: استفاده از دسترسی کامل، عوض کردن ‎/settings یک گروه، اجرای ‎/update و نصب قابلیت ویس (داخلی: owner و admin true،‏ user و read_only false). هیچ‌وقت به کسی اجازهٔ عوض کردن اعضا یا نقش‌ها را نمی‌دهد و هیچ‌وقت از کف ایمنی معاف نمی‌کند.
  • ‏bypass_role_denies،‏ bypass_safety: جدول را ببینید.
  • ‏deny_tools،‏ allow_tools،‏ deny_bash_patterns،‏ deny_paths_no_access،‏ deny_paths_no_write: قانون‌ها چطور کار می‌کنند را ببینید.

نقشی که از صفر تعریف کنید با can_prompt و can_approve روشن، can_manage و هر دو معافیت خاموش، فایل‌های اطلاعات ورود در deny_paths_no_access آن، و هیچ ابزار ردشده‌ای، پس Bash دارد شروع می‌شود، تا وقتی deny_tools را تنظیم کنید (aipager doctor وقتی عضوی آن را داشته باشد یک بار هشدار می‌دهد). محدودیت نوشتن و جست‌وجو روی هر نقشی بدون bypass_safety یا bypass_role_denies اعمال می‌شود. پوشهٔ root روی هر نقشی بدون can_manage اعمال می‌شود، هر معافیتی داشته باشد: نقشی که با bypass_role_denies یا bypass_safety ولی بدون can_manage تعریف کنید هر جای داخل پوشهٔ root خودش (و scratchpad) می‌نویسد و می‌گردد و هیچ جای دیگری نه، و هیچ چیزی در پوشهٔ خانهٔ شما بیرون از پوشهٔ root خودش نمی‌خواند (با bypass_safety، در سشنی که بیرون از پوشهٔ root خودش اجرا می‌شود، فقط در scratchpad می‌نویسد). فقط مالک‌ها و ادمین‌ها بی‌محدودیت‌اند.

پوشه‌های root#

هر چت یک پوشهٔ root برای اعضا دارد: پوشه‌ای که اعضایی که نقششان در آن چت can_manage ندارد (user و read_only داخلی، و نقش‌هایی که بدون آن تعریف می‌کنید) سشن‌هایشان را در آن شروع می‌کنند و نگه می‌دارند. مالک‌ها و ادمین‌ها به آن محدود نیستند. پوشهٔ root یک چت خصوصی مال همان شخص است؛ پوشهٔ root یک گروه بین اعضای محدود آن گروه مشترک است. دو چت هیچ‌وقت یک پوشهٔ root را با هم شریک نمی‌شوند، مگر اینکه عمداً یک پوشه را به هر دو بدهید (ویزارد از شما می‌خواهد تأییدش کنید).

  • تنظیم کردنش. aipager config وقتی یک گروه، یا یک چت خصوصی برای نقشی بدون can_manage، اضافه می‌کنید آن را با مقدار پیش‌فرض می‌پرسد، و Edit a scope ← Set the members' root folder عوضش می‌کند (فوراً، با خواندن دوبارهٔ تنظیمات، اعمال می‌شود). تنظیمات فعلی پوشهٔ root هر چت را نشان می‌دهد، و وقتی تنظیم نشده ‎(default)‎ را.
  • پیش‌فرض برای چت خصوصی ‎~/aipager-users/<label>‎ است (برچسب آن شخص) و برای گروه ‎~/aipager-users/group-<label>‎. برچسب به حروف کوچک برده می‌شود و هر چیزی جز حرف، رقم، .، _ و - به - تبدیل می‌شود؛ وقتی دو چت به یک پوشه برسند، به هر کدام آیدی چتش اضافه می‌شود (sara-123456). پوشه (و ‎~/aipager-users اگر هنوز وجود نداشته باشد) با حالت دسترسی 0700 ساخته می‌شود تا فقط خودتان بتوانید بازش کنید، اولین باری که یک عضو ‎/new یا فرم «سشن جدید» Mini App را باز می‌کند. پیش از شروع سشن در آن، aipager آن را برای Claude Code مورد اعتماد علامت می‌زند تا سؤال «Do you trust this folder?» در Claude Code اولین سشن عضو را تمام نکند. پیش‌فرض هیچ‌وقت جابه‌جا نمی‌شود: وقتی یک ویرایش در aipager config (پوشهٔ root یک چت دیگر، یک چت حذف‌شده، یک برچسب جدید) پوشهٔ پیش‌فرض یک چت را عوض می‌کرد، ویزارد پوشه‌ای را که داشت به‌عنوان پوشهٔ root آن چت می‌نویسد.
  • آنچه ویزارد رد می‌کند: مسیر نسبی، نویسه‌های wildcard، /، پوشهٔ خانهٔ شما یا پوشه‌ای بالاتر از آن، و پوشه‌ای که یکی از پوشه‌های محافظت‌شدهٔ aipager یا فایل‌های اطلاعات ورود است، داخل آن است یا آن را در خود دارد (‎~/.claude،‏ ‎~/.config/aipager،‏ ‎~/.config،‏ ‎~/.ssh، ...)، و پوشهٔ موقت Claude Code (‎/tmp/claude-*‎، جایی که scratchpad همهٔ سشن‌هاست). پوشه‌ای که هنوز وجود ندارد مشکلی ندارد. برای پوشه‌ای که سیستم شما از آن برنامه اجرا می‌کند (‎~/bin،‏ ‎~/.local/bin،‏ ‎~/.config/systemd،‏ ‎~/.config/autostart، یا یکی داخل آن‌ها) از شما تأیید می‌خواهد.
  • شروع سشن‌ها. صفحهٔ «پوشه» در ‎/new و Mini App پوشهٔ root و پوشه‌های مستقیم داخل آن را فهرست می‌کنند (نه پوشه‌های پنهان، و نه لینکی که به بیرون آن برسد)، بدون ردیف «پوشهٔ پیش‌فرض»؛ سشن جدید در خود پوشهٔ root شروع می‌شود، مگر اینکه یکی از آن‌ها را انتخاب کنید. «پوشهٔ جدید» پوشه را داخل همانی که انتخاب کرده‌اید می‌سازد. هر چیز دیگری این را می‌گیرد: «نقش شما فقط در پوشهٔ خودتان ~/... یا پوشه‌ای داخل آن می‌تواند سشن شروع کند.»
  • سشن‌های بیرون از آن. ادامه دادن، ری‌استارت، جایگزینی و عوض کردن مود سشنی که پوشه‌اش بیرون از پوشهٔ root است این را می‌گیرد: «این سشن بیرون از پوشهٔ شما ~/... کار می‌کند، پس نقش شما نمی‌تواند آن را ادامه دهد، ری‌استارت کند یا مودش را عوض کند. از یک ادمین بخواهید.» پیام‌ها به چنین سشنی که در حال اجراست باز هم فرستاده می‌شوند، و هوک ایمنی کار را نگه می‌دارد: آنجا فقط در scratchpad می‌نویسد.
  • هوک کار را به چه چیزی محدود می‌کند. کار یک عضو محدود فقط در پوشهٔ سشن (وقتی داخل پوشهٔ root است) و scratchpad آن می‌نویسد، هیچ چیزی را در پوشهٔ خانهٔ شما بیرون از پوشهٔ root نمی‌خواند و آنجا Grep یا Glob نمی‌کند (به‌جز scratchpad و فایل جواب خودش)، و هیچ‌وقت به پوشهٔ root چت دیگری، هر جا که باشد، دست نمی‌زند. پوشه‌های بیرون از پوشهٔ خانهٔ شما (‎/usr،‏ ‎/etc، ...) خواندنی می‌مانند، پوشه‌های محافظت‌شده رد می‌مانند، و Bash برای user رد می‌ماند. وقتی یک کار دو عضو با پوشه‌های root مختلف را با هم دارد، باریک‌تری برنده است؛ دو پوشه که داخل هم نیستند فقط پوشهٔ خود سشن را باقی می‌گذارند.

برای اینکه Bash را به user برگردانید (فقط برای کسانی که حاضرید به آن‌ها shell بدهید)، آن را در allow_tools نام ببرید (که آن‌وقت فهرست مجاز آن نقش هم می‌شود) یا deny_tools آن را عوض کنید:

yaml
roles:
  user:
    # فهرست داخلی، بدون Bash
    deny_tools: [PowerShell, Monitor, REPL, Workflow, CronCreate,
                 RemoteTrigger, AppifactRepl, self_hosted_runner_spawn_local,
                 self_hosted_runner_requeue_session, SendMessage,
                 EnterWorktree, ExitWorktree]

آن‌وقت aipager doctor هشدار می‌دهد: role user has Bash: its safety rules are best-effort, not a boundary. اگر policy.yaml شما قبل از وجود این پیش‌فرض deny_tools را برای user تنظیم کرده بود، فهرست شما هنوز جای آن را می‌گیرد، پس آن نقش تا وقتی Bash را دوباره اضافه کنید Bash دارد؛ هشدار doctor همین را می‌گوید. برای چیزهایی که این محدودیت‌ها پوشش نمی‌دهند، مدل امنیتی ← اجرای قانون‌ها در استفادهٔ تیمی را ببینید.

حرف زدن با ربات در گروه#

ربات در گروه چه پیام‌هایی را می‌خواند#

در گروه، aipager فقط روی پیامی کار می‌کند که:

  • یک فرمان باشد: ‎/status،‏ ‎/x1 fix the tests، یا همین‌ها با ‎@aipagerbot بعد از فرمان (‎/x1@aipagerbot) که تلگرام وقتی آن را از منو انتخاب می‌کنید اضافه می‌کند. فرمانی برای ربات دیگر (‎/x1@otherbot) نادیده گرفته می‌شود؛
  • جواب به یکی از پیام‌های ربات باشد؛
  • پیامی که ربات را منشن می‌کند باشد: ‎@aipagerbot fix the tests؛
  • زدن کیبورد ربات در گروه باشد. در گروه، هر دکمهٔ کیبورد با یک مربع کوچک شروع می‌شود (▫️ توقف، ▫️ پاک کردن گفتگو)، و فقط همان متن علامت‌دار زدن دکمه حساب می‌شود. تایپ کردن خود کلمه، حرف معمولی است: عضوی که توقف، پاک کردن گفتگو، Opus یا اسم یک سشن را تایپ کند چیزی را عوض نمی‌کند. برای استفادهٔ عمدی از یک کلمهٔ کیبورد بدون کیبورد، ربات را خطاب کنید: ‎@aipagerbot stop، یا stop در جواب یکی از پیام‌هایش.

هر چیز دیگری (حرف‌های اعضا با هم، عکس یا ویسی که جواب ربات نیست) نه ری‌اکشن می‌گیرد و نه جواب. این، چه ربات ادمین گروه باشد چه نه، برقرار است. پیام‌های ویرایش‌شده همه‌جا نادیده گرفته می‌شوند: پیامی را ویرایش کنید و اتفاقی نمی‌افتد؛ به جایش دوباره بفرستیدش.

عکس، فایل یا ویس هم همین‌طور: آن را در جواب ربات بفرستید، یا ربات را در کپشن منشن کنید. برای یک آلبوم، کپشن را روی اولین آیتمش بگذارید: آیتم‌هایی از آلبوم که بعد از آیتم دارای کپشن، منشن یا جواب می‌رسند برداشته می‌شوند، و آن‌هایی که قبلش می‌رسند نه.

منشن حذف می‌شود. ‎@aipagerbot fix the tests به‌شکل fix the tests به Claude می‌رسد (Claude Code یک ‎@word را فایل می‌خواند). ‎@aipagerbot status و ‎@aipagerbot x2 مثل تایپ status یا x2 در چت خصوصی کار می‌کنند، و ‎@aipagerbot تنها نشان می‌دهد پیام‌هایتان به کجا ارسال می‌شوند. فرمان یک سشن بعد از منشن کار می‌کند (‎@aipagerbot /x1 fix it)، ولی یکی از فرمان‌های خود aipager نه: ‎@aipagerbot /stop این را می‌گیرد: «‎/stop را جداگانه و بدون صدا زدن ربات بفرستید.»

فقط اعضا. کسی که عضو گروه نیست یک جواب می‌گیرد («🚫 شما اجازهٔ استفاده از ربات در این چت را ندارید.») با آیدی تلگرامش که به شما بدهد، و برای aipager config یادداشت می‌شود؛ بعد از آن ربات تا ری‌استارت aipager نادیده‌اش می‌گیرد. به یک عضو read_only یک بار نقشش گفته می‌شود (نقش‌ها را ببینید).

ادمین‌های ناشناس باید با نام خودشان پیام بفرستند. ادمین گروهی که «Remain anonymous» را روشن کرده، یا پیامی که به اسم گروه یا یک کانال فرستاده شده، نمی‌گوید چه کسی آن را نوشته: تلگرام برای همهٔ ادمین‌های ناشناس یک فرستنده نشان می‌دهد. aipager نمی‌تواند به چنین پیامی نقش کسی را بدهد، پس جواب می‌دهد «برای استفاده از ربات، با نام خودتان پیام بفرستید.» (یک بار برای هر چت تا ری‌استارت aipager) و کار دیگری نمی‌کند. هیچ‌وقت به‌عنوان کاربر منتظر یادداشت نمی‌شود و ویزارد آن آیدی مشترک را رد می‌کند. در تنظیمات ادمین گروه «Remain anonymous» را برای خودتان خاموش کنید، یا از حساب خودتان پیام بفرستید.

حرف زدن با یک سشن در گروه#

به یکی از پیام‌های یک سشن (جوابش، کارتش) جواب بدهید تا پیامتان به همان سشن ارسال شود. یا ‎/x1 your message را بفرستید، یا کپشنی که با ‎/x1 شروع شود.

هر نفر سشن فعلی خودش را دارد: همانی که آخرین بار به آن رفته (‎/x1)، به آن پیام داده، جوابش را داده یا شروعش کرده. جواب دادن سشن یک عضو دیگر آن را عوض نمی‌کند، و پیام‌های دیگران هم نه. یک منشن، یک ویس، یک قالب یا یک فرمان کیبورد به سشن فعلی خودتان ارسال می‌شود، و فرمان کیبورد یا قالب در جوابش اسم آن را می‌آورد («🧹 ‎/clear برای x1 ارسال شد»). یک ‎/stop،‏ ‎/mode،‏ ‎/kill،‏ ‎/restart،‏ ‎/rename،‏ ‎/delete یا ‎/diff خالی فقط روی سشن فعلی خودتان کار می‌کند (با تأیید همیشگی‌اش)، و فقط وقتی فرمان برای آن معنا داشته باشد (در حال کار برای ‎/stop، بسته‌شده برای ‎/delete)؛ وگرنه همیشه فهرست انتخاب را نشان می‌دهد، حتی وقتی فقط یک سشن مانده، چون ممکن است آن یکی مال کس دیگری باشد. ‎/clearqueue و ‎/now روی سشن فعلی شما کار می‌کنند. ‎/kill x1 و بقیهٔ فرمان‌هایی که اسم دارند روی همان سشن کار می‌کنند، مثل قبل.

  • اگر سشن فعلی‌ای از خودتان ندارید و بیش از یک سشن در حال اجراست، ربات می‌پرسد «کدام سشن؟ به یکی از پیام‌هایش جواب بدهید، یا پیامتان را با ‎/x1 بفرستید.» با یک دکمه برای هر سشن، و چیزی نمی‌فرستد. با فقط یک سشن در حال اجرا، پیام به همان ارسال می‌شود.
  • اگر سشن فعلی خودتان بسته شده، پیام به تنها سشنی که هنوز اجرا می‌شود فرستاده نمی‌شود (ممکن است مال کس دیگری باشد): ربات جواب می‌دهد «x1 بسته شده. کدام سشن؟» با یک دکمه برای هر سشن در حال اجرا و، وقتی x1 قابل ادامه است، «▶️ ادامهٔ x1»، و چیزی نمی‌فرستد.
  • زدن دکمهٔ یک سشن روی هر کدام از این دو سؤال، پیامی را که دربارهٔ آن پرسیده شده (یک متن، متن یک ویس یا یک فایل) هم به آن سشن می‌فرستد، انگار خودتان آنجا فرستاده بودید، و سؤال به «به x2 ارسال شد.» تبدیل می‌شود. فقط کسی که پیام را فرستاده می‌تواند از دکمه‌ها استفاده کند، و فقط تا ده دقیقه و تا ری‌استارت aipager: بعد از آن دکمه فقط آن سشن را سشن فعلی شما می‌کند («این پیام دیگر قدیمی شده و فرستاده نشد؛ دوباره بفرستید.»). ▶️ ادامه، x1 را برمی‌گرداند ولی چیزی نمی‌فرستد: پیامتان را دوباره بفرستید.
  • نوار سنجاق‌شده در گروه خط «پیام‌ها به ... ارسال می‌شوند» ندارد، چون برای هر نفر فرق دارد.

کارت‌هایی که منتظر جواب‌اند مال یک نفرند. کارت سشن جدید می‌گوید «اسم سشن را در جواب همین پیام بفرستید؛ اگر خواستید، اولین کار را هم بنویسید:»، و سؤال تغییر اسم «... به همین پیام با اسم جدید جواب بدهید.». در گروه هر کدام نشان می‌دهد مال کیست («🆕 سشن جدید (‎@alice)»)، فقط همان شخص می‌تواند جوابش را بدهد، و دو نفر می‌توانند همزمان سشن شروع کنند یا اسم عوض کنند. جواب یک عضو دیگر به کارت سشن جدید کسی این را می‌گیرد: «این کارت مال ‎@alice است. برای کارت خودتان ‎/new بفرستید.» و به هیچ سشنی ارسال نمی‌شود. سؤال تغییر اسم بعد از ۱۰ دقیقه، یا همین که صاحبش کار دیگری بکند، دیگر منتظر نمی‌ماند. کارت «آماده»، جواب ‎/x1،‏ ‎/start و ‎/help می‌گویند به پیام یک سشن جواب بدهید یا ربات را منشن کنید («به پیامی از x1 جواب بدهید (یا ‎@aipagerbot را صدا بزنید) تا با آن حرف بزنید.»)، چون پیام معمولی به ربات نمی‌رسد.

کیبورد مال هر نفر است. «قالب‌ها»، «فرمان‌ها»، «مدل ›» و «« بازگشت» فقط کیبورد کسی را که آن‌ها را می‌زند عوض می‌کنند: ربات در جواب به زدن همان شخص جواب می‌دهد و کیبورد هیچ‌کس دیگر تکان نمی‌خورد. «« بازگشت» از جایی که هستید یک قدم بالا می‌رود، هر چه بقیهٔ اعضا دارند نگاه می‌کنند. کیبورد اصلی که ‎/start می‌فرستد مال کل گروه است و همه را به کیبورد اصلی برمی‌گرداند. وقتی یک سشن گروه شروع یا بسته می‌شود، aipager یک بار دوباره همان کیبورد اصلی را برای گروه می‌فرستد تا دکمه‌های سشن‌هایش آپدیت بمانند. بعد از آپدیت از نسخه‌ای که دکمه‌های علامت‌دار نداشت، ممکن است زدن یکی از دکمه‌های کیبورد قدیمی نادیده گرفته شود: یک بار ‎/start بفرستید تا گروه کیبورد جدید را بگیرد. کیبورد چت خصوصی علامتی ندارد و مثل قبل کار می‌کند.

Mini App#

‏‎/app فقط در چت خصوصی Mini App را باز می‌کند. در گروه در منوی / نیست؛ اگر آنجا تایپ شود، به عضوی که چت خودش با ربات تنظیم شده می‌گوید «📱 Mini App فقط در چت خصوصی کار می‌کند - به ربات پیام خصوصی بدهید و ‎/app را آنجا بفرستید.»، و به بقیه «Mini App از چت خصوصی خودتان با ربات باز می‌شود. از مالک ربات بخواهید شما را اضافه کند.»

‏Mini App هر بار یک چت را نشان می‌دهد. کسی که در بیش از یک چت هست (مثلاً چت خصوصی خودش و یک گروه) ردیفی از اسم چت‌ها در بالا می‌گیرد تا بینشان جابه‌جا شود؛ روی چت خصوصی خودش باز می‌شود، وگرنه روی اولین چتی که او را دارد، و آخرین انتخاب را روی همان گوشی به خاطر می‌سپارد. همه‌چیز داخل آن (سشن‌ها، دکمه‌هایشان، تنظیمات و اعلان‌هایی که می‌فرستد) برای چت انتخاب‌شده است، با نقشی که آن شخص در آن چت دارد. با یک چت، چیز اضافه‌ای نشان داده نمی‌شود.

پیام با اختیارات چه کسی اجرا می‌شود#

هر پیام با اختیارات کسی که آن را فرستاده اجرا می‌شود، در چتی که از آن فرستاده. کسی که در گروه user است و در چت خصوصی خودش owner، در گروه به‌عنوان user پیام می‌فرستد، دکمه می‌زند و فرمان اجرا می‌کند، به هر ترتیبی که چت‌ها در aipager.yaml آمده باشند.

  • هر پیام تلگرام هویت و قانون‌های فرستنده‌اش را به سشن می‌برد (مدل امنیتی ← اجرای قانون‌ها در استفادهٔ تیمی را ببینید). Claude می‌بیند هر پیام را چه کسی فرستاده (‎[via Telegram · @bob · role:user]‎ در گروه)، هیچ‌وقت کسی را که قبل از او سشن را می‌گرداند. هر کسی پیامی بفرستد گردانندهٔ سشن می‌شود، چه تایپش کرده باشد، چه از ‎/x1، یک قالب یا یک فرمان کیبورد استفاده کرده باشد.
  • پیام‌های نگه‌داشته‌شده فرستنده‌شان را نگه می‌دارند. وقتی کار یک نفر دیگر در جریان است (از جمله یک ایجنت پس‌زمینه که شروعش کرده)، یا وقتی پیام کس دیگری هنوز منتظر برداشته شدن است، یا وقتی یک درخواست اجازه یا سؤال باز است، پیام جدید نگه داشته می‌شود (👀) و وقتی این‌ها تمام شد، به‌عنوان کار خودش و با اختیارات فرستندهٔ خودش فرستاده می‌شود. کاری که در ترمینال تایپ شده مال مالک حساب می‌شود: فقط پیام یک مالک (یا، در چت خصوصی، پیام عضو همان چت) به آن اضافه می‌شود. پیام‌های خودتان هیچ‌وقت منتظر کار خودتان نمی‌مانند. اگر کاری که منتظرش‌اند متوقف شود، یا چون جلوی یک ابزار گرفته شده متوقف شود، پیام‌های نگه‌داشته‌شده دور ریخته می‌شوند (🤷): دوباره بفرستیدشان.
  • سخت‌ترین قانون برنده است. اگر پیام‌های آدم‌های مختلف باز هم در یک کار جمع شوند، آن کار با محدودکننده‌ترین ترکیب همهٔ کسانی که در آن هستند اجرا می‌شود. پیامی که به یک کار در جریان اضافه شود هیچ‌وقت آن را بازتر نمی‌کند: بقیهٔ کار سخت‌ترین قانون‌های همهٔ کسانی را که اضافه شده‌اند نگه می‌دارد.
  • فرمان‌های اسلش از نقش‌های محدود. نقشی که از قانون‌های نقش معاف نیست (user،‏ read_only، نقش‌هایی که بدون bypass_role_denies تعریف می‌کنید، و فرستنده‌ای که aipager نمی‌شناسد) فقط فرمان‌های اسلش کیبورد «فرمان‌ها» (مال شما، اگر keyboard.json عوضش کرده)، ‎/compact و تعویض مدل (‎/model <name>‎) را می‌تواند بفرستد. هر چیز دیگری، چه تایپ شود، چه با ‎/x1 /deliver ...‎، چه در کپشن یک فایل، چه به‌عنوان اولین پیام ‎/new x1 /review ...‎ یا به‌شکل یک قالب، «این فرمان فقط برای ادمین است.» و یک 🤷 می‌گیرد و هیچ چیزی به Claude نمی‌رسد. مالک‌ها و ادمین‌ها هر فرمانی را می‌فرستند.
  • نقش‌های محدود از پوشهٔ خانه و فایل‌های اطلاعات ورود دور می‌مانند. کار یک user یا read_only هیچ‌وقت در پوشهٔ سشنی که پوشهٔ خانهٔ شما، / یا بالاتر از آن است نمی‌نویسد (فقط در scratchpad) و هیچ‌وقت فایل‌های اطلاعات ورودی را که زیر نقش‌ها آمده نمی‌خواند.
  • نقش‌های محدود در پوشهٔ root خودشان می‌مانند. کار نقشی بدون can_manage هیچ چیزی در پوشهٔ خانهٔ شما بیرون از پوشهٔ root چت نمی‌خواند و هیچ چیزی در پوشهٔ سشنی بیرون از آن نمی‌نویسد. پوشهٔ root مال همان چتی است که پیام عضو از آن آمده، به هر سشنی که برود.
  • عضو حذف‌شده اختیاراتش را فوراً از دست می‌دهد، نه کار در جریانش را. فرستنده‌ای که aipager دیگر نمی‌شناسد (وقتی پیامش منتظر بوده حذف شده) با کف محدود اجرا می‌شود. بعد از خواندن دوبارهٔ تنظیمات، پیام‌های نگه‌داشته‌شده‌اش دور ریخته می‌شوند، و کاری از او که هنوز در جریان است به کارش ادامه می‌دهد، به کف محدود بسته تا تمام شود؛ برای تمام کردن فوری‌اش ‎/stop بفرستید (خواندن دوبارهٔ تنظیمات بدون ری‌استارت را ببینید).
  • پیامی از یک سشن Claude دیگر اختیارات فرستنده‌اش را دارد. پیامی که یک سشن به سشن دیگر می‌فرستد (SendMessage در Claude Code) با اختیارات کاری اجرا می‌شود که آن را فرستاده، همان‌طور که aipager تأییدشان کرده، هیچ‌وقت با اختیارات قبلی سشن گیرنده. پیامی که aipager نمی‌تواند تأییدش کند با سخت‌ترین قانون‌ها و بدون تغییر فایل یا دسترسی به وب اجرا می‌شود (مدل امنیتی ← پیام‌های بین سشن‌های Claude را ببینید).
  • ابزار مسدود کار را متوقف می‌کند. وقتی یک کار ابزاری را امتحان می‌کند که قانون‌هایش رد می‌کنند، کار فوراً با «🛑 x1 · قانون ایمنی جلویش را گرفت: ... (متوقف شد)» متوقف می‌شود و هر اجرای ابزار بعدی در آن کار هم رد می‌شود.

چه کسی چه دکمه‌ای را می‌تواند بزند#

هر دکمه نقش کسی را که آن را می‌زند، در چتی که دکمه در آن است و در همان لحظهٔ زدن، چک می‌کند. نقش کسی که فرمانِ سازندهٔ دکمه را فرستاده حساب نمی‌شود. (بعضی کارت‌ها چک می‌کنند چه کسی آن‌ها را خواسته: کارت‌های تأیید و کارت‌های ‎/new، پایین.)

  • نگاه کردن برای همهٔ اعضا آزاد است (VIEW). اعضای read_only می‌توانند ‎/resume را ورق بزنند، صفحهٔ «بسته‌شده‌ها»ی ‎/status، منوی ⋮ یک سشن، مود یا diff آن را باز کنند، ‎/settings را بگردند و یک منو را ببندند. نمی‌توانند کاری بکنند: هر دکمهٔ دیگری جواب می‌دهد «نقش شما در این چت اجازهٔ این کار را نمی‌دهد.»
  • جواب دادن به Claude can_approve لازم دارد (APPROVE): اجازه بده، همیشه اجازه بده، رد کن، گزینه‌های یک سؤال، ارسال، ادامه و «جواب» نوار سنجاق‌شده. read_only آن را خاموش دارد.
  • کار روی یک سشن can_prompt لازم دارد (PROMPT): توقف، دوباره امتحان کن، کامپکت، ارسال همین حالا، بستن، ری‌استارت، تغییر اسم، حذف، ادامه، تعویض مود، ✍️ گفتگو، پاک کردن همه، تنظیمات خود یک سشن و کارت‌های ‎/new. دکمه‌ای که aipager نمی‌شناسد هم همین را لازم دارد.
  • رفتن به دسترسی کامل ادمین لازم دارد (MANAGE:‏ owner،‏ admin، یا نقشی با can_manage، همان قانون ‎/mode full): «بله، عوض کن» و «توقف و تغییر مود» روی کارتی که به دسترسی کامل می‌برد، و ادامه در دسترسی کامل. رفتن بین مود پرسش و مود خودکار مال هر کسی است که می‌تواند روی سشن کار کند. ادامه دادن سشنی که در دسترسی کامل بود (تایپ ‎/resume x1، فهرست انتخاب، «ادامه» روی کارت اسم ‎/new، یا Mini App) برای هر کس دیگری آن را در مود خودکار برمی‌گرداند و جواب همین را می‌گوید: «♻️ x1 در مود خودکار دوباره باز شد: مود دسترسی کامل فقط برای ادمین است.»
  • در چت خصوصی خودش، هر کسی، با هر نقشی، می‌تواند از دسترسی کامل استفاده کند (از جمله یک user؛ نه read_only که پیامی نمی‌فرستد؛ یک نقش سفارشی can_prompt و can_approve لازم دارد، چون دسترسی کامل به همهٔ درخواست‌های اجازهٔ Claude Code جواب می‌دهد). همهٔ راه‌های رفتن به دسترسی کامل که بالا آمد آنجا برایش کار می‌کنند: ‎/mode full، کارت مود، ‎/new !x1، کارت‌های ‎/new،‏ ‎/resume و Mini App. چت خودش تنها جایی است که این اعمال می‌شود: در گروه، و در چت خصوصی هر کس دیگر، دسترسی کامل هنوز ادمین لازم دارد. سشن‌های جدیدش مثل همه در مود خودکار شروع می‌شوند، تا وقتی زیر ‎/settings ← سشن‌های جدید دسترسی کامل را انتخاب کند. هیچ کار دیگری از کارهای ادمین برایش باز نمی‌شود (‎/update، دکمهٔ نصب قابلیت ویس، و ‎/settings یک گروه فقط برای ادمین می‌مانند). دادن دسترسی کامل به این شکل بی‌خطر است: Claude Code را با ‎--dangerously-skip-permissions شروع می‌کند که فقط از درخواست‌های اجازهٔ خود Claude Code رد می‌شود. هوک PreToolUse aipager همچنان روی هر اجرای ابزار اجرا می‌شود و قانون‌های نقش آن عضو را (کف ایمنی، محدود بودن به پوشه، قانون‌های رد، فایل‌های اطلاعات ورود) درست مثل مود پرسش و مود خودکار اعمال می‌کند.
  • نصب کردن ادمین لازم دارد (UPDATE): دکمه‌های نصب و ری‌استارت قابلیت ویس، مثل دکمه‌های ‎/update.
  • عوض کردن ‎/settings یک گروه ادمین لازم دارد. نگاه کردنش برای همه آزاد است.
  • کارت تأیید مال کسی است که آن را خواسته. در گروه، کارت‌های تأیید بستن (‎/kill، ⋮ بستن سشن)، ری‌استارت، حذف و تعویض مود، فهرست‌های انتخاب سشنی که ‎/kill،‏ ‎/restart،‏ ‎/delete،‏ ‎/mode،‏ ‎/stop،‏ ‎/rename و ‎/diff نشان می‌دهند، و کارت «ادامهٔ x1 در:» که زدن «ادامه» باز می‌کند (دکمه‌های مودش) فقط به کسی جواب می‌دهند که فرمان را فرستاده یا دکمه‌ای را زده که آن‌ها را باز کرده. زدن هر کس دیگری، حتی لغو، این را می‌گیرد: «این کارت مال ‎@alice است. برای کارت خودتان ‎/kill x2 بفرستید.» (با فرمان همان کارت) و چیزی را عوض نمی‌کند. خود کارت ‎/mode (اینکه یک سشن در چه مودی است) مال همه است: تعویضی که رویش زده شود یک کارت تأیید باز می‌کند که مال زننده است. کارت‌های ‎/new فقط به کسی که ‎/new را فرستاده جواب می‌دهند. صاحب یک کارت تا وقتی استفاده یا لغو شود، حتی بعد از ری‌استارت aipager، به خاطر سپرده می‌شود (۴۰۹۶ کارت آخر). کارت اسم ‎/new و سؤال اسم ‎/rename استثنا هستند: در هر حال بعد از ۱۰ دقیقه منقضی می‌شوند، پس بعد از ری‌استارت فرمان را دوباره بفرستید.
  • دکمه فقط در چت سشن خودش کار می‌کند. دکمه‌ای که هر جای دیگری زده شود جواب می‌دهد «این دکمه مال یک چت دیگر است.» و کاری نمی‌کند، و «ادامه» همیشه همان سشنی را که دکمه نام می‌برد ادامه می‌دهد، هیچ‌وقت سشن هم‌اسم یک چت دیگر را.
  • دکمه‌های قدیمی چیزی را عوض نمی‌کنند. دکمه‌ای که از یک کار قبلی، یا از قبل از اینکه سشن بسته شود و برگردد، جا مانده روی چیزی که الان در جریان است اثر نمی‌گذارد؛ همین را می‌گوید (فرمان‌ها ← دکمه‌های قدیمی را ببینید).

آنچه همه می‌بینند#

جواب‌ها به Claude. هر «اجازه بده»، «رد کن» و جواب، با اینکه چه کسی آن را داده، در چت زیر کارت سشن نوشته می‌شود:

text
✅ x1 · اجازه داده شد · @alice · Bash: ls -la /tmp
🚫 x1 · رد شد · @bob · WebFetch: https://example.com
✓ x1 · جواب داده شد · @carol · Which database? ← Postgres

چه کسی یک سشن را عوض کرد. زدن یک دکمه را فقط کسی که آن را می‌زند می‌بیند، پس در گروه هر نتیجه‌ای که یک سشن را عوض کند می‌گوید چه کسی این کار را کرد:

text
⚠️ x1 · @bob متوقف کرد
⏹ @bob سشن x2 را بست
🔄 @alice سشن [x1] را ری‌استارت کرد.
🗑️ @carol سشن [x3] را حذف کرد.
⚙️ @alice سشن را به 🤖 مود خودکار برد.
@alice تغییرش داد.          (زیر /settings)

کارت «آماده» می‌گوید چه کسی مود یا مدلش را عوض کرد («‎@bob مدل را به Opus عوض کرد.»). در چت خصوصی، این خط‌های نتیجه اسم کسی را نمی‌آورند. تغییری که در Mini App انجام شود در چت به‌شکل «... از Mini App» نوشته می‌شود (توقفی که از آنجا انجام شود، روی کارت سشن هم اسم آن شخص را می‌آورد).

ابزاری که یک قانون جلویش را گرفته. کار با «🛑 x1 · قانون ایمنی جلویش را گرفت: Write is in this role's deny_tools (متوقف شد)» متوقف می‌شود. اگر Claude Code برای ابزاری اجازه بخواهد که کسی که پیامش کار در جریان را شروع کرده نمی‌تواند از آن استفاده کند، ربات خودش «رد کن» را جواب می‌دهد، هیچ درخواستی نشان نمی‌دهد، و ⛔ x1 · Edit برای @bob (نقش user) مسدود شد را با خلاصهٔ آن اجرا زیرش می‌نویسد و اسم آن شخص را می‌آورد. کاری که پیام‌های چند نفر شروعش کرده وقتی مسدود می‌شود که هر کدام از آن‌ها نتواند از آن ابزار استفاده کند، و اسم همان یکی را می‌آورد. کاری که در ترمینال تایپ شده مال شماست و هیچ‌وقت با قانون‌های یک عضو مسدود نمی‌شود، مگر اینکه یک پیام تلگرام به آن اضافه شده باشد: آن‌وقت با قانون‌های کسی که آخرین پیام سشن را فرستاده چک می‌شود (وقتی آن معلوم نباشد، فهرست خود گروه). وقتی aipager نمی‌داند کار مال کیست (وقتی aipager ری‌استارت شد از قبل در جریان بود)، از قانون‌های کسی که آخرین پیام سشن را فرستاده استفاده می‌کند، و وقتی آن هم معلوم نباشد، از فهرست خود گروه.

وضعیت پیام‌ها. 👀 روی یک پیام یعنی به سشن ارسال شد (یا نگه داشته شده تا بتواند ارسال شود)؛ 👍 یعنی Claude آن را برداشت؛ 🤷 یعنی قبل از اینکه Claude آن را بردارد دور ریخته شد. ‎/whoami برچسب، نقش و قانون‌های شما در این چت را نشان می‌دهد.

نوار وضعیت سنجاق‌شده. گروه نوار وضعیت سنجاق‌شدهٔ خودش را دارد (فرمان‌ها ← نوار وضعیت سنجاق‌شده را ببینید) که فقط سشن‌های همین گروه را فهرست می‌کند، اگر ربات ادمینی باشد که اجازهٔ سنجاق کردن دارد. بدون این اجازه، نوار برای آن گروه کنار گذاشته می‌شود: پیام به جای اینکه سنجاق‌نشده در تاریخچه بماند پاک می‌شود.

ممیزی روی دیسک. ‎~/.claude/aipager-audit.jsonl هر تصمیم را با user_id،‏ username و چت ثبت می‌کند، تا بعداً بتوانید بازسازی کنید هر کس چه کرد. همیشه به انگلیسی نوشته می‌شود، به هر زبانی که چت باشد.

زبان. یک گروه یک زبان برای پیام‌ها، کارت‌ها و کیبوردهای خود aipager دارد که یک ادمین با ‎/language تنظیمش می‌کند؛ تا وقتی یک ادمین انتخابش کند انگلیسی است. هیچ‌وقت دنبال برنامهٔ تلگرام کسی نمی‌رود. چیزی که فقط یک نفر می‌بیند، یعنی پیام کوچک بعد از زدن یک دکمه، به زبان خود همان شخص است: انتخابش در چت خصوصی‌اش با ربات، وگرنه زبان برنامهٔ تلگرامش برای کسی که بعد از این نسخه اضافه شده، وگرنه زبان گروه. فقط متن aipager عوض می‌شود؛ Claude به همان زبانی جواب می‌دهد که هر کس برایش می‌نویسد. زبان‌ها را ببینید.

پیام‌ها کجا ارسال می‌شوند#

  • هر سشن مال یک چت است و همه‌چیزش به همان چت ارسال می‌شود: کارت‌ها، جواب‌ها، درخواست‌های اجازه، فایل‌ها و اعلان‌هایش. پیامی در یک چت هیچ‌وقت به سشن چت دیگری ارسال نمی‌شود، و اسم یک سشن فقط در چت خودش کار می‌کند: تایپ اسم سشن یک چت دیگر جواب «⚠️ سشنی به این اسم نیست» را می‌گیرد. سشنی که وقتی aipager بدون هیچ چتی اجرا می‌شد شروع شده، همین که aipager config چت‌ها را اضافه کند چتش را می‌گیرد؛ تا وقتی یک سشن چتی ندارد، هیچ چتی آن را فهرست نمی‌کند و نمی‌تواند رویش کاری بکند.
  • سشن‌هایی که در ترمینال شروع شده‌اند (aipager session <name>‎) مال چت خصوصی مالک‌اند: چت خصوصی‌ای که عضوش نقش owner (نقشی با bypass_safety) را دارد. با چند چت خصوصی که هیچ‌کدام مال مالک نیست، اولین چت خصوصی فهرست است؛ بدون هیچ چت خصوصی، اولین چت. در نصبی که چت خصوصی دارد هیچ‌وقت به یک گروه نمی‌روند.
  • آپگرید سوپرگروه خودکار دنبال می‌شود (وقتی تلگرام گروه را آپگرید می‌کند را ببینید).

ساختار aipager.yaml (بخش‌های تیمی)#

yaml
schema_version: 3
bot_token: "…"

scopes:
  - kind: dm
    chat_id: 12345       # چت خصوصی خودتان: آیدی‌اش همان آیدی کاربری شماست
    label: owner DM
    members:
      - id: 12345
        label: alice
        role: owner
  - kind: group
    chat_id: -100123456789
    label: team
    deny_tools: [Write, Edit]   # اختیاری: جواب «Block file edits»
    root: /home/alice/aipager-users/group-team   # پوشهٔ root اعضا
    members:
      - id: 12345        # آیدی کاربری تلگرام (نه برچسب، نه آیدی چت)
        label: alice     # اسمی که آن شخص در چت با آن نشان داده می‌شود (@alice)
        role: owner
      - id: 67890
        label: bob
        role: user
        deny_tools: [WebFetch]  # اختیاری، برای هر عضو
      - id: 11111
        label: charlie
        role: read_only

یک چت خصوصی و چت‌های گروهی کنار هم کار می‌کنند: ربات در همهٔ چت‌های فهرست‌شده کار می‌کند و سشن‌های هر چت از هم جدا می‌مانند. aipager config این فایل را می‌نویسد؛ هیچ‌وقت لازم نیست ویرایشش کنید.

قانون‌ها چطور کار می‌کنند#

‏‎~/.config/aipager/policy.yaml قانون‌های هر نقش را تعریف می‌کند. با aipager policy validate چکش کنید. فیلدهای پشتیبانی‌شدهٔ هر نقش (جدا از آن‌هایی که در نقش‌های سفارشی آمده):

  • ‏deny_tools: اسم ابزارهایی که بدون پرسیدن رد می‌شوند (مثلاً Write،‏ Edit،‏ Bash،‏ WebFetch).
  • ‏allow_tools: اگر خالی نباشد، یک فهرست مجاز است: هر چیز دیگری برای آن نقش رد می‌شود.
  • ‏deny_bash_patterns: الگوهایی که با ورودی‌های Bash جور می‌شوند.
  • ‏deny_paths_no_access /‏ deny_paths_no_write: قانون‌های مسیر. برای user،‏ read_only و هر نقشی که بدون bypass_role_denies تعریف می‌کنید، deny_paths_no_access با فایل‌های اطلاعات ورودی که بالا زیر user آمده شروع می‌شود؛ تنظیمش آن فهرست را عوض می‌کند، پس آن‌هایی را که می‌خواهید نگه دارید در فهرست خودتان کپی کنید (کار در جریانی که پیام دیگری به آن اضافه شود تا تمام شدن دوباره به آن فهرست محدود می‌شود). قانونی بدون / یا ~ در اول (‎**/.env) هر جایی جور می‌شود، پس تا وقتی چنین قانونی هست، هر Grep/Glob یک نقش محدود رد می‌شود (هر جست‌وجویی می‌توانست چنین فایلی را بخواند)، و این آن کار را متوقف می‌کند.

‏deny_tools یک چت و deny_tools یک عضو در aipager.yaml به فهرست نقش اضافه می‌شوند، و allow_tools یک عضو به فهرست مجاز نقش اضافه می‌شود. همهٔ این‌ها فقط روی نقش‌هایی بدون bypass_role_denies اعمال می‌شوند: یک مالک یا ادمین تحت تأثیرشان نیست.

فایل‌های ‎~/.config/aipager/policy.d/*.yaml بعد از policy.yaml و به ترتیب اسم، با همان قالب خوانده می‌شوند: فیلد نقشی که در فایل بعدی تنظیم شود جای مقدار قبلی را می‌گیرد، و یک فهرست safety:‎ فقط اضافه می‌کند. aipager policy validate همه را چک می‌کند.

زیر همهٔ نقش‌ها یک کف ایمنی هست (مسیرهای محافظت‌شده و الگوهای دستور) که فقط owner از آن معاف است: ادمین‌ها هم به آن محدودند. این کف فهرست داخلی aipager به‌علاوهٔ بخش safety:‎ در policy.yaml است که فقط می‌تواند به آن اضافه کند:

yaml
safety:
  deny_paths_no_access: [/srv/secrets/**]   # نه خواندن، نه نوشتن، نه جست‌وجو
  deny_paths_no_write: [~/notes/**]         # خواندن آری، نوشتن نه
  deny_bash_patterns: ['\bcurl\b']          # دستورهای Bash که بسته می‌شوند

هر کار هر نقشی جز owner همهٔ آن را می‌گیرد، و همین‌طور کارهایی که aipager نمی‌تواند به کسی نسبت دهد؛ aipager doctor --safety-check آنچه را اعمال می‌شود فهرست می‌کند. بعد از خواندن دوبارهٔ تنظیمات، تغییری در آن روی پیام‌هایی اعمال می‌شود که بعد از آن فرستاده می‌شوند؛ کاری که از قبل در جریان است، یا پیامی که از قبل در صف منتظر است، فهرست قدیمی را نگه می‌دارد (برای اعمال فوری تغییر، آن کار را متوقف کنید). مسیری در deny_paths_no_access آنجا که بدون / یا ~ در اول باشد هر جایی جور می‌شود، پس تا وقتی هست، هر Grep/Glob هر نقشی جز owner رد می‌شود (aipager doctor دربارهٔ آن هشدار می‌دهد). مسیرهای محافظت‌شده برای ابزارهای فایل Claude Code (Read،‏ Write،‏ Edit،‏ MultiEdit،‏ NotebookEdit،‏ LSP،‏ Grep،‏ Glob) برقرارند؛ Grep/Glob یک نقش محدود باید داخل پوشهٔ سشن هم بماند (جست‌وجوی ‎~/.config برای aipager/**‎ رد می‌شود). WebFetch از نظر مسیر چک نمی‌شود؛ SendUserFile (فایل‌هایی که Claude به چت می‌فرستد) مثل یک Read چک می‌شود، و یک عضو فقط از پوشهٔ root چت می‌فرستد (امنیت). کار تلگرامی که aipager نمی‌تواند به یک فرستنده نسبتش دهد کف را می‌گیرد که دست‌کم به سختی user است. «دوباره امتحان کن» با نقش کسی اجرا می‌شود که آن را زده، اگر همان شخص پیامی را که دوباره فرستاده می‌شود فرستاده باشد، وگرنه با کف. الگوهای دستور فقط برای نقشی مهم‌اند که Bash دارد، و آنجا یک فیلترند، نه یک دیوار؛ مدل امنیتی ← اجرای قانون‌ها در استفادهٔ تیمی را ببینید.

نکته‌های حریم خصوصی#

  • ربات فقط به چت‌های تنظیم‌شده گوش می‌دهد. اضافه کردن ربات به یک گروه دیگر آن را آنجا فعال نمی‌کند: هیچ‌وقت آنجا جواب نمی‌دهد. ولی یادداشت می‌کند چه کسی آنجا خطابش کرده (آیدی، یوزرنیم و اسمش، و آیدی و عنوان گروه) در ‎~/.claude/aipager-pending-users.json، تا aipager config بتواند آن گروه را اضافه کند. فقط شما می‌توانید آن فایل را بخوانید، و ۲۰۰ نفر آخری را که در ۳۰ روز گذشته دیده شده‌اند نگه می‌دارد.
  • اعضای read_only می‌توانند پیام‌ها، جواب‌ها و ورودی ابزارها را بخوانند. نمی‌توانند کاری بکنند، ولی همه‌چیز گروه را می‌بینند. اگر کاری باید از کسی پنهان بماند، آن شخص جایش در گروه نیست.
  • در نصبی که چت خصوصی دارد، سشن‌های ترمینال و سشن‌های چت خصوصی شما هیچ‌وقت در یک گروه دیده نمی‌شوند (پیام‌ها کجا ارسال می‌شوند را ببینید). سشن ترمینالی که یک aipager قدیمی‌تر از قبل به گروه برده مال گروه می‌ماند: ببندیدش، از سشن‌های بسته‌شدهٔ گروه حذفش کنید و دوباره شروعش کنید.
  • ‏aipager.yaml حالت دسترسی 0600 دارد (فقط مال صاحبش). aipager حالت دسترسی policy.yaml را تنظیم نمی‌کند: خودتان آن را فقط مال خودتان نگه دارید (chmod 600 ~/.config/aipager/policy.yaml).
  • لاگ ممیزی (‎~/.claude/aipager-audit.jsonl) حالت دسترسی جداگانه‌ای ندارد: به اندازهٔ پوشهٔ ‎~/.claude شما خصوصی است.

گرفتن دسترسی یک کاربر#

  1. ‏aipager config ← Edit a member ← آن چت ← آن شخص ← Remove member را اجرا کنید. برای گرفتن اجازهٔ پیام فرستادن ولی نگه داشتن اجازهٔ خواندن، به جایش از Set role استفاده کنید و read_only را انتخاب کنید. (برای اضافه کردن دوباره در آینده: Edit a scope ← آن گروه ← Add a member.) برای چت خصوصی خود یک نفر، سشن‌هایش را ببندید، بعد Edit a scope ← چت خصوصی او ← Remove this scope.
  2. ویزارد تنظیمات aipager را بدون ری‌استارت دوباره می‌خواند؛ می‌گوید «Scopes reloaded live». همان لحظه پیام‌های نگه‌داشته‌شده‌اش دور ریخته می‌شوند (🤷 و یک جواب «ارسال نشد») و کاری از او که هنوز در جریان است تا تمام شدن به کف محدود بسته می‌شود. برای تمام کردن فوری آن کار ‎/stop بفرستید.
  3. او را از گروه تلگرام هم حذف کنید. تا وقتی در آن است، هنوز می‌تواند هر چیزی را که آنجا نوشته می‌شود بخواند: کارت‌ها، جواب‌ها، ورودی ابزارها و درخواست‌های اجازه.

آنچه ویزارد بعد از قدم ۱ می‌گوید را چک کنید. اگر گفت aipager را ری‌استارت کنید، نتوانسته به آن برسد: ری‌استارتش کنید (aipager service stop، بعد aipager service start)، چون تا آن موقع فهرست قبلی اعضا هنوز در حافظه است. اگر گفت «Not applied»، مشکلی را که نام می‌برد درست کنید: aipager تا آن موقع تنظیمات قبلی را نگه می‌دارد. بعد از ویرایش دستی aipager.yaml، خودتان سیگنال خواندن دوباره را بفرستید (خواندن دوبارهٔ تنظیمات بدون ری‌استارت را ببینید).