Writing an msr.json manifest
Instructions for an AI agent asked to describe a software product as an
MSR JSON 2.0 manifest. MSR JSON is the machine-readable file a product publishes
about itself, the way robots.txt is the file a site publishes about crawling.
- Specification: https://msrjson.org
- JSON Schema: https://mysoftrank.com/schemas/msr-2.0.json
- A live example: https://mysoftrank.com/.well-known/msr.json
1. The one rule that matters
Never invent a fact. Every value in this file is a claim the publisher makes in public, and a registry, a crawler or a buying agent may act on it. If you do not have a value, leave the field out. An absent optional field is correct; a guessed one is a false claim.
This applies hardest to: version numbers, release dates, prices, licenses, SPDX identifiers, country codes and any URL. Do not derive a download URL from a pattern. Do not assume the license from the word "free". Do not write today's date as the release date because you do not know the real one.
If a required field is unknown, stop and ask the publisher for it. A manifest that cannot be written truthfully is not written.
2. Required structure
Five top-level keys are required: $schema, protocol, entity,
capabilities, releases.
protocol — fixed, never edited
Copy this block verbatim. It states facts about the specification, not about the product, and a manifest that alters it is not an MSR manifest.
{
"name": "MSR JSON",
"version": "2.0.0",
"author": "Antonio Santos",
"specification_license": "CC-BY-4.0",
"reference_implementation_license": "MIT"
}
protocol.canonical_url is optional: the public URL this very file is served
from.
entity — what the product is
| Field | Required | Notes |
|---|---|---|
name |
yes | The product name as the publisher writes it, version excluded |
slug |
yes | Lowercase ASCII, words joined by -, derived from name |
domain |
yes | Bare DNS name, no scheme and no path: acme.example |
type |
yes | One of the enum below |
descriptions |
yes | At least one locale, each with a summary |
license |
no | { "type": ..., "spdx_id": ... } |
vendor |
no | { "name", "website", "country_code", "support_url" } |
entity.type is one of: software, saas, ai-agent, mcp-server, api,
open-source, framework, library, plugin, extension, mobile.
entity.license.type is one of: open-source, freeware, freemium,
commercial, trial, subscription. Use spdx_id only for a real SPDX
identifier such as MIT or Apache-2.0.
descriptions is keyed by BCP 47 tag. summary is required and capped at 500
characters; tagline is capped at 120; text is unbounded prose. Write the
locales the publisher actually has. Do not machine-translate marketing copy into
locales the publisher never approved.
capabilities — how it is delivered
deployment is required and is an array of: cloud, self-hosted,
on-premise, hybrid, desktop, mobile, edge, docker.
pricing is optional: { "model": "free" }, or a starting price as integer
minor units plus an ISO 4217 code — { "starting_price_cents": 2900, "currency": "USD" }. Never write a price as a float or as a formatted string.
releases.latest — the current version
version and published_at are both required. published_at is an RFC 3339
timestamp in UTC. release_type is one of initial, major, minor, patch,
security. changelog_url and artifacts are optional; an artifact is
{ "platform", "uri", "sha256" } and the sha256 is a digest you have actually
been given, never one you compute a placeholder for.
3. A complete, valid example
{
"$schema": "https://msrjson.org/schemas/msr-2.0.json",
"protocol": {
"name": "MSR JSON",
"version": "2.0.0",
"author": "Antonio Santos",
"specification_license": "CC-BY-4.0",
"reference_implementation_license": "MIT",
"canonical_url": "https://acme.example/.well-known/msr.json"
},
"entity": {
"name": "Acme Notes",
"slug": "acme-notes",
"domain": "acme.example",
"type": "saas",
"license": { "type": "freemium" },
"vendor": {
"name": "Acme Labs",
"website": "https://acme.example",
"country_code": "BR",
"support_url": "https://acme.example/support"
},
"descriptions": {
"en": {
"tagline": "Shared notes that stay in sync",
"summary": "Acme Notes keeps a team's notes in sync across devices, with offline editing and per-workspace permissions.",
"text": "Longer prose about the product, its audience and what it does not do."
},
"pt-BR": {
"tagline": "Notas compartilhadas sempre em sincronia",
"summary": "O Acme Notes mantém as notas de um time sincronizadas entre dispositivos, com edição offline e permissões por workspace."
}
}
},
"capabilities": {
"deployment": ["cloud", "desktop"],
"pricing": { "model": "freemium", "starting_price_cents": 2900, "currency": "USD" }
},
"releases": {
"latest": {
"version": "4.2.0",
"published_at": "2026-09-14T00:00:00Z",
"release_type": "minor",
"changelog_url": "https://acme.example/changelog"
}
}
}
4. Checklist before you hand the file over
- Every required field is present:
$schema,protocol,entity,capabilities,releases.latest. - Every enum value is spelled exactly as the schema lists it — lowercase, with hyphens, not underscores.
- Every URL is absolute and
https. domainhas no scheme, no path and nowww.prefix.- Money is integer minor units plus a currency code. Dates are UTC.
- No field was filled with a guess. Anything unknown was left out or asked about.
- The file parses as JSON — no trailing commas, no comments.
5. Publishing and submitting
Serve the file at https://<domain>/.well-known/msr.json with
Content-Type: application/json. That path is where registries and agents look
for it without being told.
To list the product on MySoftRank, submit the public URL of the manifest at https://mysoftrank.com/publish. No account is required; the listing is queued for moderation. A product whose vendor is already claimed by an account must be updated from that account, not anonymously.
Legacy PAD XML is also accepted. POST /api/v1/convert/pad converts a PAD
document into an MSR draft, and POST /api/v1/validate/pad returns a
field-by-field verdict on one. A converted draft is a draft: the publisher
reviews it before it is published, because PAD carries no equivalent for several
MSR fields.
6. Using this file with your coding agent
This file is plain Markdown with no tool-specific syntax, so it works in any harness — Claude Code, OpenAI Codex, Cursor, Gemini CLI, Antigravity, GitHub Copilot, Qwen Code, a DeepSeek-backed agent, or your own loop. Put it where yours reads from:
| Harness | Where it looks |
|---|---|
| Codex, and any agent following the open convention | AGENTS.md at the repository root |
| Claude Code | CLAUDE.md, or a skill under .claude/skills/ |
| Cursor | .cursor/rules/ (it also reads AGENTS.md) |
| GitHub Copilot | .github/copilot-instructions.md |
| Gemini CLI | GEMINI.md |
| Antigravity | its own rules directory in the repository |
| Anything else — DeepSeek, Qwen, a local Ollama model, a custom harness | paste it into the system prompt |
Two ways to use it. Either commit it, so the agent has the rules whenever it touches your repository, or paste it once into a chat and ask for the manifest in that turn. Both work; committing it is what keeps the manifest correct on the next release, when the version and the date change and nobody remembers the rules.
Conventions move faster than this document. If your harness reads a path that is not listed here, the file still works there — nothing in it depends on the tool.