# "For agents: Myna in one page" > A dense operating manual for agents working against a Myna project, suitable for pasting into AGENTS.md or CLAUDE.md. Myna is a platform of [products](/concepts/products) a project enables: - **Content** — schemas are code, all writes create draft revisions grouped into [change sets](/concepts/change-sets), and publishing is a separate, human-gated atomic operation. You draft, validate, and preview; a human reviews field-level diffs and publishes. - **Analytics** — page views and custom events, with sessions, funnels, and the [joins to content and reports](/concepts/analytics). You read; the only thing you write is what an event *means*. - **Feedback** — bug reports and QA findings on [boards](/concepts/reports), with an append-only timeline. You read, reproduce, reply, and resolve. The three are the point. Content is what the product says, Analytics is what people did, Feedback is what they said — and because they share a project, "why did signups drop this week" is a sequence of calls rather than a research project. A route or tool belonging to a product the project does not run answers [`PRODUCT_NOT_ENABLED`](/errors/product-not-enabled) — a `404`. Do not retry it with different arguments. ## Credentials - API keys are bearer tokens with the prefix `myna_sk_`. Send `Authorization: Bearer $MYNA_TOKEN`. - SDK/CLI/MCP all read `MYNA_TOKEN`; the [MCP server](/mcp/setup) also reads `MYNA_PROJECT`, `MYNA_ORGANIZATION`, and `MYNA_API_URL` (default `https://api.myna.sh`). - Your key is typically scoped `content:read`, `content:write`, `assets:read`, `assets:write`, `preview:write`, `schema:read`, plus `feedback:read`, `feedback:write`, and `analytics:read` — and deliberately **not** `content:publish`. See [scopes](/platform/scopes). - `project:admin` never widens to a product added later. A key that should reach every product needs `admin:all` by name. ## The golden rules 1. **Writes are drafts.** Creating or updating an entry never changes what is publicly served. 2. **Never publish without explicit human instruction.** Even if you hold `content:publish`, do not call publish unless the human asked for it in this task. 3. **Always create a preview.** End every writing task with one preview URL covering the whole change set, and hand it to the human. 4. **Include `changeSummary` on every write.** One sentence per change; reviewers read these like a commit log. 5. **Use `expectedRevisionId` when updating** an existing entry, so concurrent edits fail loudly (`STALE_REVISION`) instead of being clobbered. 6. Destructive MCP tools require `confirm: true`: `myna_delete_entry`, `myna_unpublish_entry`, `myna_publish_change_set`, `myna_schedule_change_set`, `myna_close_change_set`, `myna_restore_revision`, `myna_revert_release`, `myna_reorder_entries`. 7. **Read the guidance.** `myna_get_collection_schema` returns a `guidance` string when the collection has one — the project's house style for what you are about to write. Follow it; it is the part a schema cannot express. It also returns `policy`: the rules the collection *enforces*, which fail the `policy` check and block publishing if you break them. 8. **Check for company before writing.** `myna_get_entry` returns `openChangeSets` — anyone else already staging a change to this entry, and the fields they touch — plus `contendedFields` where more than one does. A collision found here is free; the same collision found by the `conflicts` check costs whatever you wrote first. ## Content: the loop MCP tool names (see the [tool reference](/mcp/tools)) with [CLI](/cli/overview) equivalents: 0. `myna_search_entries` — find the entry a human described in prose ("the pricing page") instead of listing a collection and scanning it. Full-text over every text field, draft or published. CLI: `$ myna entries search ""`. 1. `myna_get_collection_schema` — know the fields *and the guidance* before writing. CLI: `$ myna schema inspect `. 2. `myna_create_change_set` — one change set per task. Check `myna_list_change_sets` first if you may be resuming work. CLI: `$ myna changes create --title "..."`. 3. `myna_create_entry` / `myna_update_entry` — pass `changeSet`, `changeSummary`, and (on update) `expectedRevisionId`. On an update, `myna_get_entry` first: its `openChangeSets` says whether someone is already editing the fields you are about to touch. CLI: `$ myna entries create --set k=v --change-set chs_... --summary "..."` and `$ myna entries update / --set k=v --expected-revision rev_... --change-set chs_... --summary "..."`. 4. `myna_upload_asset` — base64 bytes or a local path. CLI: `$ myna assets upload `. 5. `myna_validate_change_set` — fix every reported error before previewing. CLI: `$ myna changes validate chs_...` (non-zero exit when invalid). 6. `myna_diff_change_set` — read back what you actually changed, field by field, and use it to write your summary. Long prose fields carry word-level `segments`, so a body you rewrote reads as the words that moved. CLI: `$ myna changes diff chs_...`. 7. `myna_create_preview` — exactly one of `changeSet` or `entry`; prefer the change set. CLI: `$ myna changes preview chs_...`. 8. **Stop.** Report the change set id and preview URL. Publishing (`myna_publish_change_set` with `confirm: true`; CLI `$ myna changes publish chs_... --confirm-publish`) is for humans or explicitly instructed, publish-scoped principals. It applies the whole change set in one transaction. Entries are addressed as `/` or by `ent_` id. Statuses: `draft`, `published`, `changed`, `unpublished`, `deleted`. If a task is cancelled, close your change set (`myna_close_change_set`) rather than leaving it open. Abandoned sets accumulate and every one of them looks to a human like work waiting for review. ## Beyond the loop - **Reuse assets.** `myna_list_assets` accepts a `checksum`; check before `myna_upload_asset` so the same logo does not land three times. If you upload anyway, the result's `similar` names existing images that look like the same picture — including resized or re-encoded copies a checksum cannot match. Reference one of those and delete your upload rather than leaving the library with two. `myna_update_asset` sets alt text, which the `policy` check requires wherever a collection declares `policy.altText()`. - **Bulk work.** `myna_import_entries` creates and updates many entries in one call, matched by slug, with `dryRun: true` to see what would happen first. Prefer it over a hundred single writes. - **Reviewing.** `myna_diff_change_set` plus `myna_get_change_set_review` is everything a reviewer sees. If the project declared an external check you can compute, report it with `myna_report_check_result`; a failing required check blocks publish, so do not report `passed` you did not verify. - **Translations.** `myna_translation_coverage` names exactly which entries and fields are missing a locale. ## Feedback: the loop The fourteen Feedback tools exist only when the project runs [Feedback](/concepts/reports). In the order they are usually needed: 1. `myna_report_digest` — what came in since a time or a release, counted and ordered by priority. One call rather than paging `myna_list_reports`. CLI: `$ myna feedback digest --since `. 2. `myna_get_report` — the description, the environment the application supplied, the board's guidance, every custom field, the whole timeline, and what evidence exists. CLI: `$ myna feedback reports open 42`. 3. `myna_get_report_attachment` — images come back as images you can look at. CLI: `$ myna feedback attachments get 42 rat_... --out shot.png`. 4. `myna_find_similar_reports` — check for a duplicate before spending a reproduction on one. 5. `myna_update_report` — status, priority, assignee, labels, title, body, in one call. 6. `myna_reply_to_report` — **`visibility` defaults to `internal`.** Pass `"public"` only when you mean to reach whoever filed the report. 7. `myna_resolve_report` — resolve, link the `commit` or `pullRequest`, and reply in one call. Set `requestRetest: true` when you could not reproduce the problem yourself: it asks the reporter to confirm rather than declaring the matter closed. `myna_request_retest` does the same for a report you are not resolving. Reports are addressed by per-project number, so `#42` works anywhere an id does. Statuses: `triage`, `open`, `in_progress`, `needs_retest`, `resolved`. The timeline is append-only — a resolution can be reopened and a merged duplicate keeps its own history, so nothing you do here destroys the record. Read the board's `guidance` the way you read a collection's: it is the house style for handling reports there, and reporters never see it. `myna_merge_report` marks a duplicate; nothing is deleted, so a wrong merge buries a distinct problem rather than losing it. `myna_move_report` moves a report to another board on the same project — every board is read by the same people, so that is filing, not publishing. **Blocking a reporter is not triage.** `myna_block_reporter` exists for abuse, not for somebody who reports too much. It stops them filing, reading their reports back, and being emailed. ## Analytics: answering "what changed" The ten Analytics tools exist only when the project runs [Analytics](/concepts/analytics). Read them in this order when somebody asks why a number moved. 1. **`myna_analytics_events` first, always.** It lists every event the project records *and what each one means*. Nothing in the data says whether `checkout_started` fires on the click or on the page, and a funnel built on the wrong assumption is confidently wrong. If an event you need is undescribed, describe it with `myna_describe_analytics_event` once you have worked out what it measures — that is a durable contribution, not a side effect. 2. `myna_analytics_overview` — the window, the previous window, and the change, in one call. Enough to say whether anything is different. 3. `myna_analytics_friction` — where people stop: exit pages, bounce pages, and the pages generating bug reports out of proportion to their traffic. The third list is the one to start from, because it names a page *and* tells you what people said about it. 4. `myna_analytics_breakdown` — narrow it. Any dimension, or `property:` for a custom property. `entry`, `collection`, and `release` group by Myna content. 5. `myna_analytics_funnel` — ordered, time-bounded conversion. Order is enforced, and `withinHours` runs from the visitor's first step. 6. `myna_analytics_release_impact` — the payoff. Give it a release number and it returns overall movement, per-entry movement for everything the release touched, per-event movement, and the reports filed since. It is **correlation**: say so when you report it. A release is not the only thing that happened that day. 7. `myna_analytics_entry` — one content entry: its numbers, every publication in the window, and what moved either side of each. 8. `myna_analytics_person` — one user's sessions, events, and reports together. When a report is hard to reproduce, the events before it are usually the steps the reporter did not write down. Every read takes the same filters and echoes back the window it resolved, so a number you quote can be reproduced. Name **either** `period` (`7d`, `30d`) **or** `from`/`to` — naming both is refused rather than guessed at. Then close the loop with the Content tools: a change set fixing what you found, validated and previewed, published by whoever holds `content:publish`. Myna collects the ground truth; the reasoning and the fix are yours. ## When a call fails `myna doctor --json` reports the CLI version, API reachability and compatibility, whether the credential is valid, which scopes the key carries, project access, and schema drift — each with a `status` and a `remedy`. Check it before retrying a failing call or reporting a broken setup. A denial can mean a missing scope or a missing resource. `myna auth verify --json` returns `credentialPresent` and `credentialValid` separately, so a stored-but-rejected credential is distinguishable from one that was never there. **After a 403 or 404, call `myna_explain_denial` once instead of retrying.** Pass the tool that failed (and the collection it touched, if any); it names which of three unrelated causes applies — the credential lacks the capability, the credential is confined to other collections, or the resource does not exist — and returns a `remedy`. Only the last is worth another attempt with different arguments; the first two are worth reporting to a human, because no retry will change them. CLI: `$ myna access --capability content:publish --collection posts` (exit code 1 when denied). ## Where to learn more - `https://docs.myna.sh/llms.txt` — index of all docs; `llms-full.txt` is the full concatenation. - Append `.md` to any docs URL for raw Markdown (e.g. `/concepts/change-sets.md`). - `https://docs.myna.sh/openapi.json` — OpenAPI 3.1 description of the HTTP API. ## Common errors | Code | HTTP | What to do | | --- | --- | --- | | `VALIDATION_FAILED` | 422 | Read the per-field errors, fix the offending fields, retry the write. | | `STALE_REVISION` | 409 | Someone else wrote first. Re-read the entry, merge, retry with the new `expectedRevisionId`. | | `PERMISSION_DENIED` (on publish) | 403 | Expected: your key lacks `content:publish`. Stop and ask the human to review the preview and publish. | | `PLAN_LIMIT_REACHED` | 402 | Stop and report; the organization's plan limit must be raised by a human. | | `PERMISSION_DENIED` (naming collections) | 403 | Your key is confined to specific collections. The message lists them; work within it and report the mismatch rather than trying another route. | | `CHECKS_FAILED` | 409 | A required check has not passed on the current contents. Fix what it reports, or report the check result if you are the one computing it. | | `PRODUCT_NOT_ENABLED` | 404 | The project does not run that product. `enabledProducts` lists what it does run. No retry helps; report it. | Every mutation you make is attributed (`created_by_type`, `created_by_id`) and every revision is immutable — you cannot destroy history, so prefer acting and reporting over asking about safe, draft-level operations.