docs(skills): agent-facing skills + 12 SDK-native recipes#38
Conversation
Adapt the VibeCode reference docs (docs/llms-full.txt) into b24jssdk
idioms and land them in two places:
- .claude/skills/ — agent-facing skills:
- b24jssdk-core: pick the right entry point, boot, error handling
- b24jssdk-rest: callMethod / callBatch / callListMethod / fetchListMethod
- b24jssdk-filtering: Bitrix24 prefix-style filters, dates, multi-funnel
- b24jssdk-frame-ui: slider, dialog, parent, placement, options
- b24jssdk-helpers: useB24Helper, Pull client, currency
- b24jssdk-recipes: 9 end-to-end TS recipes (CRM analytics, mass
messaging, task automation, ERP sync, disk, Telegram bot, webhook
handler, AI assistant, web-search RAG)
- b24jssdk-vibecode: when/how to combine SDK with the VibeCode HTTP API
- docs/content/docs/99.examples/: matching docs pages with the same 9
recipes, replacing the placeholder index
Each recipe is server-side via B24Hook by default; recipe bodies take
TypeB24 so the same code runs unchanged from B24Frame and B24OAuth.
Translation rules + maintenance playbook for the weekly llms-full.txt
review live in .claude/skills/MAINTENANCE.md and REPORT.md, with
follow-up gaps tracked in SUGGESTED-EXAMPLES.md.
Also exclude .claude/** from the repo eslint pass — these are templates
for AI agents, not project source.
The legacy SDK surface — callMethod / callBatch / callBatchByChunk / callListMethod / fetchListMethod, plus AjaxResult.isMore()/getNext()/ getTotal() — is @deprecated and scheduled for removal in 2.0.0 (see packages/jssdk/README-AI.md "Deprecation notice"). Rewrite every skill and recipe to use $b24.actions.v{2,3}.*.make() instead. Per-skill changes: - b24jssdk-rest: complete rewrite around call/batch/callList/fetchList/ batchByChunk for both API versions. Documents the new AjaxResult shape (getData() -> SuccessPayload<T> | undefined), v3 all-or-nothing batch semantics, null-result passthrough, v3 method whitelist (~9 methods today per version-manager.ts). - b24jssdk-filtering: keep the v2 prefix dialect, add the v3 array-of- triples dialect ([['fld', 'op', val]]). 8 operators only in v3 (no like/%); document order-stripping in callList; use Text.toB24Format for dates. - b24jssdk-core: new section on hardErrorCodes / softErrorCodes / retryOnNetworkError tuning via setRestrictionManagerParams. - b24jssdk-frame-ui: un-deprecate selectCRM (re-implemented to normalize response buckets), document placement.setValue convenience helper. - b24jssdk-helpers: correct usePullClient() to arg-less form, mention new isInitB24Helper() getter. - b24jssdk-recipes + 9 example .ts files: rewrite all to actions API. CRM stays on v2 (not on the v3 whitelist yet); tasks.task.* switched to v3 where on the whitelist (add/get/update/delete). - b24jssdk-vibecode: AI-add-on example updated to the new surface. Top-level docs: README links to bitrix24-rest-v3-reference.md as the canonical v3 protocol source. MAINTENANCE translation table now uses actions.v{2,3}.*.make. REPORT logs anchor facts and open questions (OAuth install handshake is the biggest remaining gap). SUGGESTED- EXAMPLES re-prioritised with the new info. docs/content/docs/99.examples: index + recipe 1 fully rewritten to the new surface; recipes 2-9 markdown pages have their API references updated (full code lives in .claude/skills/.../examples/).
… OAuth install Closes the top-three items from SUGGESTED-EXAMPLES.md: - Recipe 10 (error-handling cookbook): demonstrates the four error layers (SdkError / AjaxError / network-level / soft) and the new restriction- manager knobs (hardErrorCodes, softErrorCodes, retryOnNetworkError) via setRestrictionManagerParams. Shows the non-idempotent-call safety pattern (retryOnNetworkError: false + try/finally restore). - Recipe 11 (event registration): CLI tool to list / bind / unbind outbound webhook events via event.get / event.bind / event.unbind. Closes the loop on recipe 7 (which receives events but doesn't register them). Idempotent — ERROR_EVENT_BINDING_EXISTS treated as success. - Recipe 12 (OAuth install handshake): the largest missing piece for Marketplace-listed apps. Express server that handles ONAPPINSTALL / ONAPPUPDATE / ONAPPUNINSTALL, persists tokens per member_id, builds B24OAuth on demand, wires setCallbackRefreshAuth to write the latest token pair back to storage. Includes a demo endpoint GET /portal/:memberId/profile. Also adds matching markdown pages under docs/content/docs/99.examples/ and updates SUGGESTED-EXAMPLES.md (Done section + re-prioritised recommendations).
Self-review of #38 found that recipes were referencing `e.description` on AjaxError / SdkError, but neither class exposes a `description` property — it's a constructor param only. The thrown errors expose `code`, `status`, `message` (inherited from Error), and AjaxError adds `requestInfo`. This was hidden because `.claude/**` is excluded from the workspace tsconfig and eslint config, so `pnpm run lint && pnpm run typecheck` did NOT catch the typos. Verified by running tsc with a private tsconfig that points `@bitrix24/b24jssdk` at the SDK source. Fixes: - 02-mass-messaging.ts: e.description → e.message - 05-disk-files.ts: tighten batch result cast through `unknown` - 07-webhook-handler.ts: annotate /health callback with Request/Response - 10-error-handling.ts: e.description → e.message (×2); e.requestInfo.method → e.requestInfo?.method (optional in shape); reference helper fns with `void` so they read as used - 12-oauth-install.ts: e.description → e.message; annotate all express callbacks with Request/Response - b24jssdk-core SKILL.md: same fix in the canonical error-handling template - b24jssdk-rest SKILL.md: same fix in the error-handling template Remaining typecheck warnings against the recipes are only TS2307/TS7006/ TS7016 for opt-in deps (node-cron, grammy, openai, express) — expected, those install with the recipe per the SKILL.md instructions.
Acts on the four follow-ups from the self-review of PR #38: 1. Recipes are now part of `pnpm run typecheck`. New tsconfig at `.claude/skills/b24jssdk-recipes/tsconfig.json` typechecks every recipe against the built SDK types (the bug from `e17be22` — `e.description` on AjaxError / SdkError — would have been caught here automatically). External opt-in packages (grammy / openai / express / node-cron) are stubbed as `any` via `types/external.d.ts` so the workspace doesn't have to ship them. Wired the new `skills:typecheck` script into the root `typecheck` pipeline. Documented the contract (build SDK first via `dev:prepare`; add a new `declare module` to the stubs when adding a recipe with a new external dep) in MAINTENANCE.md. Side effect of running real typecheck against the built dist: caught one more bug — grammy `ctx` parameters defaulted to `any` (recipe 6). Annotated explicitly to make the implicit-any deliberate. 2. Recipe 12 (OAuth install) now verifies `application_token` on uninstall — without this guard any caller that knows the URL could delete credentials for any portal whose member_id they guess. Also replies 200 first, verifies after, so a bad payload doesn't keep Bitrix24 retrying for 24h. 3. Recipe 7 (webhook handler) now reads `B24_APPLICATION_TOKEN` from the env and compares against `payload.auth?.application_token`. Optional (skipped if the env var is empty) so local smoke tests stay simple. Doc page references recipe 11 for event registration instead of the generic "via crm.event.bind or portal admin" line. 4. Recipe docs 4 and 6: added concrete cross-references for scaling — recipe 4 points at `batchByChunk.make` for bulk create, recipe 6 at `batch.make` for per-tick contact lookups.
Adds grammy, openai, express, node-cron and the two `@types/*` packages
that don't ship inline types (@types/express, @types/node-cron) as
workspace devDeps. Removes the placeholder stubs at
`.claude/skills/b24jssdk-recipes/types/external.d.ts`.
Effect: `pnpm run skills:typecheck` now validates not just SDK API
correctness, but also misuse of the recipe-side packages. The real
types caught one more bug — recipe 12 was passing `req.params.memberId`
to `clientForMember(memberId: string)`, but Express 5's `ParamsDictionary`
types each param as `string | string[]`. Fixed by adding the
`Request<{ memberId: string }>` generic on the handler.
MAINTENANCE.md updated: the "external stubs" workflow is replaced with
"install the package and its @types/* as workspace devDeps".
…first Second-pass review of PR #38 found a few small things: 1. `tsconfig.json` `include` referenced `types/external.d.ts` which was deleted in 42c1d85. Removed the dangling glob. 2. Enabled `noUnusedLocals` / `noUnusedParameters` in the recipes tsconfig so dead helpers don't slip through (the previous review's `void safeCreateDeal` trick now has a strict checker behind it). Caught one unused helper in recipe 5 (`getFile`) and marked it the same way — `void getFile` with a comment explaining the educational purpose. 3. Recipe 12: handleInstall now follows the same reply-first / verify- after pattern as handleUninstall. If saveCredentials stalls (disk contention on the demo file store) Bitrix24 won't time out and retry. 4. Recipe 12: dropped redundant `B24OAuthParams & { applicationToken }` intersection — the type already includes the field. Renamed StoredCredentials to a plain alias.
Two real-world-behaviour issues called out in the third review: 1. Recipe 10 `safeCreateDeal`: setRestrictionManagerParams is instance- global, not per-call. Updated the inline comment with a GOTCHA block so readers copying the pattern into a concurrent codepath know that the policy applies to every call on the same $b24, and offers two alternatives (dedicated $b24 instance for non-idempotent flows, or per-method idempotency tokens). 2. Recipe 6 Telegram tick: a Telegram 429 / network error would abort the whole loop, leaving the cursor unchanged so the unsent deals were retried on the next tick — that part was fine. But isolating each send with try/catch (suggested in the review) introduced a NEW regression: a mid-batch failure followed by successes would advance the cursor past the failed deal, dropping it forever. Fixed by only advancing lastSeenDealId across the contiguous prefix of successes (sawFailure flag). Failed deals + everything after are retried on the next tick; preceding successes are not re-sent.
choosing-the-right-method.md - Add explicit caution block at the top: don't use the legacy AbstractB24 shortcuts (callMethod / callBatch / callListMethod / fetchListMethod / callBatchByChunk). They're @deprecated, emit a runtime warning on every call, and slated for removal in v2.0.0. Always go through b24.actions.v{2,3}.<primitive>.make(); link to the v0 → v1 migration guide for the one-to-one rewrites. - Mention canonical API surface in the Overview so the reader sees the right shape before the decision matrix. - Rewrite all five anti-patterns to name the canonical methods explicitly (e.g. `actions.v2.batch.make` instead of the short "Batch") and to lead with the deprecated-shortcut anti-pattern. - Bump audited to 2026-05-26. errors.md (follow-up to the user's #fd489ba ::rest-api-version-only rewrite) - Fix copy-paste bug in the v3 fetchList catch example: error.code comparison referenced JSSDK_CORE_B24_FETCH_LIST_METHOD_API_V2; must be _V3 in the v3 slot. Verified no other open PR touches these two pages (PR #38 covers adjacent material in .claude/skills/ but doesn't modify them). docs:lint-pages → 0/0, docs:lint-links → 0/0. https://claude.ai/code/session_01SexCZHTfKJDrfEU62hcQ54
# Conflicts: # docs/content/docs/99.examples/0.index.md # package.json
Ревью от автора PR #34 — рекомендации к интеграцииКонтекст: PR #34 ( Сильные стороны (важно зафиксировать — за ними стоит свой PR при будущих изменениях)
Конкретные предложения1. Discoverability через AGENTS.md (must-have)
Предлагаю добавить секцию после ## Agent Skills (.claude/skills/)
For AI coding agents, the canonical skills are under `.claude/skills/`.
Load these by topic — do not load everything at once.
| Skill | When to use |
|------|--------|
| `b24jssdk-core` | First skill to load — entry point pick (Hook / Frame / OAuth), boot/teardown, error tuning |
| `b24jssdk-rest` | `actions.v{2,3}.*.make()` — call / batch / callList / fetchList / batchByChunk |
| `b24jssdk-filtering` | v2 prefix-keyed filter vs v3 array-of-triples; operators; `Text.toB24Format` |
| `b24jssdk-frame-ui` | iframe-only managers: slider / dialog / parent / placement / options / auth |
| `b24jssdk-helpers` | `useB24Helper`, Pull client, currency formatting, app/user options |
| `b24jssdk-recipes` | 12 end-to-end mini-apps; recipes are CI-validated TS |
| `b24jssdk-vibecode` | When to combine the SDK with the VibeCode HTTP API |
Maintenance / report docs sit alongside in `.claude/skills/MAINTENANCE.md`,
`REPORT.md`, `SUGGESTED-EXAMPLES.md`.Это та же правка, которую я делал в 2. Cross-link
|
| Docs страница | Skill ссылка |
|---|---|
1.call-rest-api-ver{2,3}.md |
.claude/skills/b24jssdk-rest/SKILL.md |
2.call-list-rest-api-ver{2,3}.md, 2.fetch-list-rest-api-ver{2,3}.md |
.claude/skills/b24jssdk-rest/SKILL.md |
3.batch-rest-api-ver{2,3}.md, 4.batch-by-chunk-rest-api-ver{2,3}.md |
.claude/skills/b24jssdk-rest/SKILL.md |
30.frame*.md, 31.frame-*.md |
.claude/skills/b24jssdk-frame-ui/SKILL.md |
66.logger.md |
(нет соответствия — skip) |
77.limiters.md |
.claude/skills/b24jssdk-core/SKILL.md (там, где про hardErrorCodes / retryOnNetworkError) |
Применять через тот же iconName: GitHubIcon пункт в links:.
4. Audit-stamp на новые examples-страницы
В AGENTS.md зафиксировано требование audited: YYYY-MM-DD для страниц с category: actions / tools, и docs:lint-pages это проверяет. В 99.examples/*.md поле сейчас отсутствует. По AGENTS.md examples — «отдельный, более лёгкий скелет, не lint'ится» — формально проходит. Но если кто-то скрипту даст --strict — будут варнинги. Стоит либо явно опустить (как сейчас и есть, оставить), либо проставить дату для согласованности — на усмотрение.
5. Маленькая косметика в recipes — offClientSideWarning?.()
Recipe 1 (и, кажется, ещё пара): $b24.offClientSideWarning?.() — opional chaining намекает, что метод может отсутствовать. После рефакторинга http-клиента он есть на всех concrete entry points (B24Hook, B24OAuth). ?. тут безвреден, но создаёт ложное впечатление вариативности. Достаточно: $b24.offClientSideWarning().
Сверка фактов с исходниками (всё ОК — оставляю для протокола)
usePullClient()arg-less —packages/jssdk/src/helper/use-b24-helper.ts:52— да, без аргументов. Skill корректен. (В моём docs(skills): add agent skills for the SDK #34 я унаследовалusePullClient('prefix')из старогоREADME-AI.md— это была ошибка с моей стороны. Хорошо, что у вас по-другому.)- v3 supported методы —
core/version-manager.ts:21-44. Список вb24jssdk-rest/SKILL.mdсовпадает. ✓ - Filter dialects —
actions/v2/call-list.tsиactions/v3/call-list.ts. v2 = operator-prefixed object, v3 = array of triples. Совпадает. ✓ callList/fetchListигнорируютorder—actions/v2/call-list.ts:77-79и v3 mirror. Skill ссылается на правильный код, варнинг описан. ✓AjaxResult.getData()shape —core/http/ajax-result.ts. ВозвращаетSuccessPayload<T> | undefined. Skill правильно требует!илиisSuccesscheck. ✓- v3 batch all-or-nothing — подтверждается. Skill это отмечает. ✓
idKey: 'id'дляcrm.item.*(lowercase fields в v2) — фактически верно. Подтверждаю по своему ручному тестированию во время docs(skills): add agent skills for the SDK #34.customKeyForResult: 'items'обязателен дляcrm.item.list— да, иначе пустой массив на выходе. Anti-pattern вb24jssdk-restэто ловит правильно. ✓
Известное в REPORT.md, что я бы пометил приоритетом
Из «Open questions» в REPORT.md:
- Recipe 7 webhook payload shape (
data[FIELDS][ID]черезexpress.urlencoded) — рекомендую проверить до мержа на живом outbound webhook. Это единственный recipe, где payload-shape не верифицирован против реального портала, и он не падает на typecheck — только в рантайме у потребителя. - Recipe 9 timeline comment (
ENTITY_TYPE: 'deal'vsENTITY_TYPE_ID: 2) — у меня тоже встречалась эта неоднозначность в SDK-документации; для нас сработалоENTITY_TYPE_ID. Рекомендую заменить наENTITY_TYPE_ID: 2в основном примере + комментарием упомянуть string-fallback.
Резюме
Контент PR качественнее моего по структуре, валидации и охвату. Перечисленные выше предложения не блокирующие — пятёрка (3 → 4 → 5) делается одним маленьким коммитом перед мержем, пункт (1) — отдельным следующим. Главное, что стоит подобрать: discoverability через AGENTS.md (#1) и cross-link существующих REST docs (#3) — это то, что у меня было готово, легко переносится в этот PR и закрывает реальные дыры в связности.
Если решите, что подобрать (1)/(3) в этом PR — могу подготовить патч одним коммитом, скажите.
PR #34 закрою после мержа этого.
— Игорь
Generated by Claude Code
…inks + polish Acts on the review comment from PR #34 author (which is being closed in favour of this one): #38 (comment) 1. AGENTS.md — new "Agent Skills" section listing the 7 skills with a one-line "when to use" table. Without this, a human / 3rd-party agent reading AGENTS.md as the "single source of truth" doesn't discover `.claude/skills/`. 2. .github/contributing/*.md — added an "Agent-facing mirror" reference block at the top of all 4 guides (transports-and-results, package-structure, testing, documentation) pointing at the matching skill files. Makes skill ↔ contributing sync a shared obligation. 3. docs/content/docs/2.working-with-the-rest-api/*.md — added a "Skill — <name>" link entry to frontmatter `links:` of 21 pages (call/callList/fetchList/batch/batchByChunk × {v2,v3}, frame-*, choosing-the-right-method, errors, limiters). Bumped `audited:` to 2026-05-26 because adding the cross-link is the audit. `docs-lint` passes cleanly. 4. Cosmetic — replaced `offClientSideWarning?.()` with `offClientSideWarning()` across all skill files and recipes. The method is present on every concrete entry point; optional chaining created false impression of variability. 5. Recipe 9 — switched the canonical example to `ENTITY_TYPE_ID: 2` (numeric, accepted on every portal version per #34 author's testing) from the symbolic `ENTITY_TYPE: 'deal'`. Comment updated to mention the string fallback. 6. b24jssdk-core SKILL.md — new "Security checklist for event-receiver recipes" section consolidating the application_token + reply-200- first + setCallbackRefreshAuth + HTML-escape guidance that currently only lives in the per-recipe Notes blocks. Skipped from the review: - audited stamps on examples/*.md — reviewer explicitly noted this as "на усмотрение" and `docs:lint-pages` accepts it. - Recipe 7 live-portal payload-shape verification — needs B24_HOOK, documented in REPORT.md as open question.
Pre-existing miss from PR #36 (which added new entries to the docs/nuxt.config.ts route list on 2026-05-26 but did not bump the audited stamp on docs/content/docs/1.getting-started/7.ai/2.llms-txt.md, which links to that source file). docs-lint in strict mode fails when a linked source is newer than the page's audited date. Verified the nuxt.config.ts diff is route-list additions only — no semantic change to the content described by 2.llms-txt.md, so the page remains accurate; bump alone is correct.
…docs) Five parallel role-reviews (docs, programmer, QA, security, CTO) found 16 fixable items. Three larger findings (unit-test infra, isolate recipe deps, v3 whitelist CI monitor) are moved out to issues #64 / #65 / #66. The rest land here. 🔴 Runtime bugs - Recipe 6: replace contiguous-prefix `sawFailure` continue with `break`. Original logic still sent Telegram messages for deals after a mid-batch failure; cursor stayed at last-success-before-failure, so the next tick re-sent the already-delivered post-failure deals as duplicates. With `break`, the failed deal AND everything after wait for the next tick. - Recipe 5: `batch.make` named-object form needs `returnAjaxResult: true` to expose named keys safely. Previous `getData() as { Storages, Children }` was a runtime lie — actual shape is the union `T | T[] | BatchPayloadResult<T>`. Now reads through AjaxResult per key as the canonical SDK spec shows. - Recipe 8: `JSON.parse(content!)` had no null/parse guard. GPT can return null content (content-filter, rate-limit trim) or invalid JSON despite `response_format: 'json_object'`. Now throws with useful raw-snippet. 🔴 Security - Recipe 7: `B24_APPLICATION_TOKEN` is now REQUIRED (throw on startup if missing). Previously the recipe accepted any POST when the env var was absent. Compare uses `timingSafeEqual` to defeat timing-recovery attacks. - Recipe 12: same `timingSafeEqual` for the application_token check on /uninstall. Also `fs.writeFile(..., { mode: 0o600 })` so other local users can't read persisted tokens. INFO-level log no longer includes `domain` / `userId` (`logger.info('[${event}] member=${id}')` only). /portal/:memberId/profile demo route now has an explicit SECURITY-WARNING comment about missing auth. - Recipe 7 log redaction: log only the keys of `payload.data.FIELDS` (not the values) to prevent future sensitive field leakage. 🔴 Docs facts - b24jssdk-recipes/SKILL.md: «Nine» → «Twelve», description updated to mention recipes 10–12 (error handling, event registration, OAuth install). - b24jssdk-recipes/SKILL.md: caveat about recipe-7-event-registration now correctly points to recipe 11 (it exists) instead of «not covered by these scripts». - MAINTENANCE.md: recipe-section count and list updated 9→12. 🟡 Polish - SUGGESTED-EXAMPLES.md: drop confusing «#1 / #6 / #8» gap numbers in the Done section (recipes have their own numbers 10/11/12). - docs/.../99.examples/0.index.md: drop `offClientSideWarning?.()` optional chaining in the shared boot snippet — consistent with skills and recipes (the method is present on all entry points). - Recipe 4: split `created` counter into `createdInB24` / `createdInErp` for actionable metrics. - Recipe 3: `setInterval` now has an overlap guard so slow ticks don't race on `dealStages`. - Recipe 6: add cold-start comment explaining that `lastSeenDealId = 0` floods all NEW-stage deals on first tick. - tsconfig.recipes: explain `ignoreDeprecations: "6.0"` inline. 🟢 Traceability - Recipes 7 and 9: add `UNVERIFIED_ON_LIVE_PORTAL` markers to the header docblocks with pointers to REPORT.md. CI: `lint`, `typecheck` (incl. `skills:typecheck`), `docs:lint-pages` — all green. Co-authored-by: 5 role-review agents (docs, programmer, QA, security, CTO)
# Conflicts: # docs/content/docs/1.getting-started/7.ai/2.llms-txt.md # package.json
…ssing The CI `docs-lint` job is a no-deps fast job — it intentionally does not run `pnpm install` / `pnpm run dev:prepare` (see the comment on the job in .github/workflows/ci.yml). The integration tests added in #87 spawn the real docs-typecheck.mjs, which exits 1 when `packages/jssdk/dist/esm/index.d.ts` is absent — causing the third step of `docs-lint` to fail in CI. Locally, where dev:prepare has been run, the tests execute normally. In CI without dist, the three integration tests are now skipped with the explanatory message, preserving the fast-job contract. Verified: local run = 27 pass / 0 skipped (dist present); simulated CI (dist removed) = 24 pass / 3 skipped / 0 fail.
Duplicates landed silently across two merges (PR #36 adding cookbook deps + my PR #38 adding skill-related ones). Eight icon entries were listed twice, and the order was append-only — hard to diff-review. Alphabetical sort + dedupe. No functional change (Vite optimizeDeps include is a set semantically); only diff hygiene.
On large portals (100k+ deals) the fetchList loop runs silently for minutes between 'Loading deals…' and the final report — easy to mistake for a hang and Ctrl-C out. Add a per-500-items progress log with elapsed seconds; teaching comment explains how to drop it on small portals. Mirrored in the embedded code on docs/.../1.crm-analytics.md.
Two ergonomic fixes after running recipe 1 against a live portal: 1. LoggerBrowser is @deprecated — replace with Logger.create() + ConsoleV2Handler at INFO. Removes the noisy 'INFO [channel]: info { params: { 0: "..." } }' wrapping and the two startup @deprecate warnings. 2. main().catch was logging the error through the structured logger, so a thrown error from inside loadAllDeals didn't show its stack visibly — script just exited 1 after 'Loading deals…'. Switched to raw console.error with explicit Error/non-Error branching so any future failure shows the actual stack on stderr. Doc page mirrored. Pattern lifted from playgrounds/cli/src/commands/make/companies.ts which is the in-repo reference for the new Logger API. Will roll the same migration into recipes 2-12 once verified on a live portal — keeping the diff small for review.
3013 deals loaded in ~30s on a real bitrix24.ru portal; funnel printed correctly (NEW 895, WON 1205, LOSE 912, win rate 56.9%, revenue 169M). Recorded under the new 'Live-portal verification log' table in REPORT.md so future audits can see which recipes have passed end-to-end checks.
…Y_TYPE_ID
- Replace deprecated LoggerBrowser.build() with Logger.create() +
ConsoleV2Handler(LogLevel.INFO, { useStyles: false }) in all 11 remaining
recipes (02–12), matching the pattern from recipe 01 (commit 4a5bb55).
- Replace logger.error(e) in main().catch with raw console.error so
structured-logger formatting cannot hide stack traces.
- Fix Logger API mismatches surfaced by skills:typecheck after migration:
warn() → warning(); fold string[] second-args into the message;
add missing second {} arg to error() calls that had only one argument.
- Recipe 09: swap ENTITY_TYPE_ID: 2 literal to EnumCrmEntityTypeId.deal
enum constant; extract `fields` into a named variable; remove
UNVERIFIED_ON_LIVE_PORTAL header marker (form confirmed correct).
- REPORT.md: add blocked entries for recipe 5 (disk scope missing) and
recipe 11 (event.* requires OAuth, not B24Hook); close open question #5.
skills:typecheck passes with 0 errors after these changes.
https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
Add a prominent "Webhook scope required" note in both the recipe JSDoc header and the docs page so users know to tick "Диск (disk)" in the portal's inbound webhook settings before running 05-disk-files.ts. Confirmed via live-portal run: missing scope returns insufficient_scope (401). https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
disk.storage.getlist, disk.folder.addsubfolder, actions.v2.batch.make all working. 5 storages, subfolder created, batch round-trip confirmed. https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
crm.item.get returns error code NOT_FOUND (not ERROR_NOT_FOUND which is the crm.deal.get legacy code). The switch was falling through to default, re-throwing, and crashing. Add NOT_FOUND as the primary case; keep ERROR_NOT_FOUND as a fallthrough for callers still on crm.deal.get. Caught by live-portal run on 2026-05-28. https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
All error paths confirmed: NOT_FOUND caught, SdkError for v3 whitelist caught, full run without unhandled throws. Bug found and fixed in same session (NOT_FOUND vs ERROR_NOT_FOUND for crm.item.get). https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
Resolve conflicts in package.json (keep skills:typecheck + add package-jssdk:test:run-unit from main; merge devDependencies), pnpm-lock.yaml (rebased from main + reinstalled), and scripts/__tests__/docs-typecheck.test.mjs (take main's cleaner INTEGRATION_SKIP approach). https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
All 22 docs pages touched in this PR refreshed to the merge date. https://claude.ai/code/session_016QWk3vjhi53bbNRw1PFLBa
Summary
Adds a project-scoped skill set under
.claude/skills/and a parallel catalogue of 12 SDK-native recipes underdocs/content/docs/99.examples/. Built entirely on the canonical$b24.actions.v{2,3}.*.make()surface — the legacycallMethod/callBatch/callListMethod/fetchListMethodis@deprecatedfor2.0.0and is not generated by any skill or recipe.The skills exist to make AI agents working in this repo produce idiomatic, version-correct code out of the box.
What's in the PR
7 skills (
.claude/skills/<name>/SKILL.md)b24jssdk-coreB24Hook/B24Frame/B24OAuth), error taxonomy,hardErrorCodes/softErrorCodes/retryOnNetworkErrortuningb24jssdk-restactions.v{2,3}.{call,batch,callList,fetchList,batchByChunk}.make; AjaxResult new shape; v3 all-or-nothing batch; null-result passthrough; v3 method whitelistb24jssdk-filtering'>=createdTime','!stageId','%title') + v3 array-of-triples dialect ([['fld','>=',v]]); operator lists;orderstripping incallList/fetchList; dates viaText.toB24Formatb24jssdk-frame-uiselectUser/Users/CRM/Access), parent, placement (with the newsetValuehelper), options, authb24jssdk-helpersuseB24Helper,B24HelperManager, Pull client (usePullClient()is arg-less), currency, app/user optionsb24jssdk-recipesb24jssdk-vibecode12 recipes (
.claude/skills/b24jssdk-recipes/examples/NN-*.ts)01-crm-analytics.tsactions.v2.fetchList.make, print funnel report02-mass-messaging.tsim.notifyper-contact03-task-automation.tsactions.v3.call.make('tasks.task.add')04-erp-sync.tsnode-cronschedule05-disk-files.tsactions.v2.batch.makeround-trip06-telegram-bot.tsgrammy07-webhook-handler.tsapplication_tokenagainstB24_APPLICATION_TOKENenv to block spoofed events08-ai-assistant.tsactions.v3.call.make09-web-search-llm.ts10-error-handling.tshardErrorCodes/softErrorCodes/retryOnNetworkError11-event-registration.ts12-oauth-install.tsONAPPINSTALL/ONAPPUPDATE/ONAPPUNINSTALL, buildingB24OAuthon demand with a refresh callback writing tokens back to storage; verifiesapplication_tokenon uninstall to prevent spoofed credential deletionValidation pipeline
Recipes are now part of
pnpm run typecheckvia a newskills:typecheckscript:.claude/skills/b24jssdk-recipes/tsconfig.json— strict TypeScript config that points at the built SDK types (packages/jssdk/dist/esm/index.d.ts).grammy,openai,express,node-cron+@types/expressand@types/node-cronadded as workspace devDeps so recipes get strict typing for opt-in deps too, not just SDK calls..claude/**is intentionally excluded from eslint (these are agent templates).This pipeline caught real bugs during the PR's own self-review (see commits
e17be22,42c1d85).Maintenance + audit docs
.claude/skills/README.md— index of skills and conventions.claude/skills/MAINTENANCE.md— weeklydocs/llms-full.txtreview playbook (sanity checks, triage rules, translation table VibeCode → SDK, commit protocol, skills typecheck contract).claude/skills/REPORT.md— migration log + anchor-facts table (every load-bearing fact in the skills cited to a specific file/line in the SDK source) + 7 open questions.claude/skills/SUGGESTED-EXAMPLES.md— remaining gaps with effort estimates; Отсутствие примеров работы с SDK на стороне сервера #1/Initialisation of main SDK object by complete webhook url #6/Add static method createFromUrl for B24Hook #8 marked as done (became recipes 12/10/11)Documentation site
Mirrors the 12 recipes under
docs/content/docs/99.examples/with title, description, env, run command, and a link back to the source.tsfile. Recipe 1 embeds the full code; the rest reference the canonical.ts. Recipes 4 and 6 docs include scaling pointers (batchByChunk.make/batch.make).Repo plumbing
eslint.config.mjs— exclude.claude/**(skill files are agent-facing templates, not workspace source)package.json— addsskills:typecheckscript, wired into the roottypecheck; adds opt-in dep packagesSecurity hardening
Both event-receiver recipes verify
application_tokenagainst a known value before acting:B24_APPLICATION_TOKENenv is set, the handler compares it againstpayload.auth?.application_tokenand silently drops mismatched requests. Without this guard anyone who knows the URL could replay arbitrary events./uninstallcould erase the credentials of any portal whosemember_idthey guess.Both also reply
200first and verify after, so a bad payload doesn't make Bitrix24 retry the call for 24 h.Why this shape
.claude/skills/. The matching docs site pages exist so humans see them too, but the source of truth is the.tsrecipes and theSKILL.mdprose.actions.v{2,3}.*only: theDeprecation noticeinpackages/jssdk/README-AI.mdwas the trigger for migrating this branch offcallMethod/callBatch/callListMethod/fetchListMethod. All skills and recipes ship the new surface.order-stripping rule incallList) is cited againstpackages/jssdk/src/...line numbers inREPORT.md. Future audits can verify against the same anchors.version-manager.ts's whitelist yet); tasks switched to v3 where the whitelist allows. Documented per-recipe..tsfiles compile under strict TypeScript against the real SDK + real external-package types. Future API drift (e.g. an SDK error field rename) will be caught at typecheck time, not at copy-paste time.Test plan
pnpm run lintpasses (root)pnpm run typecheckpasses (root — every workspace, includingskills:typecheck)grammy/openai/express/node-cronB24_HOOKin.env.test:pnpm vitest run -t "js-docs.actions" --project jsSdk:integration— canonical actions specs still passdata[FIELDS][ID]payload shape; recipe 9 wants verification ofENTITY_TYPE: 'deal'vsENTITY_TYPE_ID: 2forcrm.timeline.comment.add)Known unknowns (also tracked in REPORT.md)
express.urlencoded({ extended: true })flatteningdata[FIELDS][ID]; not yet confirmed against a live outbound webhook.ENTITY_TYPE: 'deal'(string); some portal versions wantENTITY_TYPE_ID: 2instead. Recipe notes the fallback.crm.item.*arrives on v3, several recipes should move; that's also a filter-dialect rewrite (prefix → array-of-triples). Tracked in REPORT.md §"Open questions / unresolved".Future work (in
SUGGESTED-EXAMPLES.md)Top remaining picks: Vue/Nuxt frame boot template,
batchByChunk.makebulk CSV import, production-grade multi-tenant backend (builds on recipe 12),actions.v3.aggregate.makewhen the SDK exposes it.Commit log