Skip to main content
Glama

Publish

publish
Destructive

Create an app from its files, or change one.

A change takes app_id and base_version (the version get_app_context or the last publish returned) and only the files and assets that changed. To change part of a file, send edits instead of the file: "edits": [{"path": "index.html", "find": "old text", "replace": "new text"}]. find must occur once, unless count says how many times, and a miss refuses the publish and says what it found. Without base_version a publish replaces every file. A stale base is refused, so someone else's change is reloaded rather than overwritten. An app is named by an app_id from a reply or list_apps, never found by name.

A create omits app_id and takes intent. Files are a single client-side page: index.html plus css/js, plain text, no build step, no server. Files with SKILL.md at the root and no index.html publish a skill, in one call with all its files. A picture, font or sound is an asset: listed in assets with its sha256 and byte count, and the reply says where to PUT its bytes before publishing again. Changes start from the files get_app_context returned, not the HTML at the app URL. Files carry literal angle brackets.

Every call takes work_context (goal, current_state, decisions, open_work, verification, known_issues; no credentials, transcripts, or stored records) and summary (one line of 200 characters or fewer, in the person's words). When work stops unpublished, checkpoint_app saves that context with the exact base_version.

An app that stores data uses window.cloche and declares collections in schema. get_deploy_instructions returns the runtime API, the purpose-built AI surface, the authoring rules, and the less common publishes: rename, reserve an address before the files exist, share or invite while creating, slug, icon.

A local folder with server code (Flask, Express, SQLite, login routes, database URLs) is rewritten into this shape before publishing. Its server is neither uploaded nor run, its credentials are dropped, and no auth is invented: window.cloche and schema replace them. A rewrite of any existing tool, including a browser localStorage app, keeps every persisted entity and field from the source store, including optional fields and nested groups such as folders, as schema collections and fields, and adds no feature the source lacked.

Data from a private or external source travels as data_publication with the files, never as rows in files or work_context: the collections and fields the app reads and the recipe of read-only tool calls that produces them. Its shape is the example get_deploy_instructions returns. Those collections are shared in schema, and the app reads them through window.cloche.data like stored ones.

Cloche runs the recipe for each person who opens the app with that person's own access to the source, so everyone sees what they can already see there. No model or generated code runs it. An owner's publish goes live; an editor's reading anything new waits for approval at the Data address this call returns, where the owner can keep a copy.

A changed source, argument, selection, collection, or field is a new publication: the files go again with the complete publication details.

The result's bundle_bytes is what the app's files now total, for checking the change. An app far smaller than before was sent truncated, not edited. get_app_context with version returns a past version. Its files published against the live base_version put a damaged live version back.

The result says what looks like personal data in the version and where, when the organization checks for it.

Files are live only when this call returns ready.

Input Schema

NameRequiredDescriptionDefault
iconNowhen creating: a Tabler icon name saying what the app is, e.g. list-check. An unknown name is read by its words, then the app name
nameNodisplay name; with app_id and no files: rename
roleNofor a grant share, user or editor; for a link, omit or user -- a link cannot be editor
slugNofull label on rename; creation adds the organization handle. Earlier names open until removed
editsNowith base_version, change part of a file without sending it whole
filesNothe app bundle's files, inline
shareNowhen creating: how to share it once live: "link", "public", or "grant" by subject_or_email; omit to keep it private
app_idNoomit to create; otherwise the app_id from a reply or list_apps
assetsNobinary files (images, fonts, audio, video) by path, sha256 and byte count; the reply says where to PUT the bytes before a second publish
intentNowhen creating: what the app is for, in the author's own words
schemaNocollections this app stores; needs files on create; omit for an app that stores nothing. A replace takes the whole schema again
answersNoreplies to open comments by comment_id, shown under each with this version
summaryNoone line of 200 characters or fewer, naming what this is or what changed, in the words the person would use for it
base_versionNothe version get_app_context or your last publish returned; files may then carry only what changed
organizationNowhen creating: destination organization id. Required when you belong to multiple organizations
work_contextYescompact continuation state for the next session: no credentials, transcripts, or stored app records
removed_pathsNopaths to delete from the version named by base_version
contract_versionNo
data_publicationNowith files: the collections and fields this app reads from a source, and the recipe of read-only tool calls that produces them; never rows
subject_or_emailNowho to invite when share is "grant": their email address, or their Cloche account id
development_tokenNo

Output Schema

NameRequiredDescriptionDefault
urlYesthe app's own URL, a Template's page in Cloche, or a skill's page until it is public. The app stays private unless you shared it
kindNo"app" or "skill": what this publish put live
nameNo
app_idNo
reasonNoset when status is "failed" with what stopped the publish, "awaiting_upload" with the next step to finish the upload or "waiting" with who decides
statusNo"ready" when the files are live, "failed" when nothing went live, "reserved" when this call only took the address and there are no files yet, "awaiting_upload" when this call went no further than naming the bytes it needs -- nothing is live, "waiting" when the files are stored and an approver must decide before they go live
answersNorecorded ids, ignored ids (no open comment of this app has the id, or the answer was blank or repeated) and unsaved ids (a server problem kept the answer from being saved, so send it again)
uploadsNoset when status is awaiting_upload: a signed url per asset that takes its raw bytes by PUT. The same publish arguments sent again then complete it
versionNothe version this publish put live, and the base_version of the next change to this app
data_urlNowhere the owner keeps a copy, and approves a data update that waits
deploy_idNo
share_urlNothe link people open, when share was "link"; the app's own URL stays private
access_noteNoset on every publish while the app is private with nobody invited and no link, so only its owner can open it, and on every skill publish with who can install it; this result's own message already says it
asset_bytesNowhat this app's assets total now, against asset_cap_bytes
bundle_bytesNowhat this app's files total now, against bundle_cap_bytes
personal_dataNowhat looks like personal data in this version, as a count, a kind and a place such as "3 email addresses in index.html", then each file that was not checked. It holds no value
asset_cap_bytesNo
continue_promptNousually absent today; when present, a short message the person can paste into any agent to keep working
bundle_cap_bytesNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changed
    • changedInput schema / properties / organization / description
      Previous value: -"when creating: which organization to create it in; omit to use your personal one"New value: +"when creating: destination organization id. Required when you belong to multiple organizations"
  2. Changed1 schema field changed
    • addedOutput schema / properties / personal_data
      Added value: +{
      +  "description": "what looks like personal data in this version, as a count, a kind and a place such as \"3 email addresses in index.html\", then each file that was not checked. It holds no value",
      +  "items": {
      +    "type": "string"
      +  },
      +  "type": [
      +    "null",
      +    "array"
      +  ]
      +}
  3. Changed1 schema field changed
    • changedOutput schema / properties / url / description
      Previous value: -"the app's own URL, or a skill's page in Cloche until the skill is public. It stays private unless you shared it"New value: +"the app's own URL, a Template's page in Cloche, or a skill's page until it is public. The app stays private unless you shared it"
  4. Changed3 schema fields changed
    • changedInput schema / properties / schema / properties / collections / items / properties / access / description
      Previous value: -"omit or \"shared\" so everyone sees the same rows; \"private\" so each signed-in person keeps their own list"New value: +"omit or \"shared\" so everyone sees the same rows; \"private\" so each signed-in person keeps their own list; \"assigned\" so a user sees rows assigned to them and owners and editors all"
    • changedInput schema / properties / schema / properties / collections / items / properties / access / enum
      Previous value: -[
      -  "private",
      -  "shared"
      -]New value: +[
      +  "private",
      +  "shared",
      +  "assigned"
      +]
    • addedInput schema / properties / schema / properties / collections / items / properties / assigned_to
      Added value: +{
      +  "description": "assigned only: the text field holding a person's id",
      +  "type": "string"
      +}
  5. Changed4 schema fields changed
    • addedInput schema / properties / answers
      Added value: +{
      +  "description": "replies to open comments by comment_id, shown under each with this version",
      +  "items": {
      +    "additionalProperties": false,
      +    "properties": {
      +      "comment_id": {
      +        "type": "string"
      +      },
      +      "text": {
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "comment_id",
      +      "text"
      +    ],
      +    "type": "object"
      +  },
      +  "type": [
      +    "null",
      +    "array"
      +  ]
      +}
    • addedOutput schema / properties / answers
      Added value: +{
      +  "additionalProperties": false,
      +  "description": "recorded ids, ignored ids (no open comment of this app has the id, or the answer was blank or repeated) and unsaved ids (a server problem kept the answer from being saved, so send it again)",
      +  "properties": {
      +    "ignored": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": [
      +        "null",
      +        "array"
      +      ]
      +    },
      +    "recorded": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": [
      +        "null",
      +        "array"
      +      ]
      +    },
      +    "unsaved": {
      +      "items": {
      +        "type": "string"
      +      },
      +      "type": [
      +        "null",
      +        "array"
      +      ]
      +    }
      +  },
      +  "required": [
      +    "recorded",
      +    "ignored"
      +  ],
      +  "type": [
      +    "null",
      +    "object"
      +  ]
      +}
    • changedOutput schema / properties / reason / description
      Previous value: -"set when status is \"failed\" with what stopped the publish or \"awaiting_upload\" with the next step to finish the upload"New value: +"set when status is \"failed\" with what stopped the publish, \"awaiting_upload\" with the next step to finish the upload or \"waiting\" with who decides"
    • changedOutput schema / properties / status / description
      Previous value: -"\"ready\" when the files are live, \"failed\" when nothing went live, \"reserved\" when this call only took the address and there are no files yet, \"awaiting_upload\" when this call went no further than naming the bytes it needs -- nothing is live"New value: +"\"ready\" when the files are live, \"failed\" when nothing went live, \"reserved\" when this call only took the address and there are no files yet, \"awaiting_upload\" when this call went no further than naming the bytes it needs -- nothing is live, \"waiting\" when the files are stored and an approver must decide before they go live"
  6. Changed3 schema fields changed
    • changedOutput schema / properties / access_note / description
      Previous value: -"set on every publish while the app is private with nobody invited and no link, so only its owner can open it; this result's own message already says it"New value: +"set on every publish while the app is private with nobody invited and no link, so only its owner can open it, and on every skill publish with who can install it; this result's own message already says it"
    • addedOutput schema / properties / kind
      Added value: +{
      +  "description": "\"app\" or \"skill\": what this publish put live",
      +  "type": "string"
      +}
    • changedOutput schema / properties / url / description
      Previous value: -"the app's own URL; it stays private unless you shared it"New value: +"the app's own URL, or a skill's page in Cloche until the skill is public. It stays private unless you shared it"
  7. Changed3 schema fields changed
    • addedInput schema / properties / data_publication / properties / recipe / properties / snapshot / additionalProperties / properties / cells
      Added value: +{
      +  "description": "With columns: path on a row to its values, like $.f.",
      +  "type": "string"
      +}
    • addedInput schema / properties / data_publication / properties / recipe / properties / snapshot / additionalProperties / properties / columns
      Added value: +{
      +  "description": "When rows are lists of values: path to the column names, like $.schema.fields[*].name. Fields then name columns.",
      +  "type": "string"
      +}
    • addedInput schema / properties / data_publication / properties / recipe / properties / snapshot / additionalProperties / properties / value
      Added value: +{
      +  "description": "With columns: path on each value, like $.v.",
      +  "type": "string"
      +}
  8. Changed1 schema field changed
    • changedInput schema / properties / slug / description
      Previous value: -"Latin URL words before the handle. On an existing app, moves its address and the old one redirects"New value: +"full label on rename; creation adds the organization handle. Earlier names open until removed"
  9. Changed1 schema field changed
    • changedInput schema / properties / icon / description
      Previous value: -"when creating: a Tabler icon name saying what the app is, e.g. list-check; a name Cloche does not carry falls back to its own mark"New value: +"when creating: a Tabler icon name saying what the app is, e.g. list-check. An unknown name is read by its words, then the app name"
  10. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations declare destructiveHint=true, readOnly=false, idempotent=false, and the description corroborates with specifics an agent needs: a stale base is refused, a `find` miss refuses the publish, an unbased publish replaces every file, an editor's publish waits for owner approval at the Data address, personal-data detection is reported, and 'Files are live only when this call returns `ready`.' That is substantial context beyond what the annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded correctly: the create-vs-change contract leads, then edits, assets, work_context, data publications, and finally the `bundle_bytes`/`ready` verification cues. It is dense and topic-organised, but several sentences are elliptical to the point of ambiguity ('Files carry literal angle brackets.', 'A changed source, argument, selection, collection, or field is a new publication') and some material duplicates what `get_deploy_instructions` is said to return.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 21-parameter, deeply nested tool with an output schema, this covers create, incremental update, edits, assets, skills, schema/storage, data publication, approval flow, and version recovery — enough to act correctly. Minor gaps remain: `contract_version` and `development_token` are never mentioned, and the relationship between `edits` and `files` in a single call is left implicit.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

With 90% schema coverage the baseline would be 3, but the description adds real semantics the schema cannot: the provenance rule for `base_version`, the find-once-unless-`count` rule for `edits`, the two-call asset flow (declare sha256/bytes, then PUT bytes before republishing), what `data_publication` must never contain (rows), and the constraint that `work_context`/`summary` carry no credentials or stored records. That materially changes how an agent fills these fields.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a specific verb and resource pair — 'Create an app from its files, or change one' — and immediately distinguishes both modes by which parameters select them (omit `app_id` vs supply `app_id` + `base_version`). It also names the siblings it is not (`get_app_context`, `list_apps`, `checkpoint_app`, `get_deploy_instructions`), so an agent can route correctly without opening other schemas.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly states when to create vs. change, when to use `edits` instead of whole files, when `base_version` is required and what happens without it, and where to go for the less common publishes ('`get_deploy_instructions` returns ... the less common publishes: rename, reserve an address ...'). It also routes the agent to `checkpoint_app` when work stops unpublished and to `get_app_context` with `version` for past versions — genuine when/when-not/alternative guidance throughout.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.