Create an app or accept an ESM app build

Existing-contract callers receive a published app synchronously; anonymous creation returns a chrm_app_* token and may request pair: true. The explicit https://charm.ing/schema/app-manifest/next.json contract requires an enabled authenticated user and Idempotency-Key, validates imports without evaluation, and returns 202 before dependency resolution or compilation. A same-owner manifest.id target is frozen at acceptance; an absent target cannot later become an overwrite. Use PUT for a known app. Every existing ESM destination requires its desired revision in If-Match; migration also requires migrate_contract: true. pair and label are not ESM fields.

post/app

Request

  • Base URL: https://charm.ing
  • URL: https://charm.ing/app
  • Auth: one of:
    • none
    • HTTP bearer

Headers

Idempotency-Keystring

Required for ESM saves. Reuse the same key, body, target and If-Match after response loss; a changed request with that key returns idempotency_conflict. Use a fresh key for each intentional save.

If-Matchstring

Desired-source revision in double quotes for an ESM upsert or migration. Read GET /app/{id}/source first.

Request body

modulestring required

Server ES module source. Must export a literal canonical manifest and a routes array. A route handler returns exactly the value declared by outputSchema; for outputSchema: { type: "array", items: ... }, return the array directly. Charming adds the HTTP transport envelope, so do not add { ok, value } or { value } unless those fields belong to outputSchema itself. default.fetch is an optional unmatched-request fallback; when absent, Charming supplies a generic 404 handler. Existing contracts publish synchronously; the explicit https://charm.ing/schema/app-manifest/next.json contract requires an enabled authenticated user and accepts a background build.

uistring nullable

Optional browser source populating #app. A classic script for the existing contract; an ES module for the explicit ESM contract. ESM bare imports must match manifest.dependencies.client.

stylesstring nullable

Optional CSS injected alongside ui.

descriptionstring nullable

Optional app description, shown to the owner and to callers who read it back. For ESM POST upserts, omission preserves the desired description.

migrate_contractboolean

ESM POST only: true explicitly migrates an existing same-owner manifest.id target. Supply its desired revision in If-Match. The existing app remains active until the build publishes.

pairboolean

Existing-contract anonymous POST only; rejected on ESM saves. Silently ignored on existing-contract authenticated upserts. When true, server mints a bound device_code alongside the app token; claiming the app approves the pairing, and approving the pairing code at /pair claims the app, so either gesture gives the agent a chrm_user_* for the claimed app.

labelstring

Existing-contract anonymous POST only; rejected on ESM saves. Silently ignored on existing-contract authenticated upserts. Human-readable label for the agent, surfaced to the user on the /pair approval page when pair: true.

Response

App created or upserted.

idstring uuid required
manifestIdstring required
displayNamestring required
urlstring uri required
capabilitiesCapabilities required(unresolved $ref)
claimedboolean required
revisioninteger required

Server-owned app source revision. New apps start at 1, each successful source write advances it once, and historical null counters project as 0. If-Match: "<N>" and expected_revision carry this revision through its canonical concurrency grammar.

tokenstring

Anonymous-create only. chrm_app_* plaintext, returned exactly once — irrecoverable.

expiresAtstring date-time

Anonymous-create only. 7-day TTL unless claimed.

warningsstring[]

Non-blocking publish feedback (#1126), present only when static validation found UI/backend contract mismatches — e.g. the UI calls an operation this version does not expose. The write succeeded; fix by adding the backend op or renaming the UI call.

Changes

No recorded changes to this operation across all 1 revision of this API.