# Resource Revisions mcpctl keeps an append-only revision log for every Prompt and Skill — so you can answer "who changed prompt X and when," diff between any two versions, and restore an earlier state without losing the audit chain. ## Model `ResourceRevision` is a single shared table keyed by `(resourceType, resourceId)` — the type discriminator allows the same infrastructure to cover both prompts and skills (and any future resource that wants version history). | Field | Purpose | |------------------|----------------------------------------------------------| | `id` | cuid; the revision's stable identity. | | `resourceType` | `'prompt'` \| `'skill'`. Validated app-layer. | | `resourceId` | Soft FK — survives deletion of the underlying resource. | | `semver` | Author-visible version (X.Y.Z). | | `contentHash` | sha256 of the canonicalised body. Stable diff key. | | `body` | Snapshot of the resource at this revision. | | `authorUserId` | Who made the change (null for system writes). | | `authorSessionId`| Session that proposed it (when applicable). | | `note` | Free-text reviewer or author note. | | `createdAt` | When the revision was recorded. | The resource row itself (Prompt/Skill) keeps the inline `content` — revisions are an audit log, not the source of truth. Hot read paths (the gate plugin, `mcpctl skills sync`, prompt indexing) never need to consult the revision log. `Prompt.currentRevisionId` and `Skill.currentRevisionId` are soft pointers to the latest revision so the UI can answer "which version is live" in one query. ## Semver semantics Auto-patch on every successful save where the body changed: ``` 0.1.0 → save with content change → 0.1.1 0.1.1 → save with content change → 0.1.2 ``` Authors can override: ```bash mcpctl edit prompt foo --bump minor # 0.1.x → 0.2.0 mcpctl edit prompt foo --bump major # 0.x.x → 1.0.0 mcpctl edit prompt foo --semver 1.2.3 # explicit mcpctl edit prompt foo --note "fixed the gotcha" # adds note to revision ``` Invalid semver values fall back to `0.1.0` rather than throwing — the revision write is best-effort and we don't want a corrupted existing semver to break the prompt save. ## contentHash sha256 of the JSON-canonicalised body (keys sorted at every object level). Two revisions with the same hash are byte-identical. Used by `mcpctl skills sync` as the diff key against on-disk state — re-publish under the same semver still triggers a sync if the contentHash changed. The server-side hash and the client-side hash are computed from the same canonical shape, so they match exactly. See `src/mcpd/src/services/resource-revision.service.ts` for the canonical JSON encoder. ## CLI ### View history ```bash mcpctl get revisions prompt my-prompt mcpctl get revisions skill demo-skill ``` ### View one ```bash mcpctl describe revision ``` ### Diff The HTTP API returns a unified-format diff: ``` GET /api/v1/revisions//diff?against= ``` The web UI's revision history tab on a Skill detail page renders the diff inline (color-coded add/remove rows). ### Restore Restore a prompt or skill to an earlier revision. This writes a *new* revision whose body is the old one — preserving the audit chain rather than deleting later revisions. ```bash mcpctl restore prompt my-prompt --revision ``` The CLI subcommand is wired through to `POST /api/v1/prompts/:id/restore-revision` (and the symmetric `/api/v1/skills/:id/restore-revision`). ## RBAC Revisions piggyback on the underlying resource's RBAC permission. If you can `view:prompts`, you can read prompt history; if you can `edit:prompts`, you can restore. ## Audit emission Each revision write emits a structured audit event captured by the existing audit-event pipeline. The event includes the revision id, contentHash, semver, and author/session — sufficient to answer "what changed" and "who" without joining tables manually. ## Storage size A revision body is the resource snapshot — for prompts that's a few KB; for skills with large `files` maps it can be tens of KB. The audit log grows linearly with edits. v1 has no rotation; if a single resource sees thousands of revisions per day this will need a retention policy (out of scope today).