-
Notifications
You must be signed in to change notification settings - Fork 24
Add Content Standards Protocol #621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
bokelley
wants to merge
22
commits into
2.6.x
Choose a base branch
from
bokelley/content-standards
base: 2.6.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
22 commits
Select commit
Hold shift + click to select a range
1b3f1aa
Add Content Standards Protocol for content safety evaluation
bokelley 43f98e1
Simplify content standards policy model
bokelley 004c6df
Fix broken links in content standards docs
bokelley 6d21696
Align content standards with property protocol patterns
bokelley 2ddcbac
Clarify buyer-managed scope selection model
bokelley dc5fbf8
Address review comments on content standards
bokelley 41a1ab0
Refine content standards schema and examples
bokelley 86d79a4
Integrate robust content-context schema from sit/adcp
bokelley 212bac5
Update changeset to list all 8 tasks
bokelley dee7861
Rename check_content to calibrate_content for collaborative calibration
bokelley a0fe830
Use protocol-level context for calibration dialogue
bokelley d6576ad
Rename content-context to content with assets array
bokelley f12b35c
Rename content to artifact with property_id + artifact_id
bokelley 59cfe75
Remove signals field, add secured asset access
bokelley d993487
Add artifacts page, restructure overview with strategic framework
bokelley 69511fc
Simplify artifact schema: assets required, title as asset, add varian…
bokelley 2ba4772
Address review comments on content standards overview
bokelley a317d96
Simplify calibrate_content response schema and examples
bokelley a8bab27
Clarify validate_content_delivery data flow: buyer as intermediary
bokelley be23208
Add get_media_buy_artifacts task for separate content retrieval
bokelley a920df1
Address review comments on validate_content_delivery schema
bokelley d7a85a4
Address PR review comments on Content Standards Protocol
bokelley File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| --- | ||
| "adcontextprotocol": minor | ||
| --- | ||
|
|
||
| Add Content Standards Protocol for content safety and suitability evaluation. | ||
|
|
||
| Discovery tasks: | ||
| - `list_content_features`: Discover available content safety features | ||
| - `list_content_standards`: List available standards configurations | ||
| - `get_content_standards`: Retrieve content safety policies | ||
|
|
||
| Management tasks: | ||
| - `create_content_standards`: Create a new standards configuration | ||
| - `update_content_standards`: Update an existing configuration | ||
| - `delete_content_standards`: Delete a configuration | ||
|
|
||
| Calibration & Validation tasks: | ||
| - `calibrate_content`: Collaborative dialogue to align on policy interpretation | ||
| - `validate_content_delivery`: Batch validate delivery records |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,304 @@ | ||
| --- | ||
| title: Artifacts | ||
| sidebar_position: 2 | ||
| --- | ||
|
|
||
| # Artifacts | ||
|
|
||
| An **artifact** is a unit of content adjacent to an ad placement. When evaluating brand safety and suitability, you're asking: "Is this artifact appropriate for my brand's ads?" | ||
|
|
||
| ## What Is an Artifact? | ||
|
|
||
| Artifacts represent the content context where an ad appears: | ||
|
|
||
| - A **news article** on a website | ||
| - A **podcast segment** between ad breaks | ||
| - A **video chapter** in a YouTube video | ||
| - A **social media post** in a feed | ||
| - 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 an opaque identifier for that specific piece of content. The artifact_id scheme is flexible - it could be a URL path, a platform-specific ID, or any consistent identifier the property owner uses internally. | ||
|
|
||
| ## Structure | ||
|
|
||
| **Schema**: [artifact.json](https://adcontextprotocol.org/schemas/v2/content-standards/artifact.json) | ||
|
|
||
| ```json | ||
| { | ||
| "property_id": {"type": "domain", "value": "reddit.com"}, | ||
| "artifact_id": "r_fitness_post_abc123", | ||
| "assets": [ | ||
| {"type": "text", "role": "title", "content": "Best protein sources for muscle building", "language": "en"}, | ||
| {"type": "text", "role": "paragraph", "content": "Looking for recommendations on high-quality protein sources...", "language": "en"}, | ||
| {"type": "image", "url": "https://cdn.reddit.com/fitness-image.jpg", "alt_text": "Person lifting weights"} | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| ### Required Fields | ||
|
|
||
| | Field | Description | | ||
| |-------|-------------| | ||
| | `property_id` | Where this artifact lives - uses standard identifier types (`domain`, `app_id`, `apple_podcast_id`, etc.) | | ||
| | `artifact_id` | Unique identifier within the property - the property owner defines their scheme | | ||
| | `assets` | Content in document order - text blocks, images, video, audio | | ||
|
|
||
| ### Optional Fields | ||
|
|
||
| | Field | Description | | ||
| |-------|-------------| | ||
| | `variant_id` | Identifies a specific variant (A/B test, translation, temporal version) | | ||
| | `format_id` | Reference to format registry (same as creative formats) | | ||
| | `url` | Web URL if the artifact has one | | ||
| | `metadata` | Artifact-level metadata (Open Graph, JSON-LD, author info) | | ||
| | `published_time` | When the artifact was published | | ||
| | `last_update_time` | When the artifact was last modified | | ||
|
|
||
| ## Variants | ||
|
|
||
| The same artifact may have multiple variants: | ||
|
|
||
| - **Translations** - English version vs Spanish version | ||
| - **A/B tests** - Different headlines being tested | ||
| - **Temporal versions** - Content that changed on Wednesday | ||
|
|
||
| Use `variant_id` to distinguish between them: | ||
|
|
||
| ```json | ||
| // English version | ||
| { | ||
| "property_id": {"type": "domain", "value": "nytimes.com"}, | ||
| "artifact_id": "article_12345", | ||
| "variant_id": "en", | ||
| "assets": [ | ||
| {"type": "text", "role": "title", "content": "Breaking News Story", "language": "en"} | ||
| ] | ||
| } | ||
|
|
||
| // Spanish translation | ||
| { | ||
| "property_id": {"type": "domain", "value": "nytimes.com"}, | ||
| "artifact_id": "article_12345", | ||
| "variant_id": "es", | ||
| "assets": [ | ||
| {"type": "text", "role": "title", "content": "Noticia de última hora", "language": "es"} | ||
| ] | ||
| } | ||
|
|
||
| // A/B test variant | ||
| { | ||
| "property_id": {"type": "domain", "value": "nytimes.com"}, | ||
| "artifact_id": "article_12345", | ||
| "variant_id": "headline_test_b", | ||
| "assets": [ | ||
| {"type": "text", "role": "title", "content": "Alternative Headline Being Tested", "language": "en"} | ||
| ] | ||
| } | ||
| ``` | ||
|
|
||
| The combination of `artifact_id` + `variant_id` must be unique within a property. This lets you track which variant a user saw and correlate it with delivery reports. | ||
|
|
||
| ## Asset Types | ||
|
|
||
| Assets are the actual content within an artifact. Everything is an asset - titles, paragraphs, images, videos. | ||
|
|
||
| ### Text | ||
|
|
||
| ```json | ||
| {"type": "text", "role": "title", "content": "Article Title", "language": "en"} | ||
| {"type": "text", "role": "paragraph", "content": "The article body text...", "language": "en"} | ||
| {"type": "text", "role": "description", "content": "A summary of the article", "language": "en"} | ||
| {"type": "text", "role": "heading", "content": "Section Header", "heading_level": 2} | ||
| {"type": "text", "role": "quote", "content": "A quoted statement"} | ||
| ``` | ||
|
|
||
| Roles: `title`, `description`, `paragraph`, `heading`, `caption`, `quote`, `list_item` | ||
|
|
||
| Each text asset can have its own `language` tag for mixed-language content. | ||
|
|
||
| ### Image | ||
|
|
||
| ```json | ||
| { | ||
| "type": "image", | ||
| "url": "https://cdn.example.com/photo.jpg", | ||
| "alt_text": "Description of the image" | ||
| } | ||
| ``` | ||
|
|
||
| ### Video | ||
|
|
||
| ```json | ||
| { | ||
| "type": "video", | ||
| "url": "https://cdn.example.com/video.mp4", | ||
| "transcript": "Full transcript of the video content...", | ||
| "duration_ms": 180000 | ||
| } | ||
| ``` | ||
|
|
||
| ### Audio | ||
|
|
||
| ```json | ||
| { | ||
| "type": "audio", | ||
| "url": "https://cdn.example.com/podcast.mp3", | ||
| "transcript": "Today we're discussing...", | ||
| "duration_ms": 3600000 | ||
| } | ||
| ``` | ||
|
|
||
| ## Metadata | ||
|
|
||
| Artifact-level metadata describes the artifact as a whole, not individual assets: | ||
|
|
||
| ```json | ||
| { | ||
| "metadata": { | ||
| "author": "Jane Smith", | ||
| "canonical": "https://example.com/article/12345", | ||
| "open_graph": { | ||
| "og:type": "article", | ||
| "og:site_name": "Example News" | ||
| }, | ||
| "json_ld": [ | ||
| { | ||
| "@type": "NewsArticle", | ||
| "datePublished": "2025-01-15" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| This is separate from assets because it's about the artifact container, not the content itself. | ||
|
|
||
| ## Secured Asset Access | ||
|
|
||
| Many assets aren't publicly accessible - AI-generated images, private conversations, paywalled content. The artifact schema supports authenticated access. | ||
|
|
||
| ### Pre-Configuration (Recommended) | ||
|
|
||
| For ongoing partnerships, configure access once during onboarding rather than per-request: | ||
|
|
||
| 1. **Service account sharing** - Grant the verification agent access to your cloud storage | ||
| 2. **OAuth client credentials** - Set up machine-to-machine authentication | ||
| 3. **API key exchange** - Share long-lived API keys during setup | ||
|
|
||
| This happens during the activation phase when the seller first receives content standards from a buyer. | ||
|
|
||
| ### Per-Asset Authentication | ||
|
|
||
| When pre-configuration isn't possible, include access credentials with individual assets: | ||
|
|
||
| ```json | ||
| { | ||
| "type": "image", | ||
| "url": "https://cdn.openai.com/secured/img_abc123.png", | ||
| "access": { | ||
| "method": "bearer_token", | ||
| "token": "eyJhbGciOiJIUzI1NiIs..." | ||
| } | ||
|
Comment on lines
+199
to
+202
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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. |
||
| } | ||
| ``` | ||
|
|
||
| **Note on token size**: For artifacts with many assets, per-asset tokens can significantly increase payload size. Consider: | ||
|
|
||
| 1. **Pre-configured access** - Set up service account access once during onboarding | ||
| 2. **Shared token reference** - Define tokens at the artifact level and reference by ID | ||
| 3. **Signed URLs** - Use pre-signed URLs where the URL itself is the credential | ||
|
|
||
| The `url` field is the access URL - it may differ from the artifact's canonical/published URL. For example, a published article at `https://news.example.com/article/123` might have assets served from `https://cdn.example.com/secured/...`. | ||
|
|
||
| ### Access Methods | ||
|
|
||
| | Method | Use Case | | ||
| |--------|----------| | ||
| | `bearer_token` | OAuth2 bearer token in Authorization header | | ||
| | `service_account` | GCP/AWS service account credentials | | ||
| | `signed_url` | Pre-signed URL with embedded credentials (URL itself is the credential) | | ||
|
|
||
| ### Service Account Setup | ||
|
|
||
| For GCP: | ||
|
|
||
| ```json | ||
| { | ||
| "access": { | ||
| "method": "service_account", | ||
| "provider": "gcp", | ||
| "credentials": { | ||
| "type": "service_account", | ||
| "project_id": "my-project", | ||
| "private_key_id": "...", | ||
| "private_key": "-----BEGIN PRIVATE KEY-----\n...", | ||
| "client_email": "[email protected]" | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| For AWS: | ||
|
|
||
| ```json | ||
| { | ||
| "access": { | ||
| "method": "service_account", | ||
| "provider": "aws", | ||
| "credentials": { | ||
| "access_key_id": "AKIAIOSFODNN7EXAMPLE", | ||
| "secret_access_key": "...", | ||
| "region": "us-east-1" | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| ### Pre-Signed URLs | ||
|
|
||
| For one-off access without sharing credentials: | ||
|
|
||
| ```json | ||
| { | ||
| "type": "video", | ||
| "url": "https://storage.googleapis.com/bucket/video.mp4?X-Goog-Algorithm=GOOG4-RSA-SHA256&X-Goog-Credential=...&X-Goog-Signature=...", | ||
| "access": { | ||
| "method": "signed_url" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The URL itself contains the credentials - no additional authentication needed. | ||
|
|
||
| ## Property Identifier Types | ||
|
|
||
| The `property_id` uses standard identifier types from the AdCP property schema: | ||
|
|
||
| | Type | Example | Use Case | | ||
| |------|---------|----------| | ||
| | `domain` | `reddit.com` | Websites | | ||
| | `app_id` | `com.spotify.music` | Mobile apps | | ||
| | `apple_podcast_id` | `1234567890` | Apple Podcasts | | ||
| | `spotify_show_id` | `4rOoJ6Egrf8K2IrywzwOMk` | Spotify podcasts | | ||
| | `youtube_channel_id` | `UCddiUEpeqJcYeBxX1IVBKvQ` | YouTube channels | | ||
| | `rss_url` | `https://feeds.example.com/podcast.xml` | RSS feeds | | ||
|
|
||
| ## Artifact ID Schemes | ||
|
|
||
| The property owner defines their artifact_id scheme. Examples: | ||
|
|
||
| | Property Type | Artifact ID Pattern | Example | | ||
| |---------------|---------------------|---------| | ||
| | News website | `article_{id}` | `article_12345` | | ||
| | Reddit | `r_{subreddit}_{post_id}` | `r_fitness_abc123` | | ||
| | Podcast | `episode_{num}_segment_{num}` | `episode_42_segment_2` | | ||
| | CTV | `show_{id}_s{season}e{episode}_scene_{num}` | `show_abc_s3e5_scene_12` | | ||
| | Social feed | `post_{id}` | `post_xyz789` | | ||
|
|
||
| The verification agent doesn't need to understand the scheme - it's opaque. The property owner uses it to correlate artifacts with their content. | ||
|
|
||
| ## Related | ||
|
|
||
| - [Content Standards Overview](/docs/governance/content-standards) - How artifacts fit into the content standards workflow | ||
| - [calibrate_content](/docs/governance/content-standards/tasks/calibrate_content) - Sending artifacts for calibration | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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).