Agents
"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 a project enables:
- Content — schemas are code, all writes create draft revisions grouped into 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. You read; the only thing you write is what an event means.
- Feedback — bug reports and QA findings on boards, 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 — a 404. Do not retry it with different arguments.
Credentials
- API keys are bearer tokens with the prefix
myna_sk_. SendAuthorization: Bearer $MYNA_TOKEN. - SDK/CLI/MCP all read
MYNA_TOKEN; the MCP server also readsMYNA_PROJECT,MYNA_ORGANIZATION, andMYNA_API_URL(defaulthttps://api.myna.sh). - Your key is typically scoped
content:read,content:write,assets:read,assets:write,preview:write,schema:read, plusfeedback:read,feedback:write, andanalytics:read— and deliberately notcontent:publish. See scopes. project:adminnever widens to a product added later. A key that should reach every product needsadmin:allby name.
The golden rules
- Writes are drafts. Creating or updating an entry never changes what is publicly served.
- 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. - Always create a preview. End every writing task with one preview URL covering the whole change set, and hand it to the human.
- Include
changeSummaryon every write. One sentence per change; reviewers read these like a commit log. - Use
expectedRevisionIdwhen updating an existing entry, so concurrent edits fail loudly (STALE_REVISION) instead of being clobbered. - 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. - Read the guidance.
myna_get_collection_schemareturns aguidancestring 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 returnspolicy: the rules the collection enforces, which fail thepolicycheck and block publishing if you break them. - Check for company before writing.
myna_get_entryreturnsopenChangeSets— anyone else already staging a change to this entry, and the fields they touch — pluscontendedFieldswhere more than one does. A collision found here is free; the same collision found by theconflictscheck costs whatever you wrote first.
Content: the loop
MCP tool names (see the tool reference) with CLI equivalents:
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 "<words>".myna_get_collection_schema— know the fields and the guidance before writing. CLI:$ myna schema inspect <collection>.myna_create_change_set— one change set per task. Checkmyna_list_change_setsfirst if you may be resuming work. CLI:$ myna changes create --title "...".myna_create_entry/myna_update_entry— passchangeSet,changeSummary, and (on update)expectedRevisionId. On an update,myna_get_entryfirst: itsopenChangeSetssays whether someone is already editing the fields you are about to touch. CLI:$ myna entries create <collection> --set k=v --change-set chs_... --summary "..."and$ myna entries update <collection>/<slug> --set k=v --expected-revision rev_... --change-set chs_... --summary "...".myna_upload_asset— base64 bytes or a local path. CLI:$ myna assets upload <path>.myna_validate_change_set— fix every reported error before previewing. CLI:$ myna changes validate chs_...(non-zero exit when invalid).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-levelsegments, so a body you rewrote reads as the words that moved. CLI:$ myna changes diff chs_....myna_create_preview— exactly one ofchangeSetorentry; prefer the change set. CLI:$ myna changes preview chs_....- Stop. Report the change set id and preview URL. Publishing (
myna_publish_change_setwithconfirm: 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 <collection>/<slug> 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_assetsaccepts achecksum; check beforemyna_upload_assetso the same logo does not land three times. If you upload anyway, the result'ssimilarnames 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_assetsets alt text, which thepolicycheck requires wherever a collection declarespolicy.altText(). - Bulk work.
myna_import_entriescreates and updates many entries in one call, matched by slug, withdryRun: trueto see what would happen first. Prefer it over a hundred single writes. - Reviewing.
myna_diff_change_setplusmyna_get_change_set_reviewis everything a reviewer sees. If the project declared an external check you can compute, report it withmyna_report_check_result; a failing required check blocks publish, so do not reportpassedyou did not verify. - Translations.
myna_translation_coveragenames exactly which entries and fields are missing a locale.
Feedback: the loop
The fourteen Feedback tools exist only when the project runs Feedback. In the order they are usually needed:
myna_report_digest— what came in since a time or a release, counted and ordered by priority. One call rather than pagingmyna_list_reports. CLI:$ myna feedback digest --since <iso>.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.myna_get_report_attachment— images come back as images you can look at. CLI:$ myna feedback attachments get 42 rat_... --out shot.png.myna_find_similar_reports— check for a duplicate before spending a reproduction on one.myna_update_report— status, priority, assignee, labels, title, body, in one call.myna_reply_to_report—visibilitydefaults tointernal. Pass"public"only when you mean to reach whoever filed the report.myna_resolve_report— resolve, link thecommitorpullRequest, and reply in one call. SetrequestRetest: truewhen you could not reproduce the problem yourself: it asks the reporter to confirm rather than declaring the matter closed.myna_request_retestdoes 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. Read them in this order when somebody asks why a number moved.
myna_analytics_eventsfirst, always. It lists every event the project records and what each one means. Nothing in the data says whethercheckout_startedfires 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 withmyna_describe_analytics_eventonce you have worked out what it measures — that is a durable contribution, not a side effect.myna_analytics_overview— the window, the previous window, and the change, in one call. Enough to say whether anything is different.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.myna_analytics_breakdown— narrow it. Any dimension, orproperty:<key>for a custom property.entry,collection, andreleasegroup by Myna content.myna_analytics_funnel— ordered, time-bounded conversion. Order is enforced, andwithinHoursruns from the visitor's first step.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.myna_analytics_entry— one content entry: its numbers, every publication in the window, and what moved either side of each.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.txtis the full concatenation.- Append
.mdto 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.
