The manifest

An application manifest is a JSON document that declares the application's services, network access, and other deployment requirements. Generated and hand-written manifests use the same schema. Ask your tool to read the context://manifest_schema resource before it submits with submit_manifest. A manifest that fails validation is refused with the JSON path of each violation.

The members

Seven top-level members are required. Three more, settings, upstreams, and realm, are optional, and any other top-level member is refused. The manifest declares no environments: an application has production, and development where you turn it on with create_environment. A manifest with an environments member is refused environment_unsupported.

Member What it declares
manifest_version The version of the manifest format, the integer 1. An unknown version is refused.
services The provisioned services the application uses, each an object with a kind. The list after this table gives the members each kind takes. An empty array declares no services. Hosting is not an entry, because every accepted application is hosted.
health The health endpoint, an absolute path on the application's own address. The platform checks it at every deploy, promote, and platform redeploy. A deploy to an environment that serves no version yet is refused health_path_unserved where no source file of the zip names the path's last segment.
region usa is the only value available today. The schema also lists europe, uk, and global, but submission refuses them as region_unavailable. The global value makes no promise about where data is kept.
egress The outbound hosts the application may reach: exact lowercase hostnames and *.example.com host families. An empty array declares no external hosts. In enforce mode the egress proxy refuses undeclared destinations; in observe mode it can allow and record them. See Egress firewall and request limits.
audience Who may reach the application: {"kind": "public"}, {"kind": "invited"}, or {"kind": "workforce", "tenant": …}. The invited and workforce kinds may also list session_free_paths. See The audience kinds.
packages The library entries the application includes, each as a name and a version. The version is null for a font family and for the library's own requirements entry, library/prd. Use the library says how your tool copies it from system/manifest.json at each submission. An application with no entries declares an empty array.
settings Optional. Stored secrets the application's code reads as named settings, as an object from a setting name to {"secret": "<stored name>"}, at most fifty entries. Each deploy and promote injects the value stored for its environment. See Bound settings.
upstreams Optional. The application programming interfaces (APIs) the application calls with a stored key through the platform's gateway, as an object from an upstream's name to its declaration, at most fifty entries. Each submission declares them for the application. See Upstreams in the manifest.
realm Optional. The sign-in setup of both end-user realms: sign_in_methods, creation, entra, and apple, as configure_realm takes them. See Sign-in and push in the manifest.

Each kind of services entry takes these members besides its kind:

  • database, object_storage, accounts, and email take no other member.
  • push takes only its providers.
  • issue_tracking with no other member gives the application one issue-tracking space for both environments. It may instead give a space your account owns, one identifier or { "development": ..., "production": ... }, with a level of report or contribute. The application is then bound to that space, and nothing is created.
  • custom_domain takes its domain.
  • schedule takes its schedules: one to twenty-five declarations, each a name, a five-field cron in UTC, and an absolute path on the application's own server. The path may not be the health path or fall under /__account/ or /__router/. Such a declaration is refused manifest_invalid at its own JSON path.

The database, object storage, and accounts services run today. The schema accepts email and custom_domain, and declaring one provisions nothing. schedule runs today and requires its schedules array; a bare schedule entry is refused. push runs today, and the declaration allows the push configuration and the push routes. Its providers are named in the entry itself (Sign-in and push in the manifest) or configured afterwards with configure_push (Send push notifications).

The audience kinds

  • Public. Anyone can reach the application.
  • Invited. Every request needs an end-user session. The application's realms become invitation-only: a first sign-in without an invitation from issue_invitation creates no user, whatever the realm's creation setting is.
  • Workforce. Only one company's staff can reach the application. The tenant member is the identifier (a GUID) of the company's work-account tenant. The realm's entra sign-in method is configured against that tenant, as Manage end users describes. Only that tenant's signed-in users reach the application.

Under invited and workforce, a request without an end-user session is refused. There are two exceptions: the platform's own scheduled runs, and the paths the audience lists in session_free_paths. A payment provider's webhook, or any other service's callback, has no session, so list its path there to receive it. The platform checks nothing about the sender on a listed path, so the route checks each caller itself, by the provider's signature. Add sign-in to your app gives the rules for the list.

Bound settings

The settings member binds a stored secret to a setting the application's code reads. The binding names the secret, never its value, and it is reviewed and versioned with the code. A setting name is an upper-case letter, then upper-case letters, digits, or underscores, ending in a letter or a digit.

Most outbound API keys belong with the egress gateway instead, which adds the key to each call and never gives it to the application. A bound value is in the container. A replacement takes effect at the environment's next deploy or promote, or at a restart where the running copy already has the binding. Store a secret compares the two.

A binding never names a setting name the platform reserves, a name the platform created, an upstream's key, or a sign-in method's or push provider's credential. Author the manifest lists each refusal.

Upstreams in the manifest

An upstream is an outside API the application calls through the platform's gateway, which adds the stored key on the way. The upstreams member declares them with the code, in place of a declare_upstream call for each. Each entry takes what declare_upstream takes except application, because the manifest's application is the one it is submitted for.

With its upstreams in the manifest, an application is described by one file. Re-creating it, or copying it into another account, takes the manifest, a store_secret for each key, and a deploy.

Upstream names are unique within an account. A copy beside the original in the same account gives its upstreams names of their own. A name another application already uses is refused, and the refusal names that application.

While the member lists an upstream, the manifest controls it, and declare_upstream refuses to change it. An upstream the member does not list can still be changed with declare_upstream. No submission ends an upstream, so a running version that calls it keeps working. undeclare_upstream ends one once the member no longer lists it. Author the manifest shows the member and its refusals.

Sign-in and push in the manifest

The realm member declares the sign-in setup that is the same in every environment: the sign-in methods, who may create an account, and the entra and apple route members. A push entry in services may also name its providers, apns and fcm. Each credential member names a stored secret, never its value.

With these members and upstreams, re-creating an application, or copying it into another account, takes the manifest, a store_secret for each credential, and a deploy. No configure_realm or configure_push call is needed.

While the manifest names a field, it controls that field, and configure_realm or configure_push refuses to change it. The settings that differ by environment stay with the actions: a realm's limits, session lengths, invitation days, and native clients, and Apple's push gateway. Author the manifest shows the members.

What submitting does

submit_manifest records the manifest for an application, then provisions the implemented services it declares:

  • Database. The first database declaration creates the development database and its role at submission, on every application, for local runs. While the manifest declares the kind, the first deploy to production creates the production database and role on one environment, and the first promote creates them on two.
  • Accounts. The first accounts declaration creates an end-user realm for each environment the application has: production's alone on one environment. The production realm stays until the application is deleted. A development realm is created by create_environment or by a submission while development is on, and ends with delete_environment or with the application.
  • Credentials. The first submission creates two development values: the development platform credential, and the development database credential where the manifest declares the database kind. No production credential is ever returned.
  • Bound settings. A settings member provisions nothing. The result's settings rows say, per setting and environment the application has, whether the bound name is stored there yet.
  • Upstreams. An upstreams member declares each upstream, as declare_upstream would, from that moment. A key not stored yet is accepted. The result's upstreams rows say, per upstream and environment, whether its key is stored there. An entry that drops its key setting ends the egress keys running copies hold, and egress_keys_ended counts them. A detail line names each environment that lost one and the way back: restore the entry's settings.key, submit again, then call restart_application there.
  • Sign-in and push. A realm member configures the realm of each environment the application has, and a push entry's providers configure each of those environments, as the two actions would. On one environment that is production alone, and create_environment configures development when it adds it. A credential not stored yet is accepted. The result's detail names each one not stored yet, with the environment where only one environment lacks it.

How your tool receives the two development values depends on how it calls:

  • On the Hypertext Transfer Protocol (HTTP) API, a submission that names no local_run returns each value once, for your local environment file.
  • Through the Model Context Protocol (MCP) tool, the result withholds both values. So does an HTTP submission that names local_run, because the line it returns creates both again.
  • A submission that names local_run: true returns the provision line, which writes the settings a local run needs into your environment file. Through the MCP tool, a submission with no local_run returns provisioning.next, which says to submit again naming it.

Submission also updates schedule declarations. A declaration fires in an environment once that environment has a deploy or promote made at or after the declaration. On one environment that is a deploy to production. On two it is a deploy to development or a promote to production. It does not fire while its environment is halted. Run scheduled work covers the rest.

The platform validates the whole manifest before it provisions anything, but provisioning itself can stop part way. A failed database setup can leave the manifest recorded and the setup partly done. The refusal says how to retry; Author the manifest explains this case.

Changing the manifest

Change the manifest through submit_manifest, and send the whole document. A submission replaces the recorded manifest, so a member you leave out removes that declaration. Adding a service or an egress entry changes what the application depends on or can reach. A deploy reads the recorded manifest and does not change it. The manifest-author skill writes or changes a manifest against the published schema, and the add-service skill adds a service declaration.

Removing a declaration deletes nothing:

  • A removed database, with its role, remains until delete_environment removes the development database or delete_application removes both.
  • A removed accounts declaration leaves each realm in place on the same terms.
  • A removed schedule declaration runs no more, and its run records are kept.
  • A removed upstream entry stays declared, and declare_upstream can change it again. It ends when you call undeclare_upstream, or when the application or your account is deleted. Promote the version that no longer calls it first: within a short cache interval, its calls are refused in both environments.
  • A removed realm field or push provider keeps its configuration, and configure_realm or configure_push can change it again.

A binding added or removed takes effect at the environment's next deploy or promote. A restart re-applies the bindings the running copy was started with, never the current manifest's. A rollback re-applies the bindings its version last had in production, or those its deploy recorded where production never ran it.

The platform gives a deployed copy what the environment has, not what the manifest declares. While a database remains, each deploy or promote supplies the connection string of the environment it reaches. While a realm remains, the deploy and the promote still supply its public keys. A deploy to production or a promote creates the production database only while the manifest declares the database kind. One made after the kind is declared again creates it.

A resubmission that changes nothing records the document. If the development database and the development platform credential already exist, it provisions nothing new and creates no credential. To create new development credentials, your tool submits again naming local_run and runs the provision line the response returns. The line calls rotate_secret on the development scope.

Provenance

The platform does not record where an application's code came from. Today's workflow uploads an artifact you build yourself, and no result reports its origin. The manifest has no member for it: generated and hand-written manifests pass the same validation and get the same access and network controls.