CLAUDE.md ยท diff

git:20260914.f4d7abc to git:20260914.5582908

3 added, 1 removed. Audit A to A.

# AdCP Client
## For AI Agents Building on AdCP
**Start here**: Read `docs/llms.txt` for a complete protocol overview
(all tools, types, error codes, examples โ€” single fetch).
**Do NOT read these files** โ€” they are machine-generated and will waste
your context: `src/lib/types/*.generated.ts`, `src/lib/agents/index.generated.ts`, `schemas/`
**Use instead**: `docs/TYPE-SUMMARY.md` for curated type signatures.
**Key entry points**: `src/lib/index.ts`, `examples/signals-agent.ts`
**Building a server-side agent?** Read `docs/guides/BUILD-AN-AGENT.md`. Storyboards live at `https://adcontextprotocol.org/compliance/{version}/` (pulled into `compliance/cache/{version}/` by `npm run sync-schemas`).
**Validating a server-side agent?** Read `docs/guides/VALIDATE-YOUR-AGENT.md` โ€” the five-command checklist plus deep references for `adcp storyboard run`, `adcp fuzz` (T1/T2/T3), `adcp grade request-signing`, multi-instance testing, webhook conformance, schema-driven validation hooks, custom `--invariants`, the `npm run compliance:fork-matrix` reference-adapter regression harness (extend with your adapter path + `expectedRoutes` to inherit the three-gate contract), and how to read the runner's `context_value_rejected` diagnostics (the `๐Ÿ’ก Hint:` lines printed on failing storyboard steps).
**Putting credentials in `ctx_metadata`?** Don't. Read `docs/guides/CTX-METADATA-SAFETY.md` โ€” the wire-strip protects buyer responses but does NOT protect server-side log lines, error envelopes, heap dumps, or adopter-generated strings. Re-derive bearers per request from `ctx.authInfo` + your token cache; embed only non-secret upstream IDs in `ctx_metadata`.
**Reviewing a safety-critical PR (auth, signing, replay, idempotency, governance, tenancy)?** Read `docs/development/REVIEW-STACKS.md`. Run Claude expert agents (DX, protocol, code-review, security) in parallel **plus** `npm run review:codex -- --all --base main` for a second-model opinion. Convergence between the two stacks = ship confidence; divergence = the actual review. The pattern caught a real replay-protection bypass on PR #1858 that the Claude reviewers couldn't be reached for due to API capacity.
**Calling an AdCP agent as a buyer?** Read and follow `skills/call-adcp-agent/SKILL.md` โ€” covers the wire contract, minimal payload shapes, async flow, and error recovery so you don't stall on `oneOf`/discriminated-union fields that schema-free tool discovery won't explain. Significantly reduces the hop count an LLM needs to make its first successful call (3-4 attempts โ†’ 1 attempt on common tools in empirical comparison).
**Building a seller agent?** Read and follow `skills/build-seller-agent/SKILL.md` โ€” covers guaranteed vs non-guaranteed, pricing, approval workflows, creative management.
**Building a generative seller / AI ad network?** Read and follow `skills/build-generative-seller-agent/SKILL.md` โ€” covers brief-based creative generation, standard + generative format catalogs, brand resolution.
**Building a signals agent?** Read and follow `skills/build-signals-agent/SKILL.md` โ€” covers marketplace vs owned data, segments, pricing, activation destinations.
**Building a retail media network?** Read and follow `skills/build-retail-media-agent/SKILL.md` โ€” covers catalog sync, conversion tracking, performance feedback, dynamic ads.
**Building a creative agent?** Read and follow `skills/build-creative-agent/SKILL.md` โ€” covers ad servers, creative management platforms, format discovery, preview, and build.
**Building a governance agent?** Read and follow `skills/build-governance-agent/SKILL.md` โ€” covers campaign governance (spending authority, approval/denial), property lists, content standards.
**Building a sponsored intelligence agent?** Read and follow `skills/build-si-agent/SKILL.md` โ€” covers offering discovery, session lifecycle, conversational sponsored content.
**Building a brand rights agent?** Read and follow `skills/build-brand-rights-agent/SKILL.md` โ€” covers brand identity, rights licensing, creative approval.
### Specialism โ†’ Skill Index
Pick the specialisms you want to claim in `get_adcp_capabilities`. Each maps to a compliance storyboard at `compliance/cache/latest/specialisms/<id>/`. The skill below has a dedicated section for each specialism's deltas.
| Specialism | Protocol | Status | Skill |
| ----------------------------- | ---------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `sales-guaranteed` | media-buy | stable | `skills/build-seller-agent/` |
| `sales-non-guaranteed` | media-buy | stable | `skills/build-seller-agent/` |
| `sales-broadcast-tv` | media-buy | stable | `skills/build-seller-agent/` |
| `sales-dooh` | media-buy | stable | `skills/build-seller-agent/` |
| `sales-streaming-tv` | media-buy | preview | `skills/build-seller-agent/` |
| `sales-social` | media-buy | stable | `skills/build-seller-agent/` |
| `sales-exchange` | media-buy | preview | `skills/build-seller-agent/` |
| `sales-catalog-driven` | media-buy | stable | `skills/build-retail-media-agent/` |
| `sales-retail-media` | media-buy | preview | `skills/build-retail-media-agent/` |
| `sales-proposal-mode` | media-buy | stable | `skills/build-seller-agent/` |
| `audience-sync` | media-buy | stable | `skills/build-seller-agent/` (track: `audiences`; uses `sync_audiences`, `list_accounts`) |
| `signed-requests` | media-buy | preview | **Cross-cutting** โ€” applies to any agent that receives mutating requests, regardless of primary specialism. The yaml classifies it under `media-buy` because that's where financial stakes are highest, but the verifier behavior is identical across all protocols. See `skills/build-seller-agent/` (ยง signed-requests). |
| `creative-ad-server` | creative | stable | `skills/build-creative-agent/` |
| `creative-template` | creative | stable | `skills/build-creative-agent/` |
| `creative-generative` | creative | stable | `skills/build-creative-agent/` or `skills/build-generative-seller-agent/` (if you also sell inventory) |
| `signal-marketplace` | signals | stable | `skills/build-signals-agent/` |
| `signal-owned` | signals | stable | `skills/build-signals-agent/` |
| `governance-aware-seller` | media-buy | stable | `skills/build-seller-agent/` (track: governance-aware; uses `sync_governance` + `sync_plans` to consume governance signals during the buy flow) |
| `governance-spend-authority` | governance | stable | `skills/build-governance-agent/` |
| `governance-delivery-monitor` | governance | stable | `skills/build-governance-agent/` |
| `property-lists` | governance | stable | `skills/build-governance-agent/` |
| `collection-lists` | governance | stable | `skills/build-governance-agent/` (program-level brand safety via IMDb/Gracenote/EIDR IDs) |
| `content-standards` | governance | stable | `skills/build-governance-agent/` |
| `measurement-verification` | governance | preview | `skills/build-governance-agent/` |
| `brand-rights` | brand | stable | `skills/build-brand-rights-agent/` |
| `buyer-activation` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
| `buyer-discovery` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
| `buyer-monitoring` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
| `buyer-negotiation` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
| `buyer-recovery` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
| `orchestrator-multi-agent` | media-buy | preview | Consumer-under-test track; use `docs/guides/CONFORMANCE.md` and the published storyboard. |
**Multi-specialism bundles:** See [`examples/README.md` ยง Common multi-specialism bundles](./examples/README.md#common-multi-specialism-bundles) for canonical claim combinations by adopter shape (retail-media, broadcaster, identity provider, etc.).
**Naming conventions:** specialism IDs are kebab-case (`sales-broadcast-tv`). Storyboard category IDs in `index.yaml` are snake_case (`media_buy_broadcast_seller`). Yaml titles are prose ("Broadcast linear TV seller agent"). Same concept, three names โ€” don't confuse them.
**`protocol:` vs `domain:`.** The specialism yaml uses `protocol:` (renamed from `domain:` in AdCP 3.0 GA). If you see older docs or issues reference `domain:`, they mean the same thing.
**Preview specialisms** have `phases: []` in their `index.yaml` โ€” the storyboard is a placeholder and the agent passes the protocol baseline only. Claim a preview specialism to advertise intent; expect `phases` to populate in a subsequent AdCP release.
**Adding wire-version compat (e.g. SDK pin moves to v4, or a new legacy seller version)?** See [`docs/development/WIRE-VERSION-COMPAT.md`](./docs/development/WIRE-VERSION-COMPAT.md) โ€” playbook for the schema cache, codegen, adapter registry, validation pinning, conformance fixtures, and smoke harness. Reference whenever you touch `src/lib/adapters/legacy/`, `src/lib/types/v*-*/`, or `schemas/cache/<version>/`.
+ **Migrating from 13 to 14 (prerelease)?** See [`docs/migration-13-to-14.md`](./docs/migration-13-to-14.md). One account-model breaking change to audit: **`accounts.resolution: 'derived'` is now an upstream-managed account-id namespace** (adcp-client#1647, upstream adcp#5062). It accepts `{ account_id }` and refuses the `{ brand, operator }` arm โ€” the exact inverse of the 6.7-era behavior described further down this list. `accounts.list` (or `opts.accounts.listAccounts`) is required for the mode, `accounts.resolve` must verify the buyer-supplied id against what the caller's credential can reach (the framework fails a mismatch closed), `sync_accounts` natural-key provisioning entries fail per-row with `UNSUPPORTED_PROVISIONING` while `account: { account_id }` settings-update entries pass through after a reachability check, and a declared `'derived'` projects `account.require_operator_auth: true`. `createDerivedAccountStore` does the verification, the paging, and the `list_accounts` wiring for you โ€” `toAccount` for one account per credential, `listAccounts` (+ optional `lookupAccount`) for a roster.
+
**Migrating from 7.9 to 7.10?** See [`docs/migration-7.9-to-7.10.md`](./docs/migration-7.9-to-7.10.md) โ€” **pure additive walkthrough; no breaking recipes.** Headlines: `AgentClient.getProducts()` auto-augments responses with V2 `format_options[]` (read-side mental model), `packageRefsForCapabilities(product, [capId])` returns `{capability_ids, format_ids?}` to spread into a `PackageRequest` (write-side, dual emission per adcp#4844 in 3.1.0-beta.2), `fetchFormatSchema` + `resolveSchemaRefs` for the `format_schema` URI+digest contract (HTTPS+SSRF+digest+bounded `$ref`), and `extractPublisherFormats` / `scopePublisherFormats` / `resolveCapabilityId` on top of `validateAdAgents()` for the `adagents.json#/formats` AAO 3.1 catalog. V1-only adopters do nothing โ€” `format_ids[]` preserved on every product, `legacy*` helpers (semantic narrowing, not deprecation) cover the single-target v1 write path. Opt-in 3.1.0-beta.2 schemas via `adcpVersion: '3.1-beta'` / `'3.1.0-beta.2'`; primary pin stays at the GA `ADCP_VERSION`. `DEFAULT_MIRROR_HOSTS` collapsed to `creative.adcontextprotocol.org` per adcp#4866 (legacy host was never provisioned).
**Migrating from 6.7 to 6.9?** See [`docs/migration-6.7-to-6.9.md`](./docs/migration-6.7-to-6.9.md) โ€” **skips past 6.8.0** (deprecated same-day; 6.7 โ†’ 6.9 is the supported path). Two breaking recipes to audit before bumping: **#1** the framework now auto-wires the sandbox-authority gate inside `createAdcpServerFromPlatform` for `comply_test_controller` (Phase 2 of #1435 โ€” resolved-account `mode` is the trust boundary, not buyer-supplied `account.sandbox`), and **#2** `npm run compliance:skill-matrix` is removed in favour of `compliance:fork-matrix` (~10 s deterministic vs ~50 min LLM-variance). Thirteen additive recipes covering `Account.mode` helpers (with `Account.sandbox` server-side `@deprecated`), `createAdcpServer.instructions` async, `BuyerAgentRegistry.extra` forwarding, `composeMethod` variadic, `ComplyControllerConfig.force` extension + `queryUpstreamTraffic` adapter, `createDerivedAccountStore` Shape D, `RosterAccountStoreOptions.resolveWithoutRef`, `ConformanceClient` Socket Mode, AdCP 3.0.6 schema bump + `tasks/get` slash registration + `AgentClient.executor`, storyboard runner symmetric account resolution, codegen `asset_type` discriminator on `Individual*Asset` slots, skill prose collapse + `skills/cross-cutting.md`, five new worked references / mock-servers. Self-grade checklist with grep-based audits.
- **Migrating from 6.6 to 6.7?** See [`docs/migration-6.6-to-6.7.md`](./docs/migration-6.6-to-6.7.md) โ€” seventeen adopter recipes plus two breaking changes to audit before bumping: **#10** `accounts.resolution: 'implicit'` now actually refuses inline `{account_id}` references (was aspirational pre-6.7), **#10b** same refusal extended to `'derived'` mode (recipe backfilled in 6.9 via #1492 โ€” runtime shipped in 6.7 via #1475), and **#11** `SalesPlatform` split into `SalesCorePlatform & SalesIngestionPlatform` (all methods individually optional, self-announcing under `tsc --noEmit`). The other fifteen recipes are additive: `definePlatform` family, `refAccountId`, `composeMethod`, `accounts.resolve` security presets, `accounts.upsert/list/syncGovernance(ctx)`, typed errors, `issues[].hint`, `BuyerAgentRegistry`, `createTenantRegistry`, `createOAuthPassthroughResolver` (Shape B), `createRosterAccountStore` (Shape C), `createDerivedAccountStore` (Shape D โ€” single-tenant `'derived'`), `createTenantStore` (multi-tenant w/ built-in security gate), `MEDIA_BUY_TRANSITIONS` + `assertMediaBuyTransition` lifecycle helpers, `createMediaBuyStore` for `targeting_overlay` echo. Worked diff + self-grade checklist included.
+ **Migrating from 6.6 to 6.7?** See [`docs/migration-6.6-to-6.7.md`](./docs/migration-6.6-to-6.7.md) โ€” seventeen adopter recipes plus two breaking changes to audit before bumping: **#10** `accounts.resolution: 'implicit'` now actually refuses inline `{account_id}` references (was aspirational pre-6.7), **#10b** same refusal extended to `'derived'` mode (recipe backfilled in 6.9 via #1492 โ€” runtime shipped in 6.7 via #1475; **reversed in SDK 14 by #1647**, where `'derived'` accepts `account_id` and refuses the natural key instead), and **#11** `SalesPlatform` split into `SalesCorePlatform & SalesIngestionPlatform` (all methods individually optional, self-announcing under `tsc --noEmit`). The other fifteen recipes are additive: `definePlatform` family, `refAccountId`, `composeMethod`, `accounts.resolve` security presets, `accounts.upsert/list/syncGovernance(ctx)`, typed errors, `issues[].hint`, `BuyerAgentRegistry`, `createTenantRegistry`, `createOAuthPassthroughResolver` (Shape B), `createRosterAccountStore` (Shape C), `createDerivedAccountStore` (Shape D โ€” `'derived'`; reworked in SDK 14 from single-tenant to upstream-managed account-id namespace), `createTenantStore` (multi-tenant w/ built-in security gate), `MEDIA_BUY_TRANSITIONS` + `assertMediaBuyTransition` lifecycle helpers, `createMediaBuyStore` for `targeting_overlay` echo. Worked diff + self-grade checklist included.
**Migrating from 4.x?** See [`docs/migration-4.x-to-5.x.md`](./docs/migration-4.x-to-5.x.md) for the full 4.x โ†’ 5.x path. Covers framework shape (5.0's `TaskResult` discriminated union + `createAdcpServer`), exports cleanup (5.1's `platform_type` removal + storyboard-tarball move), AdCP 3.0 GA alignment (5.2's `authority_level` โ†’ `human_review_required`, `inventory-lists` โ†’ `property-lists`, `idempotency_key` requirement, `serve({ authenticate })` surface), downstream ergonomics (5.3โ€“5.4 `AdcpServer` return type + `dispatchTestRequest`), signed-requests composition (5.5โ€“5.6 `requireSignatureWhenPresent` + `capabilities.overrides`), conformance runner wiring (5.7 `createExpressAdapter`), conformance defaults (5.8 `createComplyController`), A2A session continuity + typed errors (5.9), OAuth client credentials + strict validation defaults (5.10), and the pin to AdCP 3.0.0 GA (5.13: `ADCP_VERSION` switched from `latest` to the published `3.0.0` release; `validate_property_delivery` response is now wired to its generated schema). Includes a wire-interop matrix for mixed-version (beta.3 / rc.2 / GA) traffic.
**Protocol-Wide Requirements.** Two requirements apply to every mutating AdCP operation regardless of specialism:
- **`idempotency_key`** โ€” required on every mutating request. The SDK's `MUTATING_TASKS` constant is authoritative; see the full skill-domain breakdown in [`skills/cross-cutting.md`](./skills/cross-cutting.md). Handlers must return the same response when the same key is replayed. Landed in AdCP 3.0 GA.
- **RFC 9421 HTTP Signatures** โ€” optional but recommended. If you claim `signed-requests`, you verify incoming signatures; regardless, you must not break when signature headers are present.
**Critical rules**:
- ALWAYS create a changeset (`npm run changeset`) for ANY library/CLI code change before pushing a PR. This is mandatory โ€” do not wait to be asked.
- ALWAYS use official `@a2a-js/sdk` and `@modelcontextprotocol/sdk` clients โ€” never custom HTTP or SSE parsing
- NEVER inject mock/fallback data โ€” return exactly what agents provide
- NEVER hardcode API keys, tokens, or credentials โ€” use environment variables
- NEVER manually edit `package.json` version โ€” use `npm run changeset`
- When renaming or moving a doc, also update any `blob/main/` or `tree/main/` URLs that point at it โ€” `scripts/check-doc-links.ts` (run in CI as `ci:doc-links`) scans `src/`, `bin/`, `docs/`, `packages/`, `CLAUDE.md`, and `README.md` for stale references and fails the build. Add the new path to `EXEMPT_PATHS` only as a last resort, for content not in this repo.
**When a compliance storyboard fails, triage before patching.** Storyboards are assertions, not ground truth. The spec normatively pins the triage order โ€” `spec โ†’ mock โ†’ SDK` โ€” at [Mock-server authority and failure triage](https://adcontextprotocol.org/docs/building/verification/conformance#mock-server-authority-and-failure-triage). Before changing the SDK to satisfy a failing assertion, ask: _does the AdCP spec define this contract?_ Check `schemas/cache/{version}/` and the spec repo (`adcontextprotocol/adcp`). If the spec defines the behavior, fix the SDK โ€” the storyboard is doing its job surfacing drift. If the spec is silent or contradicts the assertion, the storyboard is the bug: file an issue on `adcontextprotocol/adcp`. Don't bake storyboard opinion into SDK behavior โ€” that compounds drift across the ecosystem and turns the SDK into a mirror of whichever storyboard was authored most recently.
**Full agent instructions**: [AGENTS.md](./AGENTS.md) has protocol details, architecture patterns, and testing strategies.
---
## Development & Release Guide
**@adcp/sdk** is the official TypeScript client library for the Ad Context Protocol (AdCP), with CLI tooling for testing agents.
## NPM Publishing & Release Management
### ๐Ÿšจ AUTOMATED RELEASE PROCESS ๐Ÿšจ
**IMPORTANT**: This project uses **Changesets** for version management and releases.
### ๐Ÿ“ฆ When to Create a Changeset
**ALWAYS create a changeset for:**
- โœ… Library code changes (`src/lib/`)
- โœ… CLI changes (`bin/`)
- โœ… Published files (anything in `package.json` `files` field)
- โœ… Schema changes (`src/schemas/`)
- โœ… TypeScript types changes
**NO changeset needed for:**
- โŒ Documentation only (`*.md` files, except CHANGELOG.md)
- โŒ Development tooling (`conductor.json`, `.github/workflows/`)
- โŒ Test files only (no behavior changes)
- โŒ Configuration files (`.eslintrc`, `tsconfig.json`, etc.)
**Why CLI changes need changesets:**
The CLI (`bin/adcp.js`) is bundled with the npm package. Users who run `npx @adcp/sdk@latest` or install the package globally need version bumps to get CLI fixes. Without a changeset, the fix won't be published to npm.
### ๐Ÿšจ REQUIRED: Make Changeset Check a Required Status Check ๐Ÿšจ
The CI workflow includes a `Changeset Check` job that validates changesets are included for library changes. However, this check must be marked as **required** in GitHub repository settings to prevent PRs from merging without changesets.
**To configure (repository admin only):**
1. Go to: `Settings` โ†’ `Branches` โ†’ `main` branch protection rules
2. Under "Require status checks to pass before merging", enable:
- โœ… `Changeset Check`
3. Save changes
**Verification**: After configuration, PRs that modify library code without a changeset will be blocked from merging.
**What happened when this wasn't configured:**
- PR #65 modified `src/lib/protocols/a2a.ts` and `src/lib/protocols/mcp.ts`
- The `Changeset Check` job correctly failed
- However, the PR was allowed to merge because the check wasn't required
- No Release PR was triggered because no changeset existed
- Had to manually create and merge a changeset in a follow-up PR
### ๐Ÿšจ CRITICAL: Never Manually Edit package.json Version! ๐Ÿšจ
**DO NOT** manually change the `version` field in `package.json` - changesets will handle this automatically.
**What happened when we broke this rule:**
- We manually bumped `package.json` from 2.0.2 to 2.1.0 (to match AdCP schema version)
- Changesets calculated: 2.1.0 + minor changeset = **2.2.0** (WRONG!)
- We skipped version 2.1.0 entirely
- Had to revert package.json to 2.0.2 and let changesets correctly calculate 2.0.2 โ†’ 2.1.0
**The correct separation:**
- `package.json` version = **Library version** (managed by changesets)
- `src/lib/version.ts` ADCP_VERSION = **AdCP schema version** (can differ from library version)
- These are independent and serve different purposes!
### How It Works
1. **Create a changeset for your changes**:
```bash
npm run changeset
```
This will prompt you to:
- Select the version bump type (patch/minor/major)
- Write a summary of the changes
- Create a markdown file in `.changeset/`
2. **Commit the changeset with your code**:
```bash
git add .changeset/
git commit -m "feat: add new feature"
git push
```
3. **Create a PR and merge to main**:
- Create PR from your feature branch
- **Do NOT manually edit package.json version**
- Merge PR to main when approved
4. **GitHub Actions creates a Release PR automatically**:
- **Triggered by**: Push to main with changeset files
- **PR title**: "chore: release package"
- **What it does**:
- Automatically updates CHANGELOG.md
- Automatically bumps version in package.json
- Combines all changesets since last release
- Deletes changeset files
- **No new branch needed**: The Release PR is auto-created by GitHub Actions
5. **Review and merge the Release PR**:
- Check the generated CHANGELOG.md
- Verify version bump is correct (e.g., 2.0.2 โ†’ 2.1.0)
- **Important**: Verify it's not skipping versions!
- Merge when ready to release
6. **Automatic publishing**:
- Merging Release PR triggers publish workflow
- GitHub Actions publishes to npm automatically
- Package appears on npm registry within ~1 minute
- Verify: `npm view @adcp/sdk version`
### Version Bump Guidelines
| Type | When to Use | Example |
| ------- | ---------------------------------- | ------------- |
| `patch` | Bug fixes, minor improvements | 2.0.1 โ†’ 2.0.2 |
| `minor` | New features, non-breaking changes | 2.0.1 โ†’ 2.1.0 |
| `major` | Breaking changes | 2.0.1 โ†’ 3.0.0 |
### Creating Changesets
**For a single change:**
```bash
npm run changeset
# Select: patch/minor/major
# Write: "fix: resolve authentication issue"
```
**For multiple changes in one PR:**
```bash
npm run changeset # First change
npm run changeset # Second change
# Commit all changesets together
```
### Changeset Examples
**Bug Fix (patch):**
```bash
npm run changeset
# Select: patch
# Summary: "Fixed MCP structuredContent parsing for stringified JSON"
```
**New Feature (minor):**
```bash
npm run changeset
# Select: minor
# Summary: "Added webhook signature verification support"
```
**Breaking Change (major):**
```bash
npm run changeset
# Select: major
# Summary: "Removed deprecated Agent class, use AdCPClient instead"
```
### Verification Commands
```bash
# Check current version
npm version
# View changesets that haven't been released
ls .changeset/*.md
# Check npm package versions
npm view @adcp/sdk versions
# View release history
gh release list
# Monitor release workflow
gh run list --workflow=release.yml
```
### Emergency Manual Release (Use ONLY if automated process fails)
**Prerequisite**: You must be logged in to npm locally (`npm login`).
```bash
# 1. Version packages
npm run version
# 2. Publish to npm
npm run release
# 3. Create GitHub release
gh release create v$(node -p "require('./package.json').version") --generate-notes
```
**Remember**: Always create a changeset for library changes. The automation handles the rest.
**Note**: CI uses OIDC publishing (no NPM_TOKEN needed). The package is linked to this GitHub repo on npm for tokenless publishing.
### Troubleshooting
#### Release PR is calculating wrong version (skipping versions)
**Symptom**: Release PR says it will publish 2.2.0 but we're at 2.0.2 (skipping 2.1.0)
**Cause**: Someone manually edited `package.json` version field
**Fix**:
1. Close the incorrect Release PR
2. Create a fix PR to revert `package.json` to the current npm version:
```bash
# Check what's on npm
npm view @adcp/sdk version # e.g., 2.0.2
# Edit package.json to match npm version
# Edit src/lib/version.ts LIBRARY_VERSION to match
# Keep ADCP_VERSION at its correct value
git add package.json src/lib/version.ts
git commit -m "fix: revert library version to match npm"
git push
```
3. Merge the fix PR to main
4. GitHub Actions will create a new Release PR with correct version
5. Merge the new Release PR
#### No Release PR created after merging to main
**Possible causes**:
- No changeset files in `.changeset/` directory
- Changeset files were not committed
- Release workflow disabled or failing
**Fix**:
```bash
# Check for changesets
ls .changeset/*.md
# If no changesets, create one and merge a new PR
npm run changeset
```
#### Release PR merged but package not published to npm
**Check**:
```bash
# View workflow runs
gh run list --workflow=release.yml --limit 3
# Check if publish failed
gh run view <run-id>
```
**Common issues**:
- Package.json version already exists on npm
- Build failed during publish
- OIDC publishing not configured on npm (check package access settings)
### Quick Reference
**Normal release workflow (no manual version edits needed):**
1. Make changes on feature branch
2. Run `npm run changeset` and commit
3. Create PR and merge to main
4. Wait for auto-generated Release PR
5. Review and merge Release PR
6. Package publishes to npm automatically
**Do NOT do:**
- โŒ Manually edit `package.json` version
- โŒ Manually edit CHANGELOG.md
- โŒ Create release branches manually
- โŒ Run `npm version` command
- โŒ Tag releases manually
**Let changesets handle:**
- โœ… Version bumping
- โœ… CHANGELOG generation
- โœ… Release PR creation
- โœ… Git tags
- โœ… npm publishing
---
_Last updated: 2026-05-20_
_Project: @adcp/sdk_