RuleStack

Configs

Stacks

Compare

Diff

RuleStack

Configs

Stacks

Compare

Diff

Read API

RuleStack

Configs

Stacks

Compare

Diff

Read API

Diff/openclaw-openclaw-extensions-telegram-agents ↔ openclaw-openclaw-src-plugin-sdk-agents

Comparison

A · AGENTS.md · openclaw/openclawB · AGENTS.md · openclaw/openclaw
What each file covers, counted
DimensionSharedOnly in AOnly in BOverlap
Sections0950%
Commands0010%
Section tags23040%

What each file covers

Sections

0 shared · 9 only in A · 5 only in B
  • − Telegram Plugin Guide
  • − Reliability Invariants
  • − Core drain contracts (do not re-implement in Telegram)
  • − Telegram-owned (transport + channel policy)
  • − Streaming
  • − Telegram API Ownership
  • − Context And Authorization
  • − Interactive Surfaces
  • − Review Standard
  • + Plugin SDK Boundary
  • + Source Of Truth
  • + Boundary Rules
  • + Verification
  • + Expanding The Boundary

Commands

0 shared · 0 only in A · 1 only in B
  • + pnpm build

Section tags

2 shared · 3 only in A · 0 only in B
  • − git-pr
  • − security
  • − api
  •   code-style
  •   do-not

Line diff

+85 added−127 removed10 unchanged7.3% identical
openclaw/openclaw · extensions/telegram/AGENTS.md
@@ −1 @@
1# Telegram Plugin Guide
2 
3Read this before any change under `extensions/telegram/`. These are intentional
4maintainer decisions and review-binding invariants, not incidental
5implementation details. Also read `extensions/AGENTS.md` for the plugin
6boundary rules.
7 
8Verified against Telegram Bot API 10.2, July 14 2026.
9 
10## Reliability Invariants
 
 
 
 
 
 
 
 
 
 
 
 
 
11 
12### Core drain contracts (do not re-implement in Telegram)
13 
14Owned by `src/channels/message/ingress-drain.ts` (+ claim-owner, retry-policy).
15Proof: `src/channels/message/ingress-drain.test.ts`,
16`ingress-claim-owner.test.ts`, `ingress-retry-policy.test.ts`.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17 
18- Completed rows tombstone via `complete()`, never `delete`.
19- Complete at turn adoption, not settle. Deferred holds the claim; watchdog
20 stays armed through deferral; dead-letter reason `handler-timeout`.
21- One retry policy: attempt floor **and** age gate (defaults 8 / 24h).
22- Claim refresh heartbeat while dispatching/deferred (`claimLeaseMs / 3`).
23- Never silently complete on transient failure — release/fail via disposition.
24- Pre-adoption supersede tombstones; post-adoption interruption is core-owned
25 (reply-run registry / queue interrupt).
26 
27### Telegram-owned (transport + channel policy)
 
 
 
 
28 
29- Durable-before-ack on both transports. Polling: ingress worker advances its
30 offset only after the parent's committed spool enqueue
31 (`writeTelegramSpooledUpdate`). Webhook: respond 200 only after the spool
32 write; non-200 on write failure is the redelivery contract.
33- `update_id`↔event-id encoding and per-chat/topic lane derivation stay in
34 `telegram-ingress-spool.ts` / sequential-key.
35- Polling and webhook both: enqueue then pump
36 `createTelegramTransportIngressDrain(...).drainOnce()` — no private claim
37 loops.
38- Stall timeout: `OPENCLAW_TELEGRAM_SPOOLED_HANDLER_TIMEOUT_MS` →
39 `adoptionStallTimeoutMs` (default 5 min) via
40 `resolveTelegramAdoptionStallTimeoutMs`.
41- Non-retryable classifier: `telegram-ingress-non-retryable.ts`
42 (missing harness, dispatch-dedupe rollback).
43- Supersede predicate: `telegram-ingress-supersede.ts` — only abort text /
44 authorized-looking explicit commands (and ambient room_event pending) may
45 supersede pre-adoption work. Normal messages never supersede.
46- room_event ambient work shares the sequential lane so a later user turn can
47 supersede it pre-adoption; adopted user turns are never touched (core drain
48 supersede is pre-adoption only).
49- No per-message full-store writes. Hot-path SQLite writes are per-entry.
50 Rewriting a cache on every send or read stalls the event loop, and that
51 stall masquerades as a polling stall (the sent-message-cache regression).
52- Transport error classification. The getUpdates worker retries Bot API 5xx
53 and 429 locally, honoring `parameters.retry_after`; 401/404 stay fatal; 409
54 must propagate to the parent session, which owns webhook-conflict recovery.
55 Bot API errors carry `error_code`, not `.code`; parse non-2xx bodies
56 defensively (a 502 HTML page is not JSON).
57- Send funnel parity. The durable funnel (`send.ts`) and the streaming funnel
58 (`bot/delivery.*`) must degrade identically: rich-entity 400 falls back to
59 plain text, caption parse 400 falls back to a plain caption, quote-not-found
60 400 falls back to a legacy reply. New recoveries go into the shared
61 predicates (`send-error-predicates.ts`, `reply-parameters.ts`), never into
62 one funnel only.
63- Outbound flood waits honor `retry_after` up to
64 `TELEGRAM_OUTBOUND_RETRY_AFTER_CAP_MS`; do not re-clamp Telegram sends to the
65 generic channel retry ceiling.
66- Webhook security ordering. The secret header is validated first
67 (constant-time compare, single-header enforcement, connection close on 401);
68 the request rate limit budgets only failed-auth attempts so Telegram's own
69 delivery is never throttled.
70- Every owned undici transport gets closed on all exit paths: polling session,
71 webhook shutdown and startup failure, probe-cache eviction.
72 
73## Streaming
74 
75- Do not reintroduce `sendMessageDraft` for answer streaming. Telegram drafts
76 are ephemeral 30-second previews in private chats; final delivery still
77 requires a separate `sendMessage`. OpenClaw uses `sendMessage` plus
78 `editMessageText`, then finalizes in place so the user sees one persistent
79 answer.
80- Streaming owns one visible preview message. Edit it forward. Do not send an
81 extra final bubble unless the final edit genuinely failed.
82- Keep the first-preview debounce. If a provider sends token-sized deltas,
83 coalesce them into cumulative preview text instead of removing the debounce.
84- Respect Telegram limits in the Telegram layer. Text over 4096 chars chains
85 into continuation messages. Polls keep the current Bot API 12-option cap.
86 
87## Telegram API Ownership
88 
89- Prefer grammY primitives and Telegram-native helpers when they model the
90 behavior directly. Avoid custom Bot API wrappers for behavior grammY already
91 owns.
92- Throttling is bot-token scoped. All Telegram API clients for the same token
93 share one grammY `apiThrottler()` instance.
94- Do not silently retry failed topic sends without topic metadata. A
95 wrong-surface success is worse than a loud Telegram error.
96- DM topics and forum topics are distinct. `direct_messages_topic_id` and
97 `message_thread_id` are not interchangeable.
98 
99## Context And Authorization
100 
101- Reply context comes from OpenClaw-observed messages. Bot API updates expose
102 `reply_to_message`, but there is no arbitrary `getMessage(chat, id)`
103 hydration path later.
104- Current local chat context must outrank stale reply ancestry in the prompt.
105 Old replied-to messages should not look like the active conversation.
106- The group history window is always on for groups and bounded by
107 `historyLimit`. Do not reintroduce prompt-history gating modes; that
108 regression blinded ambient rooms.
109- The group history window is rolling. Use self-entry watermark selection for
110 "since your last reply" views; do not reintroduce destructive clears because
111 room events are not persisted to the session and cleared context is
112 unrecoverable.
113- Pairing is DM-only. Group and topic authorization need explicit config
114 allowlists.
115- Telegram allowlists use numeric sender IDs. Usernames are optional, mutable,
116 and not a reliable arbitrary-user lookup key in the Bot API.
117- Group and channel visible replies are policy-controlled. Normal room replies
118 stay private unless `messages.groupChat.visibleReplies: "automatic"` is set
119 or the agent explicitly calls `message.send`.
120 
121## Interactive Surfaces
122 
123- Native callbacks stay structured. Approval, native command, plugin, select,
124 and multiselect callbacks must not fall through as raw callback text.
125- Preserve callback values exactly, including delimiters such as `env|prod`.
126- Native slash commands should remain fast-pathable before full workspace and
127 agent-turn setup.
128 
129## Review Standard
130 
131- Telegram behavior PRs need real Telegram proof when they touch transport,
132 streaming, topics, callbacks, authorization, or reply context. Prefer the
133 bot-to-bot QA lane or an equivalent live Telegram probe over synthetic-only
134 validation.
135- Reliability PRs (spool, drain, retry, ack, offset paths) need crash-window
136 or restart-replay test proof, not just happy-path tests.
137 
openclaw/openclaw · src/plugin-sdk/AGENTS.md
@@ +1 @@
1# Plugin SDK Boundary
2 
3This directory is the public contract between plugins and core. Changes here
4can affect bundled plugins and third-party plugins.
 
 
5 
6## Source Of Truth
7 
8- Docs:
9 - `docs/plugins/sdk-overview.md`
10 - `docs/plugins/sdk-entrypoints.md`
11 - `docs/plugins/sdk-runtime.md`
12 - `docs/plugins/sdk-migration.md`
13 - `docs/plugins/architecture.md`
14- Definition files:
15 - `package.json`
16 - `scripts/lib/plugin-sdk-entrypoints.json`
17 - `src/plugin-sdk/entrypoints.ts`
18 - `src/plugin-sdk/api-baseline.ts`
19 - `src/plugin-sdk/plugin-entry.ts`
20 - `src/plugin-sdk/core.ts`
21 - `src/plugin-sdk/provider-entry.ts`
22 
23## Boundary Rules
24 
25- Host loads plugins; plugins should not reach through the SDK into arbitrary
26 host internals.
27- Prefer a small versioned host/kernel seam plus narrow documented SDK
28 entrypoints over broad convenience barrels.
29- Prefer narrow, purpose-built subpaths over broad convenience re-exports.
30- Do not expose implementation convenience from `src/channels/**`,
31 `src/agents/**`, `src/plugins/**`, or other internals unless you are
32 intentionally promoting a supported public contract.
33- Keep public SDK entrypoints cheap at module load. If a helper is only needed
34 on async paths such as send, monitor, probe, directory-live, login, or setup,
35 prefer a narrow `*.runtime` subpath over re-exporting it through a broad SDK
36 barrel that hot channel entrypoints import on startup.
37- Keep SDK facades acyclic. Do not add back-edge re-exports that route a
38 lightweight contract file back through heavier policy or runtime modules.
39- Do not mix static and dynamic imports for the same runtime surface when
40 shaping SDK seams. If a surface must stay lazy, keep the eager side on a
41 light contract file and the deferred side on a dedicated runtime subpath.
42- Prefer `api.runtime` or a focused SDK facade over telling extensions to reach
43 into host internals directly.
44- When core or tests need bundled plugin helpers, prefer the plugin package
45 `api.ts` or `runtime-api.ts` plus generic SDK capabilities. Do not add a
46 provider-named `src/plugin-sdk/<id>.ts` seam just to make core aware of a
47 bundled channel's private helpers.
48- Resolver/facade loader tests are the exception to broad source API coverage:
49 use generated tiny plugin fixtures for `api.js` / `runtime-api.js` fallback
50 behavior. Do not point those tests at real bundled plugin source APIs.
51- For provider work, prefer family-level seams over provider-specific seams.
52 Shared helpers should describe a reusable behavior such as replay policy,
53 tool-schema compat, payload normalization, stream-wrapper composition, or
54 transport decoration. Avoid adding a new SDK export that only wraps one
55 provider's local implementation unless there is already a second consumer.
56- Prefer named helpers over raw options objects when the options encode a
57 stable contract. Example: export a helper for "OpenAI-style Anthropic tool
58 payload compat" instead of making every plugin pass the same mode flags.
59- Keep transport/runtime policy and plugin-facing helpers aligned. If the same
60 behavior is used in plugin registration and in core runtime paths, expose one
61 shared helper instead of letting the two paths drift.
62- SDK subpaths should help callers resolve one capability or runtime need at a
63 time. Do not grow new surfaces that require broad runtime registry access as
64 the default path.
65- If a proposed SDK export mainly exists to let setup/config/control-plane code
66 execute plugin runtime, that is usually a boundary smell. Prefer metadata or
67 descriptor-driven control-plane seams first.
68 
69## Verification
 
 
 
 
 
 
 
70 
71- If you touch SDK seams that affect lazy loading, hot channel entrypoints, or
72 bundled plugin import topology, run `pnpm build`.
73- If the change can alter bundled channel startup cost, also run the isolated
74 entrypoint profiler for the affected plugin:
75 `OPENCLAW_LOCAL_CHECK=0 node scripts/profile-extension-memory.mjs --extension <id> --skip-combined --concurrency 1`
76 
77## Expanding The Boundary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78 
79- SDK surface is too large. Do not add compat barrels, aliases, or fallback exports for convenience. Replace old entrypoints when cleaner.
80- Public third-party API is the only compat exception: document/version breaks, migrate ALL bundled/internal plugins first, then aggressively deprecate unused exports.
81- When adding or changing a public subpath, keep these aligned:
82 - docs in `docs/plugins/*`
83 - `scripts/lib/plugin-sdk-entrypoints.json`
84 - `src/plugin-sdk/entrypoints.ts`
85 - `package.json` exports
86 - API baseline and export checks
87- If a bundled channel/helper need crosses package boundaries, first ask
88 whether the need is truly generic. If yes, add a narrow generic subpath. If
89 not, keep it plugin-local through `api.ts` / `runtime-api.ts`.
90- When expanding provider-facing seams, update or add the matching narrow tests
91 that lock the contract: Plugin SDK baseline/export checks for public subpaths
92 and the most direct provider/plugin tests for the behavior you are
93 centralizing.
94- Breaking removals or renames are major-version work, not drive-by cleanup.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95 
@@ −1 +1 @@
1−# Telegram Plugin Guide
1+# Plugin SDK Boundary
22  
3−Read this before any change under `extensions/telegram/`. These are intentional
4−maintainer decisions and review-binding invariants, not incidental
5−implementation details. Also read `extensions/AGENTS.md` for the plugin
6−boundary rules.
3+This directory is the public contract between plugins and core. Changes here
4+can affect bundled plugins and third-party plugins.
75  
8−Verified against Telegram Bot API 10.2, July 14 2026.
6+## Source Of Truth
97  
10−## Reliability Invariants
8+- Docs:
9+ - `docs/plugins/sdk-overview.md`
10+ - `docs/plugins/sdk-entrypoints.md`
11+ - `docs/plugins/sdk-runtime.md`
12+ - `docs/plugins/sdk-migration.md`
13+ - `docs/plugins/architecture.md`
14+- Definition files:
15+ - `package.json`
16+ - `scripts/lib/plugin-sdk-entrypoints.json`
17+ - `src/plugin-sdk/entrypoints.ts`
18+ - `src/plugin-sdk/api-baseline.ts`
19+ - `src/plugin-sdk/plugin-entry.ts`
20+ - `src/plugin-sdk/core.ts`
21+ - `src/plugin-sdk/provider-entry.ts`
1122  
12−### Core drain contracts (do not re-implement in Telegram)
23+## Boundary Rules
1324  
14−Owned by `src/channels/message/ingress-drain.ts` (+ claim-owner, retry-policy).
15−Proof: `src/channels/message/ingress-drain.test.ts`,
16−`ingress-claim-owner.test.ts`, `ingress-retry-policy.test.ts`.
25+- Host loads plugins; plugins should not reach through the SDK into arbitrary
26+ host internals.
27+- Prefer a small versioned host/kernel seam plus narrow documented SDK
28+ entrypoints over broad convenience barrels.
29+- Prefer narrow, purpose-built subpaths over broad convenience re-exports.
30+- Do not expose implementation convenience from `src/channels/**`,
31+ `src/agents/**`, `src/plugins/**`, or other internals unless you are
32+ intentionally promoting a supported public contract.
33+- Keep public SDK entrypoints cheap at module load. If a helper is only needed
34+ on async paths such as send, monitor, probe, directory-live, login, or setup,
35+ prefer a narrow `*.runtime` subpath over re-exporting it through a broad SDK
36+ barrel that hot channel entrypoints import on startup.
37+- Keep SDK facades acyclic. Do not add back-edge re-exports that route a
38+ lightweight contract file back through heavier policy or runtime modules.
39+- Do not mix static and dynamic imports for the same runtime surface when
40+ shaping SDK seams. If a surface must stay lazy, keep the eager side on a
41+ light contract file and the deferred side on a dedicated runtime subpath.
42+- Prefer `api.runtime` or a focused SDK facade over telling extensions to reach
43+ into host internals directly.
44+- When core or tests need bundled plugin helpers, prefer the plugin package
45+ `api.ts` or `runtime-api.ts` plus generic SDK capabilities. Do not add a
46+ provider-named `src/plugin-sdk/<id>.ts` seam just to make core aware of a
47+ bundled channel's private helpers.
48+- Resolver/facade loader tests are the exception to broad source API coverage:
49+ use generated tiny plugin fixtures for `api.js` / `runtime-api.js` fallback
50+ behavior. Do not point those tests at real bundled plugin source APIs.
51+- For provider work, prefer family-level seams over provider-specific seams.
52+ Shared helpers should describe a reusable behavior such as replay policy,
53+ tool-schema compat, payload normalization, stream-wrapper composition, or
54+ transport decoration. Avoid adding a new SDK export that only wraps one
55+ provider's local implementation unless there is already a second consumer.
56+- Prefer named helpers over raw options objects when the options encode a
57+ stable contract. Example: export a helper for "OpenAI-style Anthropic tool
58+ payload compat" instead of making every plugin pass the same mode flags.
59+- Keep transport/runtime policy and plugin-facing helpers aligned. If the same
60+ behavior is used in plugin registration and in core runtime paths, expose one
61+ shared helper instead of letting the two paths drift.
62+- SDK subpaths should help callers resolve one capability or runtime need at a
63+ time. Do not grow new surfaces that require broad runtime registry access as
64+ the default path.
65+- If a proposed SDK export mainly exists to let setup/config/control-plane code
66+ execute plugin runtime, that is usually a boundary smell. Prefer metadata or
67+ descriptor-driven control-plane seams first.
1768  
18−- Completed rows tombstone via `complete()`, never `delete`.
19−- Complete at turn adoption, not settle. Deferred holds the claim; watchdog
20− stays armed through deferral; dead-letter reason `handler-timeout`.
21−- One retry policy: attempt floor **and** age gate (defaults 8 / 24h).
22−- Claim refresh heartbeat while dispatching/deferred (`claimLeaseMs / 3`).
23−- Never silently complete on transient failure — release/fail via disposition.
24−- Pre-adoption supersede tombstones; post-adoption interruption is core-owned
25− (reply-run registry / queue interrupt).
69+## Verification
2670  
27−### Telegram-owned (transport + channel policy)
71+- If you touch SDK seams that affect lazy loading, hot channel entrypoints, or
72+ bundled plugin import topology, run `pnpm build`.
73+- If the change can alter bundled channel startup cost, also run the isolated
74+ entrypoint profiler for the affected plugin:
75+ `OPENCLAW_LOCAL_CHECK=0 node scripts/profile-extension-memory.mjs --extension <id> --skip-combined --concurrency 1`
2876  
29−- Durable-before-ack on both transports. Polling: ingress worker advances its
30− offset only after the parent's committed spool enqueue
31− (`writeTelegramSpooledUpdate`). Webhook: respond 200 only after the spool
32− write; non-200 on write failure is the redelivery contract.
33−- `update_id`↔event-id encoding and per-chat/topic lane derivation stay in
34− `telegram-ingress-spool.ts` / sequential-key.
35−- Polling and webhook both: enqueue then pump
36− `createTelegramTransportIngressDrain(...).drainOnce()` — no private claim
37− loops.
38−- Stall timeout: `OPENCLAW_TELEGRAM_SPOOLED_HANDLER_TIMEOUT_MS` →
39− `adoptionStallTimeoutMs` (default 5 min) via
40− `resolveTelegramAdoptionStallTimeoutMs`.
41−- Non-retryable classifier: `telegram-ingress-non-retryable.ts`
42− (missing harness, dispatch-dedupe rollback).
43−- Supersede predicate: `telegram-ingress-supersede.ts` — only abort text /
44− authorized-looking explicit commands (and ambient room_event pending) may
45− supersede pre-adoption work. Normal messages never supersede.
46−- room_event ambient work shares the sequential lane so a later user turn can
47− supersede it pre-adoption; adopted user turns are never touched (core drain
48− supersede is pre-adoption only).
49−- No per-message full-store writes. Hot-path SQLite writes are per-entry.
50− Rewriting a cache on every send or read stalls the event loop, and that
51− stall masquerades as a polling stall (the sent-message-cache regression).
52−- Transport error classification. The getUpdates worker retries Bot API 5xx
53− and 429 locally, honoring `parameters.retry_after`; 401/404 stay fatal; 409
54− must propagate to the parent session, which owns webhook-conflict recovery.
55− Bot API errors carry `error_code`, not `.code`; parse non-2xx bodies
56− defensively (a 502 HTML page is not JSON).
57−- Send funnel parity. The durable funnel (`send.ts`) and the streaming funnel
58− (`bot/delivery.*`) must degrade identically: rich-entity 400 falls back to
59− plain text, caption parse 400 falls back to a plain caption, quote-not-found
60− 400 falls back to a legacy reply. New recoveries go into the shared
61− predicates (`send-error-predicates.ts`, `reply-parameters.ts`), never into
62− one funnel only.
63−- Outbound flood waits honor `retry_after` up to
64− `TELEGRAM_OUTBOUND_RETRY_AFTER_CAP_MS`; do not re-clamp Telegram sends to the
65− generic channel retry ceiling.
66−- Webhook security ordering. The secret header is validated first
67− (constant-time compare, single-header enforcement, connection close on 401);
68− the request rate limit budgets only failed-auth attempts so Telegram's own
69− delivery is never throttled.
70−- Every owned undici transport gets closed on all exit paths: polling session,
71− webhook shutdown and startup failure, probe-cache eviction.
77+## Expanding The Boundary
7278  
73−## Streaming
74− 
75−- Do not reintroduce `sendMessageDraft` for answer streaming. Telegram drafts
76− are ephemeral 30-second previews in private chats; final delivery still
77− requires a separate `sendMessage`. OpenClaw uses `sendMessage` plus
78− `editMessageText`, then finalizes in place so the user sees one persistent
79− answer.
80−- Streaming owns one visible preview message. Edit it forward. Do not send an
81− extra final bubble unless the final edit genuinely failed.
82−- Keep the first-preview debounce. If a provider sends token-sized deltas,
83− coalesce them into cumulative preview text instead of removing the debounce.
84−- Respect Telegram limits in the Telegram layer. Text over 4096 chars chains
85− into continuation messages. Polls keep the current Bot API 12-option cap.
86− 
87−## Telegram API Ownership
88− 
89−- Prefer grammY primitives and Telegram-native helpers when they model the
90− behavior directly. Avoid custom Bot API wrappers for behavior grammY already
91− owns.
92−- Throttling is bot-token scoped. All Telegram API clients for the same token
93− share one grammY `apiThrottler()` instance.
94−- Do not silently retry failed topic sends without topic metadata. A
95− wrong-surface success is worse than a loud Telegram error.
96−- DM topics and forum topics are distinct. `direct_messages_topic_id` and
97− `message_thread_id` are not interchangeable.
98− 
99−## Context And Authorization
100− 
101−- Reply context comes from OpenClaw-observed messages. Bot API updates expose
102− `reply_to_message`, but there is no arbitrary `getMessage(chat, id)`
103− hydration path later.
104−- Current local chat context must outrank stale reply ancestry in the prompt.
105− Old replied-to messages should not look like the active conversation.
106−- The group history window is always on for groups and bounded by
107− `historyLimit`. Do not reintroduce prompt-history gating modes; that
108− regression blinded ambient rooms.
109−- The group history window is rolling. Use self-entry watermark selection for
110− "since your last reply" views; do not reintroduce destructive clears because
111− room events are not persisted to the session and cleared context is
112− unrecoverable.
113−- Pairing is DM-only. Group and topic authorization need explicit config
114− allowlists.
115−- Telegram allowlists use numeric sender IDs. Usernames are optional, mutable,
116− and not a reliable arbitrary-user lookup key in the Bot API.
117−- Group and channel visible replies are policy-controlled. Normal room replies
118− stay private unless `messages.groupChat.visibleReplies: "automatic"` is set
119− or the agent explicitly calls `message.send`.
120− 
121−## Interactive Surfaces
122− 
123−- Native callbacks stay structured. Approval, native command, plugin, select,
124− and multiselect callbacks must not fall through as raw callback text.
125−- Preserve callback values exactly, including delimiters such as `env|prod`.
126−- Native slash commands should remain fast-pathable before full workspace and
127− agent-turn setup.
128− 
129−## Review Standard
130− 
131−- Telegram behavior PRs need real Telegram proof when they touch transport,
132− streaming, topics, callbacks, authorization, or reply context. Prefer the
133− bot-to-bot QA lane or an equivalent live Telegram probe over synthetic-only
134− validation.
135−- Reliability PRs (spool, drain, retry, ack, offset paths) need crash-window
136− or restart-replay test proof, not just happy-path tests.
79+- SDK surface is too large. Do not add compat barrels, aliases, or fallback exports for convenience. Replace old entrypoints when cleaner.
80+- Public third-party API is the only compat exception: document/version breaks, migrate ALL bundled/internal plugins first, then aggressively deprecate unused exports.
81+- When adding or changing a public subpath, keep these aligned:
82+ - docs in `docs/plugins/*`
83+ - `scripts/lib/plugin-sdk-entrypoints.json`
84+ - `src/plugin-sdk/entrypoints.ts`
85+ - `package.json` exports
86+ - API baseline and export checks
87+- If a bundled channel/helper need crosses package boundaries, first ask
88+ whether the need is truly generic. If yes, add a narrow generic subpath. If
89+ not, keep it plugin-local through `api.ts` / `runtime-api.ts`.
90+- When expanding provider-facing seams, update or add the matching narrow tests
91+ that lock the contract: Plugin SDK baseline/export checks for public subpaths
92+ and the most direct provider/plugin tests for the behavior you are
93+ centralizing.
94+- Breaking removals or renames are major-version work, not drive-by cleanup.
13795  
RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack

RuleStack

Built by

Kynth Studio

Directory

Configs
Stacks
Compare formats
Diff two configs
Best AGENTS.md examples

Formats

AGENTS.md
CLAUDE.md
Cursor rules
Copilot instructions

Reference

Read API
Corpus health
Privacy Policy
Terms

RuleStack