---
title: "Get an app's agent description without changing the app"
method: GET
path: "/app/{id}/agent.json"
---

# Get an app's agent description without changing the app

`GET /app/{id}/agent.json`

## Request

- Base URL: `https://charm.ing`
- URL: `https://charm.ing/app/{id}/agent.json`
- Auth: one of:
  - none
  - HTTP bearer
  - HTTP bearer

Side-effect-free sibling of the page gate: no auto-claim, no token mint, no cookie, no mutating telemetry. A public App or listed Template returns the full descriptor to anyone, with `operations[].input`/`output`/`examples` gated on `app:read` (owner, accepted share grant, team membership, or a bearer token) — an anonymous caller sees discovery-level operation fields only. An enabled-unlisted Template remains private without `app:read`, as does any other private App. Those callers — including an unclaimed app's claim-cookie holder, which grants `app:run` but never `app:read` — get the minimal stub (`AppDescriptorStub`). Reachable via both the `/app/{id}` UUID form and the `/{handle}/{app-name}` friendly form (byte-identical `id` + `canonical_url`), and advertised from the served page's `<link rel="alternate" type="application/json">` and matching `Link:` HTTP header.

## Response `200`

The full descriptor (manifest, operations, http_api, mcp, auth) or, for an unauthorized caller on a private app, the minimal `AppDescriptorStub`.

- union
  - AppDescriptor
    - `type` 'charming.app-descriptor', required
    - `schema_version` 'v1', required
    - `id` string, uuid, required
    - `revision` integer, 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.
    - `display_name` string, required
    - `app_name` string, nullable, required
    - `visibility` 'public' | 'remixable' | 'private', required
    - `authorized` boolean, required
    - `canonical_url` string, uri, required
    - `when_to_use` string, required
    - `author_provided` object, required
    - `operations` object[], required
    - `http_api` object, required
    - `mcp` object, required
    - `auth` object, required
    - `advisories` object[]
  - AppDescriptorStub: Fail-closed descriptor for a private app when the caller lacks app:read. It omits the app ID, revision, source state, and operations.
    - `type` 'charming.app-descriptor', required
    - `schema_version` 'v1', required
    - `visibility` 'private', required
    - `authorized` false, required
    - `message` string, required
    - `auth` object, required

## Other responses

- `400`: `id` is not a well-formed app id.
- `404`: App not found.

---

[API](https://skmtc.dev/charm/apis/charming-api.md) · [All operations](https://skmtc.dev/charm/apis/charming-api/llms.txt) · [OpenAPI document](https://skmtc.dev/charm/apis/charming-api/revisions/a9d06c419b3a?raw)
