Skip to content

Conversation

@bokelley
Copy link
Contributor

@bokelley bokelley commented Jan 5, 2026

Summary

Adds the Content Standards Protocol - draft governance protocol for content safety and suitability rules.

  • Documentation in docs/governance/content-standards/
  • JSON schemas in static/schemas/source/content-standards/
  • Task definitions: list_content_features, get_content_standards, list_content_standards, check_content
  • Feature-based verification pattern (binary, quantitative, categorical)
  • Prompt-based policies for AI evaluation

Draft for AdCP 3.0 - Part of the AAO Governance Working Group initiatives.

Test plan

  • Verify docs render correctly with mintlify dev
  • Verify schemas validate with npm test
  • Review schema structure against Property Governance pattern

🤖 Generated with Claude Code

bokelley and others added 8 commits January 5, 2026 08:21
Introduces the Content Standards Protocol with four tasks:
- list_content_features: Discover available content safety features
- get_content_standards: Retrieve content safety policies
- check_content: Evaluate content context against safety policies
- validate_content_delivery: Batch validate delivery records

Features use a generic type system (binary, quantitative, categorical)
aligned with property governance patterns. Policies use prompt-based
evaluation (like Scope3) rather than keyword lists. Standards can be
scoped by country, brand, channel, and product.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Remove sentiment analysis (subset of suitability)
- Clarify brand safety vs suitability distinction:
  - Safety = safe for ANY brand (universal thresholds)
  - Suitability = safe for MY brand (brand-specific)
- Replace three separate prompts with single policy + examples:
  - Single policy prompt for natural language guidelines
  - Examples object with acceptable/unacceptable URLs as training set
- Update schema and documentation to match

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove links to Property Governance and Creative Standards which don't
exist in this branch yet.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Address review comments:

1. Examples now use typed identifiers with language tags:
   - Uses identifier schema pattern (type: domain, apple_podcast_id, rss_url, etc.)
   - Added language field (BCP 47 tags like 'en', 'en-US')
   - Created content-example.json schema

2. Scope fields aligned with property protocol:
   - brands → brand_ids (references Brand Manifest identifiers)
   - countries → countries_all (must apply in ALL listed countries)
   - channels → channels_any (applies to ANY listed channel)
   - Removed products field (unclear purpose)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
The buyer selects the appropriate standards_id when creating a media buy.
The seller receives a reference to resolved standards - they don't need
to do scope matching themselves. Scope fields are metadata for the buyer's
internal organization, not for seller-side resolution.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
1. Scope is targeting, not metadata:
   - Clarified scope defines where standards apply
   - Removed "metadata" language

2. Add CRUD tasks for standards management:
   - Added list_content_standards, create_content_standards,
     update_content_standards, delete_content_standards
   - Organized tasks into Discovery, Management, Evaluation sections
   - Created task documentation pages

3. Clarify evaluation results pattern:
   - Always returns pass/fail verdict first
   - Features array is optional breakdown for debugging
   - Explains use cases: optimization, safety vs suitability,
     debugging third-party standards (GARM, Scope3)
   - Updated check-content-response and validate-content-delivery-response
     schemas to use verdict + optional features pattern

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Address review comments:

1. Rename 'examples' to 'calibration':
   - Better describes the purpose (training/test set for AI interpretation)
   - Add support for text snippets, image/video/audio URLs

2. Create unified content-context.json schema:
   - Used for both calibration examples and check_content requests
   - Supports: domain, text, image_url, video_url, audio_url, rss_url,
     apple_podcast_id, spotify_show_id, podcast_guid
   - Optional metadata: language, title, description, categories, text_content

3. Flatten scope structure:
   - Move brand_ids, countries_all, channels_any to top level
   - Aligns with property protocol pattern

4. Remove fixed response time claims:
   - check_content may be async with webhook callback
   - Let implementations define their own SLAs

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Integrates comprehensive content-context schema improvements:

1. Signals array (replaces simple categories):
   - Structured signals with key, value, confidence
   - Supports version, source, and reasons
   - Examples: iab_category, violence_score, mpaa_rating

2. Structured text_content (replaces simple string):
   - Array of typed blocks: paragraph, heading, image, video, audio
   - Images include alt_text, caption, dimensions, type
   - Video/audio include duration, transcript, transcript_source

3. Rich metadata object:
   - Open Graph, Twitter Card, JSON-LD
   - Author, canonical URL, meta tags

4. Temporal fields:
   - published_time, last_update_time (ISO 8601)

5. artifact_id for cross-reference tracking

6. additionalProperties: true for extensibility

Credit: sit@ca367da

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@bokelley bokelley changed the title Add Content Standards Protocol for AdCP 3.0 Add Content Standards Protocol Jan 5, 2026
@bokelley bokelley changed the base branch from main to 2.6.x January 5, 2026 23:57
bokelley and others added 13 commits January 7, 2026 04:28
🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Rename task to emphasize dialogue-based alignment vs runtime evaluation
- Add context_id and feedback parameters for multi-turn conversations
- Include verbose explanations with confidence scores and policy alignment
- Add workflow diagram showing Setup → Activation → Runtime phases
- Update schemas with calibrate-content-request/response
- Remove old check-content schemas
- Update related task links across all task docs

Key insight: calibrate_content is low-volume, verbose, dialogue-based;
runtime decisioning happens locally at seller for scale.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Remove context_id and feedback from calibrate_content task - dialogue
is handled at the protocol layer via A2A contextId or MCP context_id.

Updated documentation to show how multi-turn calibration conversations
work using the existing protocol mechanisms for conversation management.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Addresses feedback:
1. Rename "content-context" to "content" - too many "context" terms
2. Restructure to use assets array pattern like creative assets

Content is now represented as a collection of assets (text, images,
video, audio) plus metadata and signals. This aligns with the creative
asset model and avoids overloading "context" terminology.

Key changes:
- content.json replaces content-context.json
- assets array with typed blocks (text, image, video, audio)
- identifiers object for platform-specific IDs (apple_podcast_id, etc.)
- url is now the primary required field
- Updated all docs and schema references

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Content adjacent to ads is now modeled as an "artifact" - identified by
property_id (using existing identifier types) plus artifact_id (string
defined by property owner). This avoids overloading "content" and enables
identification of artifacts that don't have URLs (Instagram, podcasts,
TV scenes).

Changes:
- Rename content.json to artifact.json with new required fields
- property_id uses existing identifier type schema (type + value)
- artifact_id is a string - property owner defines the scheme
- format_id optional - can reference format registry (like creative formats)
- url now optional since not all artifacts have URLs
- Update all schema references and documentation examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Address review feedback:

1. Remove signals from artifact schema and examples - the verification
   agent evaluates content directly without pre-computed classifications.
   This simplifies the model: send content, get responses.

2. Add secured URL access pattern for private assets - supports bearer
   tokens, service accounts, and pre-signed URLs for content that isn't
   publicly accessible (AI-generated images, private conversations,
   paywalled content).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Restructure Content Standards docs around the key strategic questions:

1. What content? → New artifacts.mdx page with full schema details
2. How much adjacency? → Define in products, negotiate in media buys
3. What sampling rate? → Negotiate coverage vs cost tradeoffs
4. How to calibrate? → Dialogue-based alignment process

Changes:
- Add standalone artifacts.mdx with asset types and secured access
- Replace ASCII workflow with mermaid sequence diagram
- Add adjacency and sampling_rate sections to overview
- Simplify policy examples (remove verbose calibration details)
- Move secured URL access documentation to artifacts page

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…t_id

- Make assets array required (artifacts without content are meaningless)
- Remove title, language, description top-level fields (they're text assets)
- Add variant_id for A/B tests, translations, and temporal versions
- Add language field to text assets for mixed-language content
- Update all documentation examples to use new pattern
- Fix schema validation test to handle internal $defs references

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Rename content_standards to content_standards_adjacency_definition
- Add Adjacency Units table defining: posts, scenes, segments, seconds, viewports, articles
- Clarify human-in-the-loop aspect of calibration process

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Address review comments:
- Remove suggestion field from features (not appropriate for calibration)
- Remove policy_alignment (redundant with features breakdown)
- Make confidence explicitly optional in docs
- Simplify A2A examples to use data-only parts (no text when calling skill)
- Update response field table to show required vs optional

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Address review comment about who calls validate_content_delivery:
- Delivery records flow from seller → buyer → verification agent
- Buyer aggregates delivery data and knows which standards_id applies
- Verification agent works on behalf of the buyer

Changes:
- Add Data Flow section with mermaid diagram to validate_content_delivery.mdx
- Add media_buy_id field to request schema and delivery records
- Update overview mermaid diagram to show correct flow
- Remove suggestion field from response examples

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Content artifacts (text, images, video) are separate from delivery
metrics. This new task allows buyers to request content samples from
sellers for validation, keeping the data flow clean:

- Buyer calls get_media_buy_artifacts to get content samples
- Buyer validates samples with verification agent
- Delivery metrics stay in get_media_buy_delivery

Updates validate_content_delivery flow to reference new task.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
1. Remove redundant top-level media_buy_id - keep at record level since
   records can come from multiple media buys

2. Add country and channel fields to delivery records for targeting
   context validation

3. Replace creative_id with brand_context placeholder object - the
   governance agent needs brand/SKU info, not opaque creative IDs.
   Schema marked as TBD pending brand identifier standardization.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>

**Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json)

An artifact represents content adjacent to an ad placement - identified by `property_id` + `artifact_id` and represented as a collection of assets:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
An artifact represents content adjacent to an ad placement - identified by `property_id` + `artifact_id` and represented as a collection of assets:
An artifact represents content context where ad placements occur - identified by `property_id` + `artifact_id` and represented as a collection of assets:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sit why do you think "context where placements occur" is more clear? l can imagine adjacent not being descriptive but do you have an example?

{
"errors": [
{
"code": "STANDARDS_NOT_FOUND",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it important to add this to the list of standard error codes?

I wonder if worth documenting an error like "STANDARD_IN_USE".

{
"type": "object",
"description": "Success response",
"properties": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wonder if it's worth having a standard.json to reference, similar to artifact.json. Then this and the create_content_standards could have a common schema and we could validate all the fields are the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intuitively why would describing my standards have a similar schema to describing the artifact we're assessing? or do you mean "break out the object"

Comment on lines 20 to 24
"effective_date": {
"type": "string",
"format": "date-time",
"description": "When this version became effective"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can a standard be effective at multiple times, applied to different campaigns?

Would looking for a null or "" be a way to determine which standards are unused (e.g., for the purposes of deletion)? Or maybe it has to be inferred by listing media buys and seeing which ones have standards active.

Or if this intended to indicate when we should start using this standard as opposed to when we started using it ("became effective" vs "becomes effective")— in that case what happens when there are multiple effective at the same time, and should there be a "termination_date" concept.

"type": "string",
"description": "Natural language policy describing acceptable and unacceptable content contexts"
},
"calibration": {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could see this getting quite large and blowing up context windows easily.

- A **scene** in a CTV show
- An **AI-generated image** in a chat conversation

Artifacts are identified by `property_id` + `artifact_id` - the property defines where the content lives, and the artifact_id is the property owner's identifier for that specific piece of content.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, that's not what we do today — artifact_id in our current system is a domain/path combo. And we don't ask the property owner for the id of course, we take it from the URL itself.

For Meta, we use meta:<meta_id> as a distinguisher, even though we also have a source: META field.

Comment on lines +199 to +202
"access": {
"method": "bearer_token",
"token": "eyJhbGciOiJIUzI1NiIs..."
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a lot of tokens (e.g., we've seen web pages where we extract hundreds of images... whether or not that's a good idea).

I'd consider extracting an auth mechanism that could be referenced, either within the response or outside the workflow.

```json
{
"type": "image",
"url": "https://cdn.openai.com/secured/img_abc123.png",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could consider distinguishing the published official URL from some internal access URL (e.g.,a GCS bucket or something).

|-----------|------|----------|-------------|
| `brand_ids` | array | No | Filter by brand identifiers |
| `countries` | array | No | Filter by country codes |
| `channels` | array | No | Filter by channels |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could add a filter for effective date?


```json
{
"standards": [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could reference schema here, not sure if these examples are intentionally abbreviated or not (e.g., do you want to see the calibration data in this response).

- #1/#16: Update artifact description to "content context where placements occur"
- #2: Add STANDARDS_IN_USE error code to delete_content_standards
- #4: Clarify effective_date semantics (null = not yet effective, multiple allowed)
- #5: Add note about calibration data size concerns
- #7: Document scope conflict handling in create_content_standards
- #8/#9: Rename examples to calibration for consistency
- #10: Increase validate_content_delivery response time to 60s
- #11: Clarify artifact_id is opaque/flexible
- #12/#13: Add notes about auth mechanism extraction for large artifacts
- #14/#15: Add effective_date filter and abbreviated response note to list

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants