← Garchi CMSCONTENT HISTORYWHAT CHANGED · RULE-BASED ANALYSIS
Update to Garchi CMS
Snapshot Sep 30, 2026 · 22:55 UTC · version 4.0.0
Collection source: not recorded for this historical snapshot.
First saved snapshot
No earlier snapshot is available to establish a change.
Compare saved observations
Download comparison JSONFull technical diff · 0 changed fields
Full snapshot data
{
"name": "garchi-manage-content",
"description": "Operate content in Garchi CMS through the Garchi MCP server — pages and their section trees, section templates and props, data items, categories, item metadata, assets, languages and social posts. Use when the user asks to add or edit pages, change copy or images, build a page from templates, create blog posts or products, reorder or remove sections, add translations, update SEO metadata, or turn Garchi content into a LinkedIn or Instagram post for a person to approve. This is content operations, not code — for fetching and rendering content in an application use garchi-render-content.",
"included_files": [
{
"relative_path": "references/mcp-tools.md",
"size_in_bytes": 16925
},
{
"relative_path": "references/social-publishing.md",
"size_in_bytes": 9658
}
],
"skill_md_contents": "---\nname: garchi-manage-content\ndescription: Operate content in Garchi CMS through the Garchi MCP server — pages and their section trees, section templates and props, data items, categories, item metadata, assets, languages and social posts. Use when the user asks to add or edit pages, change copy or images, build a page from templates, create blog posts or products, reorder or remove sections, add translations, update SEO metadata, or turn Garchi content into a LinkedIn or Instagram post for a person to approve. This is content operations, not code — for fetching and rendering content in an application use garchi-render-content.\n---\n\n# Garchi CMS: operating content over MCP\n\nContent lives in the CMS. If the user wants different copy, a new page, a new\nblog post or a different image, that is an MCP operation and the application\ncode should not change at all.\n\nRequires the `garchi` MCP server. If its tools are unavailable, stop and ask the\nuser to authorize it. Do not substitute source edits for CMS edits.\n\n**Start every session by calling `get-garchi-cms-guide`.** It is free,\nread-only, takes no arguments, and returns the current content model and field\nrules straight from the server. It is more current than this file. Read it\nbefore planning any write.\n\n## The one thing to understand: ids flow between calls\n\nAlmost every Garchi tool takes an id that a previous call returned. Nothing is\nderivable, nothing is guessable. Most failed Garchi sessions are an agent\ninventing an id instead of listing for it.\n\n```\nlist-space-tool ─────────► space_uid ──► needed by nearly every other tool\n │\n ┌────────────────────────┼────────────────────────┐\n ▼ ▼ ▼\nlist-section-template list-pages-tool list-categories-tool\n │ │ │\n │ section_template_id │ page_id │ category ids\n │ + prop template ids │ │\n ▼ ▼ ▼\ncreate-section-tool ──► get-page-tool ──► section ids create-data-item-tool\n │ (mode=draft) │ │\n └──────────┬──────────────────────────────┘ ▼\n ▼ create-meta-for-item\n upsert-section-content-tool\n (needs page_id + section_id + prop template ids)\n```\n\nTwo id traps worth knowing:\n\n- `get-page-tool` takes a **`slug`** (`/`, `/about`), not a page id. But\n `upsert-section-content-tool`, `delete-section-tool` and the rank tools take a\n **`page_id`**. Get the id from `list-pages-tool` and the section ids from\n `get-page-tool`.\n- `get-data-item-tool`, `update-data-item-tool` and `create-meta-for-item-tool`\n take a numeric **`item_id`**, not the slug.\n\n## Working rules\n\n1. **Orient before writing.** `list-space-tool` first. It returns each space's\n `space_uid`, its `agent_description`, per-type content counts and, when set,\n the front-end URL — enough to tell which space the user means and what\n already exists, without further calls.\n2. **Read before you edit.** `get-page-tool` with `mode=draft` (or\n `get-data-item-tool`) to see current values and ids before changing them.\n3. **Verify after you write.** A success message confirms the call ran, not that\n the result is what the user wanted. Re-read and check the values landed.\n4. **One upsert, all the props.** `upsert-section-content-tool` accepts an array\n of props. Fill a whole section in one call rather than one call per field.\n5. **Don't re-list what you already have.** Template lists, asset lists and\n category lists are stable within a task. Fetch once, reuse. In particular,\n `list-assets-tool` returns the entire asset list in one response — never loop\n over it.\n6. **Match the code to the content.** A section template's props become a\n component's props. When creating a template for an existing component, read\n the component first and mirror its props. When the component does not exist\n yet, say so — `garchi-render-content` builds it.\n\n## Filling a section: the prop value contract\n\n`upsert-section-content-tool` merges by prop template id. Props you send are\nwritten; props you omit are left untouched. Send only what changes.\n\nThat is the contract for every Garchi write, not just this one: **only what you\nprovide changes.** A field or prop sent as `null` or `\"\"` means \"empty this\"; one\nyou leave out keeps its current value. So blanking a heading or removing an\nimage is an explicit empty value, never an omission.\n\nBecause of that, never pad a request with nulls for arguments you are not\nsetting — send the fields that change and nothing else. The fields a record\ncannot live without (a data item's `name`, `slug`, `detail_description` and\n`categories`; a page's `title`, `description` and `path`) reject an empty value\noutright, so a null-padded request fails rather than wiping content.\n\nEach entry in `props` needs the prop template `id` plus **either** `value`\n**or** `asset_id`, decided by the prop's type:\n\n| Prop type | What to send |\n| --- | --- |\n| `media` | `asset_id` from `list-assets-tool`, in the same space. `value` is ignored. Send `asset_id: null` to remove the current image. |\n| `select` | `value`, and it must be one of that prop's `allowed_values`. |\n| `text`, `longtext`, `richtext`, `date` | `value` as a string. Send `\"\"` to blank it. |\n| `icon_lucid`, `icon_hero` | `value` = an icon name from that icon library. |\n\nSending `asset_id` for a non-media prop is rejected, and so is omitting it for a\nmedia prop. Prop keys are lowercase snake_case.\n\nPass `language_id` to write a translated value for a space language other than\nthe default.\n\n## Sequences that work\n\n**Build a page**\n1. `list-space-tool` → `space_uid`\n2. `list-section-template-tool` → template ids, prop ids, prop types,\n `allowed_values`. If the space has no templates, `create-section-template-tool`\n first.\n3. `create-page-tool` → the shell only: `title`, `path`, `description`\n (the meta description), optional `json_ld` for structured data.\n4. `create-section-tool` per section — or `create-nested-section-tool` with a\n `parent_id` to place one inside another.\n5. `upsert-section-content-tool` per section, all props at once.\n6. `get-page-tool` with `mode=draft` → verify.\n\n**Edit page content**\n`list-pages-tool` → `get-page-tool` (`mode=draft`) → `upsert-section-content-tool`\nwith just the changed props → `get-page-tool` again.\n\n**Reorder** — `change-section-rank-tool` with `new_index` for top-level\nsections, `change-nested-section-rank-tool` (plus `parent_id`) for children.\nThis is what \"move that section up\" means; it is not a delete-and-recreate.\n\n**Create a data item**\n1. `list-categories-tool` → category ids (`manage-category-tool` with\n `action: create` if needed). An item needs at least one.\n2. `list-item-meta-tool` → what keys and types similar items already use.\n3. `create-data-item-tool` → `name`, unique `slug`, `categories`,\n `detail_description` (the HTML body), optional `one_liner` (a one line\n summary, max 1000 chars), optional `scheduled_for_datetime`, and `price`\n (decimals allowed) / `stock` / `sku` only for sellable items. `sku` is unique\n within the space.\n4. `create-meta-for-item-tool` per extra field, reusing the keys and types from\n step 2.\n5. `get-data-item-tool` → verify. The result carries `published`, which will be\n false.\n6. Tell the user the item is a draft and needs publishing in the dashboard.\n\n**Images** — two different systems, do not mix them:\n- *Page sections* use space assets. `list-assets-tool` to find one,\n `upload-asset-tool` to add one, then set the `media` prop by `asset_id`. The\n asset must belong to the same space; an id from another space is rejected.\n- *Data items* take images **inline as base64 data URIs** on the item itself,\n first image being the featured one — `png`, `jpg`, `jpeg`, `webp` or\n `svg+xml`, max 10 MB each. Data items never use space assets.\n- `generate-image-tool` covers both: `image_for: page` returns an `asset_id` to\n use in a section prop; `image_for: data_item` needs a `data_item_id` and sets\n that item's main image directly.\n\nFor `upload-asset-tool`, `file_type` must be an allowed MIME type and the\n`file_name` extension has to match it. Omitting the file content opens a browser\nupload window for the user and returns a signed upload link — that is the right\npath for anything but small files, rather than pushing large base64 through the\nconversation. Uploads are rate-limited; if you hit that, wait rather than retry\nin a loop.\n\n## Social posts: you draft, a person publishes\n\nA space can connect social channels (LinkedIn, and Instagram where it is\navailable to that account) in the Garchi dashboard. Over MCP you can read those\nchannels, draft posts from Garchi content, revise them and hand them to a person\nfor approval. **That is where your part ends.**\n\nThe six tools: `list-social-channels-tool`, `create-social-post-tool`,\n`update-social-post-tool`, `get-social-post-tool`, `list-social-posts-tool` and\n`request-social-post-approval-tool`.\n\n**Only a person, in the dashboard, can** approve a post, publish it, schedule or\nreschedule it, cancel it or withdraw its approval, retry a failed publish, edit a\npost that is already live on the network, delete a live post, or connect and\nreconnect a channel. No tool does any of these, and asking for one will not\nproduce one. Do not suggest workarounds.\n\n**Turn a page or item into a post**\n1. `get-page-tool` (`mode=draft`) or `get-data-item-tool` — read the source.\n2. `list-social-channels-tool` → `channel_id`s. Skip a channel with\n `usable: false` and tell the user it needs reconnecting.\n3. Write copy suited to each network yourself.\n4. `create-social-post-tool` with `body`, `channel_ids`, optional `media`, and\n `source_type`/`source_id` pointing at what it was written from.\n5. `request-social-post-approval-tool`. This checks the post against every\n selected network's rules; an error names the channel and the problem. Fix it\n with `update-social-post-tool` and ask again.\n6. Tell the user the post is waiting for their approval in the dashboard. Stop.\n\nRules that matter:\n\n- **Media is referenced, never uploaded.** `media` entries are\n `{\"source\": \"space_asset\", \"id\": \"<asset id>\"}` from `list-assets-tool`, or\n `{\"source\": \"data_item_image\", \"id\": \"<item id>\"}` for an item's feature\n image. No URLs.\n- **A post has text only, images, or exactly one video** — never both. Attaching\n a video removes the other media; attaching an image removes a video.\n- **Video must already be a space asset** (`type: uploaded-video`).\n `upload-asset-tool` does not accept video, so ask the user to upload it in the\n dashboard. LinkedIn takes MP4; Instagram takes MP4 or MOV as a Reel; 500 MB\n maximum. Garchi checks the file type and size, not codecs or duration, and\n never converts video — the network can still reject a file after approval.\n- **Editing an approved or scheduled post withdraws its approval.** It returns to\n `pending_approval`. Say so whenever you edit one.\n- **Publishing spends the space's credits**: one per successful publish to one\n channel, so a post to LinkedIn and Instagram uses two. Failed and cancelled\n publishes use none; deleting a published post gives none back. Every social\n tool returns `publishing_allowance`. When `can_publish_more` is false you may\n still draft, but tell the user it cannot publish until they upgrade.\n\nTool details, network rules and worked examples:\n[social-publishing.md](./references/social-publishing.md).\n\n## Leave notes for the next agent\n\nSpaces, pages, section templates, data items and assets each accept an\n`agent_description` — a field meant for agents, not visitors. Use it to record\nwhat a template is for, when a page should be used, or what an asset shows. It\ncosts one field on a write you are already making and it is what a later session\nreads instead of guessing. Fill it in whenever you create something.\n\n## Draft, live, and what MCP cannot do\n\n**You write drafts. A human publishes.** Nothing here reaches the live site on\nits own, and that review step is the point: the user sees the change before\ntheir visitors do.\n\n**Pages.** Every content write puts the page back into draft. Verify with\n`mode=draft`. `mode=live` keeps serving the last published version, so the site\nnever shows a half-finished edit — and your change is not visible until the\nowner publishes again. A page that has never been published returns \"no\npublished version\" on `live`. Rendering drafts in an application needs a preview\ntoken — see `garchi-render-content`.\n\n**Data items.** New and updated items are drafts (`published: false`), and the\ncontent API serves published items only, so a fresh item is not on the site yet.\nThe exception is `scheduled_for_datetime` (`Y-m-d H:i`, in the future): the item\nstays a draft until that time, then Garchi publishes it automatically.\n\n**End every content task by saying what you changed and that the user needs to\npublish it in the dashboard.** Reading your work back over MCP shows drafts, so\na clean verification is not evidence that anything is live.\n\nSeveral things are deliberately outside this server. Tell the user to do them in\nthe Garchi dashboard rather than looking for a tool:\n\n- **Creating a space.** No tool creates one.\n- **Publishing a page or a data item.** Both go live only when the owner\n publishes them in the dashboard.\n- **Deleting pages, data items, categories or section templates.**\n `delete-section-tool` is the only delete here, and `manage-category-tool` only\n creates and updates.\n- **Anything past requesting approval for a social post**: approving,\n scheduling, publishing, cancelling, retrying, editing or deleting a live post,\n and connecting a channel.\n\n## Before a change that is hard to undo\n\nTwo tools change or remove content that other content depends on:\n\n- **`delete-section-tool`** removes a section, every nested section under it, and\n all their prop values. If the page is published, the section stops appearing on\n the live site.\n- **`update-prop-template-tool`** changes a prop's `key` or `type` on a template\n that may be used by many sections across many pages. Existing values can become\n invalid for the new type, and published pages reflect the change. Renaming a\n key also breaks the matching component prop in the codebase until that is\n updated too.\n\nFor either one:\n\n1. Read first — `get-page-tool` (`mode=draft`) or `list-section-template-tool` —\n so you are acting on the right target.\n2. Name the exact page and section, or the exact template and prop, and get an\n explicit yes. \"Tidy up this page\" is not approval to delete anything.\n3. Confirm one item at a time. For a batch, show the full list first.\n4. For a prop change, check what the change breaks on the rendering side and say\n so before making it.\n\nGarchi keeps automatic restore points for recent page, section-template and data\nitem changes, restorable from the content history in the dashboard. Treat that\nas a safety net for the user, not a licence to act without asking: the window is\nlimited, and **no MCP tool restores anything** — from here every one of these\nchanges is final.\n\n## Costs and plan limits\n\n`generate-image-tool` spends part of the account's monthly AI image allowance,\nshared across all of the user's spaces. Ask before generating, keep the prompt\nunder 200 words, describe subject, style, colour and composition, leave a clear\nzone where text will overlay, and do not ask for text inside the image.\n\nCreating pages, data items, categories and generated images is capped by the\nuser's subscription plan. When a tool reports a limit reached or no active\nsubscription, **stop** — that is a billing state, not a transient failure.\nRetrying it burns calls and changes nothing. Report which limit was hit and what\nwas created before it.\n\nSocial publishing credits are counted per space: 2 on Sandbox, 300 on Basic,\nunlimited on Pro, unlimited or custom on Business. Drafting and requesting\napproval never spend them — only a successful publish does, and a person starts\nthat. Read `publishing_allowance` rather than assuming a plan.\n\n## Stop conditions\n\n- Never retry a failing call more than twice. Re-read the state, then report.\n- A validation error names the exact field and rule. Fix that field; do not\n resend the same payload hoping for a different outcome.\n- If an id is missing, list for it. Never guess one.\n- Tool calls are recorded against the user's account, so loops are not free.\n\n## Reference\n\n- [mcp-tools.md](./references/mcp-tools.md) — full tool inventory, arguments,\n and safety annotations\n- [social-publishing.md](./references/social-publishing.md) — social post tools,\n network rules, the approval boundary and worked examples\n- `get-garchi-cms-guide` — the live content model from the server\n- Content model background:\n [../garchi-render-content/references/garchi-cms-doc.md](../garchi-render-content/references/garchi-cms-doc.md)\n or <https://garchi.co.uk/documentation>\n"
}SHA-256: 6c2c69192e2f6fa5e0fe52e48ceedd4502b5d7e406a4205d85d6dd8bfc71b610