{"id":51124400,"url":"https://github.com/f/sign-ai-media","last_synced_at":"2026-06-25T06:01:06.601Z","repository":{"id":355196381,"uuid":"1227168652","full_name":"f/sign-ai-media","owner":"f","description":"Sign images and videos with C2PA provenance declaring AI-generated media.","archived":false,"fork":false,"pushed_at":"2026-05-02T11:08:15.000Z","size":259,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-02T12:06:45.653Z","etag":null,"topics":["ai-generated","c2pa","cli","content-authenticity","image","media","nodejs","provenance","typescript","video"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/sign-ai-media","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/f.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-02T09:57:30.000Z","updated_at":"2026-05-02T11:08:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/f/sign-ai-media","commit_stats":null,"previous_names":["f/sign-ai-media"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/f/sign-ai-media","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fsign-ai-media","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fsign-ai-media/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fsign-ai-media/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fsign-ai-media/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/f","download_url":"https://codeload.github.com/f/sign-ai-media/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/f%2Fsign-ai-media/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34761847,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-generated","c2pa","cli","content-authenticity","image","media","nodejs","provenance","typescript","video"],"created_at":"2026-06-25T06:01:05.813Z","updated_at":"2026-06-25T06:01:06.584Z","avatar_url":"https://github.com/f.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"./assets/logo-lockup-dark.png\"\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"./assets/logo-lockup-light.png\"\u003e\n    \u003cimg src=\"./assets/logo-lockup-light.png\" alt=\"sign-ai-media logo\" width=\"600\"\u003e\n  \u003c/picture\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  Sign images and videos with C2PA provenance that clearly declares AI-generated media.\n\u003c/p\u003e\n\n`sign-ai-media` is a small open-source Node.js package for adding signed [C2PA](https://c2pa.org/) manifests to generated images and videos. It writes a standards-based AI source signal, lets you control the generator identity shown in the manifest, and exposes both a CLI and a TypeScript API.\n\nIt is designed for model hosts, generation apps, internal media pipelines, dataset tooling, and any workflow that wants to label generated media without pretending to be another provider.\n\n## Browser Demo\n\nTry the browser-only signer and viewer:\n\nhttps://blog.fka.dev/sign-ai-media/\n\nThe demo runs entirely in the browser with `@contentauth/c2pa-web` WebAssembly and bundled development signing credentials. It is useful for testing, demos, and local experiments. Use production C2PA credentials for public/user-facing provenance.\n\n## Claude Code Skill\n\nThis repo includes a Claude Code skill:\n\n```text\n.claude/skills/sign-ai-media/SKILL.md\n```\n\nClaude Code can load project skills from the repository's `.claude/skills/` directory. To use this skill in another project, copy the skill directory into that project's `.claude/skills/` folder:\n\n```sh\nnpx skills add f/sign-ai-media --skill sign-ai-media\n```\n\nFor a global install, use `-g` so Claude Code can find it from any project:\n\n```sh\nnpx skills add f/sign-ai-media --skill sign-ai-media -g -y\n```\n\nVerify the global install with:\n\n```sh\nnpx skills list -g\n```\n\nThen restart Claude Code, or start a new session, and ask naturally:\n\n```text\nUse the sign-ai-media skill to sign this image as AI-generated.\n```\n\n```text\nUse the sign-ai-media skill to inspect this file's C2PA metadata.\n```\n\n```text\nUse the sign-ai-media skill to add browser-side signing with the CDN API.\n```\n\nUse the skill when you want Claude Code to help sign media, inspect C2PA metadata, choose the right CLI flags, or integrate the browser/CDN API. The skill mirrors the same CLI, TypeScript API, and browser CDN usage documented below.\n\n## What It Writes\n\nThe default manifest includes:\n\n- A `c2pa.actions.v2` assertion with `action: \"c2pa.created\"`.\n- A configurable `softwareAgent` object with `name` and optional `version`.\n- The IPTC digital source type `trainedAlgorithmicMedia`.\n- A `stds.schema-org.CreativeWork` assertion for optional generator, model, producer, prompt, and custom metadata.\n- A C2PA signature. You can provide your own certificate/private key, or use the bundled development signer for lower-friction local use.\n\nThe default AI source marker is:\n\n```text\nhttp://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia\n```\n\n## Installation\n\n```sh\nnpm install sign-ai-media\n```\n\nYou can also run the CLI without installing it first:\n\n```sh\nnpx sign-ai-media input.png output.png --software-agent \"my-generator\"\n```\n\nThis package uses `@contentauth/c2pa-node`, which ships native bindings. Prebuilt binaries are available for common macOS, Linux, and Windows platforms. Other platforms may need a local Rust toolchain.\n\n## Browser CDN API\n\nA browser ESM bundle is published from this repository and can be loaded directly from jsDelivr:\n\n```html\n\u003cscript type=\"module\"\u003e\n  import {\n    signAiGeneratedMedia,\n    viewAiGeneratedMedia,\n  } from \"https://cdn.jsdelivr.net/gh/f/sign-ai-media@main/web/cdn/sign-ai-media.browser.js\";\n\n  const file = document.querySelector(\"input[type=file]\").files[0];\n\n  const { blob } = await signAiGeneratedMedia(file, {\n    metadata: {\n      softwareAgent: \"my-generator\",\n      version: \"1.0.0\",\n      generator: \"My Generator\",\n      model: \"my-model-v1\",\n      producer: \"My Org\",\n      prompt: \"A red fox in a snowy forest\",\n    },\n  });\n\n  const signedFile = new File([blob], \"signed.png\", { type: blob.type });\n  console.log(await viewAiGeneratedMedia(signedFile));\n\u003c/script\u003e\n```\n\nFor pinned production use, replace `@main` with a commit SHA or release tag.\n\n## CLI Usage\n\n```sh\nnpx sign-ai-media input.png output.png \\\n  --software-agent \"acme-image-model\" \\\n  --version \"1.0.0\" \\\n  --generator \"Acme Image API\" \\\n  --model \"acme-diffusion-v1\" \\\n  --producer \"Acme Labs\"\n```\n\nFor production provenance, pass your own signing credentials:\n\n```sh\nnpx sign-ai-media input.png output.png \\\n  --software-agent \"acme-image-model\" \\\n  --certificate ./certs/signing-cert.pem \\\n  --private-key ./certs/signing-key.pem \\\n  --algorithm es256 \\\n  --tsa-url \"https://timestamp.example.com\"\n```\n\n## Viewing Metadata\n\nTo inspect AI/C2PA metadata in a signed file, use `--view` with the input file:\n\n```sh\nnpx sign-ai-media --view output.png\n```\n\nThe viewer does not modify the file. It reads the active C2PA manifest, extracts the AI-generation fields written by this package, and prints a readable summary:\n\n```text\nAI media metadata: output.png\nStatus: C2PA manifest found\nTitle: output.png\nFormat: image/png\nClaim generator: acme-image-service/1.0.0\nGenerator: Acme Image API\nModel: acme-diffusion-v1\nProducer: Acme Labs\nSoftware agent: {\"name\":\"acme-image-model\",\"version\":\"1.0.0\"}\nAction: c2pa.created\nCreated at: 2026-05-02T09:00:00.000Z\nDigital source type: http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia\nValidation: No validation issues reported.\nAssertions:\n  - c2pa.actions.v2\n  - stds.schema-org.CreativeWork\n```\n\nIf no C2PA manifest is present, the viewer prints:\n\n```text\nAI media metadata: input.png\nStatus: No C2PA manifest found.\n```\n\nUseful metadata options:\n\n```sh\n--source-type ai-generated\n--claim-generator \"acme-image-service/1.0.0\"\n--prompt \"A red fox in a snowy forest\"\n--prompt-file ./prompt.txt\n--negative-prompt \"low quality, blurry\"\n--seed 12345\n--scheduler \"euler-a\"\n--cfg-scale 7.5\n--steps 30\n--created-at \"2026-05-02T09:00:00Z\"\n--digital-source-type \"http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia\"\n--creative-work-json '{\"usageInfo\":\"internal\",\"copyrightNotice\":\"Acme Labs\"}'\n--mime-type image/png\n--remote-manifest-url \"https://cdn.example.com/manifests/image.c2pa\"\n--no-embed\n```\n\nAction/provenance options:\n\n```sh\n--action c2pa.created\n--action-description \"Generated from a text prompt\"\n--action-parameters-json '{\"pipeline\":\"txt2img\"}'\n--ingredient ./source-image.png\n--ingredient ./mask.png\n--parent ./original.png\n--model-uri \"https://example.com/models/acme-diffusion-v1\"\n--model-hash \"sha256:...\"\n--input-uri \"https://example.com/inputs/reference.png\"\n--input-hash \"sha256:...\"\n```\n\nTraining and data-mining policy options:\n\n```sh\n--ai-training-use notAllowed\n--ai-generative-training-use notAllowed\n--data-mining-use constrained\n--ai-inference-use allowed\n--training-constraint-info \"See https://example.com/ai-use-policy\"\n```\n\nViewer options:\n\n```sh\nnpx sign-ai-media --view output.png --json\nnpx sign-ai-media --view output.png --verify-trust --trust-anchors ./anchors.pem\nnpx sign-ai-media --view output.png --fetch-remote-manifest\nnpx sign-ai-media --view output.png --no-fetch-remote-manifest\n```\n\n## Why not c2patool?\n\n[`c2patool`](https://opensource.contentauthenticity.org/docs/c2patool/) is the official general-purpose command line tool for C2PA. It can read C2PA manifest reports, inspect low-level manifest data, and add manifests to supported media files.\n\nUse `c2patool` when you want a broad, standards-level C2PA utility.\n\nUse `sign-ai-media` when you want a smaller tool focused on AI-generated media workflows:\n\n- It has simple flags for common AI metadata such as `--software-agent`, `--model`, `--prompt`, `--source-type`, `--seed`, and training/data-mining policy.\n- It writes an AI-oriented manifest shape by default, including `c2pa.actions.v2`, `trainedAlgorithmicMedia`, CreativeWork metadata, and optional CAWG training/data-mining assertions.\n- It includes a TypeScript API for Node.js apps, queues, media pipelines, and CMS integrations.\n- It includes a focused `--view` mode that extracts the AI/C2PA fields this package writes, instead of only showing a full generic manifest report.\n\nIn short: `c2patool` is the toolbox. `sign-ai-media` is the shortcut for signing and reading AI media provenance in apps and automation.\n\n## TypeScript API\n\n```ts\nimport { signAiGeneratedMedia, viewAiGeneratedMedia } from \"sign-ai-media\";\n\nawait signAiGeneratedMedia({\n  input: \"input.png\",\n  output: \"output.png\",\n  metadata: {\n    softwareAgent: \"acme-image-model\",\n    version: \"1.0.0\",\n    claimGenerator: \"acme-image-service/1.0.0\",\n    generator: \"Acme Image API\",\n    model: \"acme-diffusion-v1\",\n    modelVersion: \"2026-05-02\",\n    producer: \"Acme Labs\",\n    prompt: \"A red fox in a snowy forest\",\n    negativePrompt: \"low quality, blurry\",\n    seed: 12345,\n    scheduler: \"euler-a\",\n    cfgScale: 7.5,\n    steps: 30,\n    actionDescription: \"Generated from a text prompt\",\n    trainingMining: {\n      \"cawg.ai_training\": { use: \"notAllowed\" },\n      \"cawg.ai_generative_training\": { use: \"notAllowed\" },\n    },\n  },\n});\n\nconst metadata = await viewAiGeneratedMedia({\n  input: \"output.png\",\n});\n```\n\n`viewAiGeneratedMedia()` returns a JSON-serializable object, so it can be logged, sent from an API route, or stored directly:\n\n```ts\nconsole.log(JSON.stringify(metadata, null, 2));\n```\n\nExample result:\n\n```json\n{\n  \"input\": \"output.png\",\n  \"hasManifest\": true,\n  \"metadata\": {\n    \"title\": \"output.png\",\n    \"format\": \"image/png\",\n    \"claimGenerator\": \"acme-image-service/1.0.0\",\n    \"generator\": \"Acme Image API\",\n    \"model\": \"acme-diffusion-v1\",\n    \"producer\": \"Acme Labs\",\n    \"prompt\": \"A red fox in a snowy forest\",\n    \"softwareAgent\": {\n      \"name\": \"acme-image-model\",\n      \"version\": \"1.0.0\"\n    },\n    \"digitalSourceType\": \"http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia\",\n    \"createdAt\": \"2026-05-02T09:00:00.000Z\",\n    \"action\": \"c2pa.created\",\n    \"signatureIssuer\": \"Example Signing Cert\",\n    \"signatureTime\": \"2026-05-02T09:00:00+00:00\"\n  },\n  \"validationStatus\": [],\n  \"assertionLabels\": [\"c2pa.actions.v2\", \"stds.schema-org.CreativeWork\"]\n}\n```\n\nWhen no manifest is found, the result is:\n\n```json\n{\n  \"input\": \"input.png\",\n  \"hasManifest\": false,\n  \"metadata\": null,\n  \"validationStatus\": [],\n  \"assertionLabels\": []\n}\n```\n\nPass a signer when you want the manifest signed with your own production identity:\n\n```ts\nimport {\n  SigningAlgorithm,\n  createLocalSigner,\n  signAiGeneratedMedia,\n} from \"sign-ai-media\";\n\nconst signer = await createLocalSigner({\n  certificatePath: \"./certs/signing-cert.pem\",\n  privateKeyPath: \"./certs/signing-key.pem\",\n  algorithm: SigningAlgorithm.ES256,\n  tsaUrl: \"https://timestamp.example.com\",\n});\n\nawait signAiGeneratedMedia({\n  input: \"input.png\",\n  output: \"output.png\",\n  signer,\n  metadata: {\n    softwareAgent: \"acme-image-model\",\n    version: \"1.0.0\",\n    claimGenerator: \"acme-image-service/1.0.0\",\n    generator: \"Acme Image API\",\n    model: \"acme-diffusion-v1\",\n    producer: \"Acme Labs\",\n    prompt: \"A red fox in a snowy forest\",\n  },\n});\n```\n\n## Metadata Fields\n\n`metadata.softwareAgent` is required. It should name the model, service, app, or pipeline that created the media.\n\nOptional metadata:\n\n- `version`: version of the software agent or model.\n- `claimGenerator`: C2PA user-agent style claim generator. Defaults to `softwareAgent/version`.\n- `generator`: friendly generator name for CreativeWork metadata.\n- `model`: model name for consumers that display richer generator details.\n- `modelVersion`: model revision or version.\n- `modelUri` and `modelHash`: model or model-card reference.\n- `inputUri` and `inputHash`: remote input reference.\n- `producer`: organization, service, or creator responsible for the output.\n- `prompt`: prompt text to embed. Treat this as public metadata.\n- `negativePrompt`: negative prompt text to embed. Treat this as public metadata.\n- `seed`, `scheduler`, `cfgScale`, and `steps`: generation parameters.\n- `createdAt`: ISO timestamp. Defaults to the current time.\n- `digitalSourceType`: override the IPTC source type URL.\n- `action`: C2PA action name. Defaults to `c2pa.created`.\n- `actionDescription`: free-text action description.\n- `actionParameters`: extra action parameters for advanced C2PA workflows.\n- `trainingMining`: CAWG Training and Data Mining assertion entries.\n- `creativeWork`: extra properties merged into the schema.org CreativeWork assertion.\n\n## Digital Source Presets\n\nUse `--source-type` for common source types without remembering the full vocabulary URL:\n\n- `ai-generated`: created by a trained generative AI model.\n- `ai-edited`: human or tool edits using generative AI, such as inpainting or outpainting.\n- `algorithmic`: algorithmic media not based on sampled training data.\n- `algorithmically-enhanced`: algorithmic enhancement such as denoise or sharpen.\n- `composite-ai`: composite media with at least one generative AI element.\n- `composite`: composite of several elements.\n- `composite-capture`: composite where all elements are captures of real life.\n- `capture`: digital camera or sensor capture.\n- `screen-capture`: screen capture.\n- `human-edited`: non-generative human edits.\n- `digital-art`, `digital-creation`, `software-image`, and `data-driven`: other common IPTC source categories.\n- `empty`: C2PA empty asset source type.\n- `ai-data`: C2PA trained algorithmic data source type for non-media data.\n\nYou can still pass a full URL with `--digital-source-type`.\n\n## Ingredients and Parents\n\nUse `--ingredient` to attach source media that contributed to the signed output. Repeating the flag adds multiple `componentOf` ingredients:\n\n```sh\nnpx sign-ai-media output.png signed.png \\\n  --software-agent \"acme-image-model\" \\\n  --ingredient ./reference.png \\\n  --ingredient ./mask.png\n```\n\nUse `--parent` when the output is derived from an original asset:\n\n```sh\nnpx sign-ai-media edited.png signed.png \\\n  --software-agent \"acme-editor\" \\\n  --parent ./original.png \\\n  --action c2pa.edited \\\n  --action-description \"Inpainted background\"\n```\n\n## Training and Data Mining\n\nThe `--ai-training-use`, `--ai-generative-training-use`, `--data-mining-use`, and `--ai-inference-use` flags write a `cawg.training-mining` assertion using the [CAWG Training and Data Mining Assertion](https://cawg.io/training-and-data-mining/1.1/).\n\nEach flag accepts `allowed`, `notAllowed`, or `constrained`. When using `constrained`, add `--training-constraint-info` to explain the policy or link to a license.\n\n## Supported Media\n\nMIME type is inferred from common media extensions:\n\n- `.png`\n- `.jpg` and `.jpeg`\n- `.webp`\n- `.avif`\n- `.tif` and `.tiff`\n- `.mp4`\n- `.mov`\n- `.avi`\n\nPass `--mime-type` or `mimeType` when the extension is missing or unusual.\n\n## Signing Credentials\n\nC2PA manifests need a signer, but this package does not require users to bring a certificate/private-key pair just to get started. If no signer is provided, `signAiGeneratedMedia()` and the CLI use bundled test credentials.\n\nFor production provenance, pass a local certificate/private-key pair through `createLocalSigner()` or another compatible `@contentauth/c2pa-node` signer object. Do not use another company's name, certificate, or identity fields.\n\n### Where to get production certificates\n\nProduction C2PA signing credentials should come from a certificate authority on the C2PA trust list. The official Content Authenticity Initiative docs explain that conforming generator products must use a certificate that chains back to a trusted C2PA certificate authority, and that C2PA maintains separate trust lists for claim-signing certificates and timestamp authorities.\n\nStart here:\n\n- [Getting a signing certificate](https://opensource.contentauthenticity.org/docs/signing/get-cert) from the CAI open-source docs.\n- [C2PA trust lists](https://opensource.contentauthenticity.org/docs/conformance/trust-lists), including the C2PA trust list and C2PA TSA trust list.\n- [C2PA Conformance Explorer](https://spec.c2pa.org/conformance-explorer/) for the current readable trust-list view.\n- [C2PA public trust-list repository](https://github.com/c2pa-org/conformance-public/tree/main/trust-list) for the PEM trust-list files.\n\nCertificate authorities listed by the CAI docs include:\n\n- [DigiCert C2PA Media Trust](https://www.digicert.com/solutions/c2pa-media-trust)\n- [SSL.com C2PA Enterprise Content Authenticity Solutions](https://www.ssl.com/article/c2pa-enterprise-content-authenticity-solutions/)\n- [Tauth Labs](https://tauth.io/blog/tauth-labs-becomes-c2pa-certification-authority)\n- [Trufo Trust Certificate Authority](https://trufo.ai/tca)\n\nProvider availability, onboarding requirements, and assurance levels can change, so use the official C2PA trust-list sources above as the source of truth before issuing production credentials.\n\n### Development certificates\n\nThe bundled signer is only for local development and demos. It can prove that the package writes and signs a manifest, but it does not give your output a production identity that verifiers should trust.\n\nUse development/test credentials for:\n\n- Local CLI experiments.\n- Integration tests.\n- Demo assets where trust is not implied.\n\nUse production credentials for:\n\n- Public releases.\n- User-facing generated media.\n- Workflows where platforms or verifiers should recognize your organization as the signer.\n\n## Verifying Output\n\nAfter signing, inspect the output with a C2PA-compatible verifier such as the Content Authenticity Initiative Verify tooling or another C2PA reader. For PNG files, the embedded manifest appears in a `caBX` chunk and should include `c2pa.actions.v2` plus the `trainedAlgorithmicMedia` source type.\n\n## Development\n\n```sh\nnpm install\nnpm run build\nnpm run typecheck\nnode dist/cli.js --help\n```\n\nThe package is intentionally small. Most of the heavy lifting is delegated to `@contentauth/c2pa-node`; this project focuses on shaping a clear AI-generation manifest and giving applications a stable CLI/API around it.\n\n## License\n\nGPL-3.0-or-later\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Fsign-ai-media","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ff%2Fsign-ai-media","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ff%2Fsign-ai-media/lists"}