Menu QaldyDocs

App manifest

The permission contract of an app version. Every field, generated from the schema the API and the gate validate with, and an example with the sentences a person reads before approving.

Every app version carries a manifest. The builder proposes it, a person approves it, and the gate enforces it: anything not declared here is denied. The manifest of a published version never changes; wider access is a new version.

You rarely write one by hand. A plan from the Build screen, plan_app_from_prompt or qaldy build --plan contains one, and shows it as sentences. This page is for reading a plan closely, for reviewing what an agent proposes, and for building tools around the API.

An example

json
{
  "name": "Low-stock alert",
  "description": "Tells the roastery chat in Telegram when a coffee bean stock drops below 5 kg.",
  "archetype": "radiotower",
  "category": "messaging",
  "permissions": {
    "data": [
      {
        "table": "stock",
        "access": "read"
      },
      {
        "table": "alerts_sent",
        "access": "write"
      }
    ],
    "connectors": [
      {
        "id": "telegram",
        "actions": [
          "sendMessage"
        ],
        "scope": "#roastery"
      }
    ],
    "egress": [],
    "ai": null
  },
  "triggers": [
    {
      "type": "schedule",
      "cron": "0 8 * * 1-5"
    }
  ],
  "sharing": {
    "default": "private"
  },
  "roi": {
    "manualMinutesPerRun": 10
  }
}

The plan shows this manifest to the person who approves it as these sentences:

  • Can read stock.
  • Can change alerts_sent.
  • Can send Telegram messages to #roastery through Telegram.
  • Does not use AI models.
  • Can't reach anything else on the internet.

Nothing here reaches the internet: egress is empty and ai is null. Each connector action is named, so the app can send a message to that one chat and cannot do anything else through Telegram. The app can read the stock table and write alerts_sent, and no other table.

Every field

The table is generated from the schema the API, the builder and the gate all parse with, so it cannot drift from what is enforced.

FieldTypeRequiredNotes
namestringyes2 to 60 characters
descriptionstringyes4 to 280 characters
archetype"kiosk" · "tower" · "warehouse" · "workshop" · "bank" · "townhall" · "clocktower" · "printhouse" · …yes
category"interface" · "data" · "messaging" · "money" · "ai" · "time" · "people" · "growth"yes
permissionsobjectyes
permissions.dataobject[]yes
permissions.data[].tablestringyes1 to 48 characters
permissions.data[].access"read" · "write"yes
permissions.connectorsobject[]yes
permissions.connectors[].id"shop" · "stripe" · "gmail" · "telegram" · "sheets" · "slack" · "kaspi" · "1c" · …yes
permissions.connectors[].actionsstring[]yes
permissions.connectors[].scopestringup to 80 characters
permissions.egressobject[]yes
permissions.egress[].domainstringyes3 to 253 characters
permissions.egress[].reasonstringyes8 to 200 characters
permissions.aiobject or nullyes
triggersobject[]yes
sharingobjectyes
sharing.default"private" · "team" · "workspace"yes
roiobjectyes
roi.manualMinutesPerRunnumberyes0 to 1440

How the permissions are enforced

FieldEnforced by
permissions.dataThe runtime host builds the app's data binding from it. A table not listed does not exist for the app, and write is separate from read.
permissions.connectorsThe gate matches each call to {connector, action} in the version's manifest. Anything else is 403 egress_blocked (action_not_declared).
permissions.egressThe gate allows exactly these hosts, plus the connectors' own hosts: HTTPS, port 443, an exact name. Each needs a reason a person can read. Wildcards and IP addresses are refused.
permissions.aiThe gate allows model calls only for the declared models, within the monthly budget. An undeclared model is refused.
triggersThe platform starts a run on a schedule, a webhook, a form, a button press or an event.
sharing.defaultWho can open a new app at first; sharing then works as described here.

A manifest is checked twice: the builder's static checks against the code (declared egress must equal used egress, see Approvals and the Trust Score), and the gate at run time against the actual calls.

Type to search. Up and down to choose, Enter to open, Esc to close.