Applications and environments

An application is the record Turn Zero Cloud keeps for one hosted program: its name, its plan, its managed hostnames, and its environments. A new application has production alone, and has development too once you turn it on. This page explains that record, how a version reaches each environment, the version history, and the halted state. The reference lists each action's arguments and results in full.

The application

create_application creates an application from a name and an initial plan: free, standard, or pro. It returns the application identifier that later calls use, and a label that forms the managed hostnames under ai.host. The label combines the name with a unique suffix. The production hostname serves the application after the first release to production: a deploy on one environment, a promote on two. The development hostname serves it only after a first deploy to development. A hostname retired by deletion or renaming is never reused.

list_applications returns the account's applications. Each includes environments, an array with one object per environment the application has, development first where it has one. Each object gives the environment's name, its state, its serving version (or null), and its hostname: <label>.ai.host for production and <label>-dev.ai.host for development.

read_status returns its own environments object, keyed by environment name. In that object, each environment's state is the same value list_applications returns. Beside it, compute_state gives the hosting service's own word for the compute, and it is null until the compute exists. The halt, the deletion, and the deploy record are also there (Read the status). Its top-level members describe the environment the call names in environment, production where it names none, and its top-level environment member names that environment.

The read_status and list_applications reference pages list every member. Plan and usage explains set_plan and read_usage.

In list_applications and read_status, an environment's state is one of six values. The state is the first value in this list that applies:

  • deleting: the application or the environment is being deleted.
  • halted: the developer or the platform halted the environment.
  • deploying: a deploy, a promote, or a platform redeploy of the environment is in progress.
  • deployed: a version is serving.
  • failed: no version is serving, and the environment's latest deploy or promote failed.
  • never_deployed: none of the above.

The manifest sets which services the platform provisions, separately for each environment:

  • Database. Where the manifest declares the database kind, each environment gets its own database and role. The development database and its owner role, which local runs use, are created on every application when the manifest is submitted. The production database and its owner role are created, while the manifest declares the kind, by the first release to production: a deploy on one environment, a promote on two.
  • End-user realm. Where the manifest declares the accounts kind, each environment the application has gets its own realm, a list of the application's end users. On one environment that is production's realm alone.
  • Storage. Each declared storage area keeps one partition per environment.
  • Secrets. An application-scoped secret is stored for the environment that the store_secret call gives.

Deleting an application

delete_application needs a person's approval in a browser. It removes every environment and everything bound to the application, as Manage versions and environments lists. Account-scoped secrets, unbound storage areas, unbound declared upstreams, and metering history remain. The approval page counts the affected resources by kind, and the outcome includes one receipt per kind.

While the deletion runs, any action that would change the application is refused 409 deletion_in_progress. Reads, read_pending_action, and a repeat of the same deletion are still accepted, and list_applications shows each environment as deleting. If the deletion stops at a resource it cannot remove, the outcome's receipts list what it did remove. Requesting the same deletion again resumes it, and a resource already removed reports zero removals.

Deleting the development environment

delete_environment removes the development environment alone and turns development off, so the next deploy goes to production. It also needs browser approval. It refuses production with invalid_request, because production is deleted only with its application. A development environment that was never deployed can be deleted too, which removes whatever it contains, such as its realm and its secrets.

On an application with one environment there is no development environment to turn off. Your local runs still keep records there: the development database, its platform credential, and the secrets, files, and logs you stored for them. The call is accepted in three cases:

  • a development database exists, or a setup of it stopped partway, for example one submit_manifest refuses with server_unavailable or rotate_secret refuses with database_provisioning_failed;
  • an earlier deletion of these records stopped partway; the same call completes it;
  • a development copy or realm left by an earlier version of the platform is still there.

It then removes those records, leaves production untouched, and the application keeps one environment. The approval page lists what it removes. In any other case the call is refused 409 environment_not_created, before anything is asked of you.

The deletion removes the development environment's:

  • container;
  • database and role, with their credential;
  • realm, with its passkeys and invitations;
  • issue-tracking space, where the application kept one for each environment, deleted at the issue service with every report, comment, rating, and ask in it;
  • binding to an issue space of your account's own, which keeps its records;
  • application-scoped secrets and platform credential;
  • partition of every bound storage area;
  • log entries and counter totals;
  • version rows, which list_versions no longer returns and whose numbers are never used again.

The application, its production environment, its storage areas, and its declarations remain. The secret store keeps the deleted secret values for ninety days before it purges them, and the usage meters keep their rows.

Afterwards the application has one environment, production. The next submit_manifest creates a new development database and role and a new development platform credential for local runs, and returns the development credentials once, as a first submission does. The secrets and files you stored for development are not brought back; store them again if you still need them. An application that kept an issue-tracking space for each environment also gets a new empty development space. It creates no development realm.

To turn development on again, call create_environment. Its new realm takes the manifest's realm member where there is one. Otherwise it has the default sign-in methods: google, github, email for the emailed code, and passkey. The emailed code's messages leave through the platform's one sender, so the platform's mail quota and the per-address and per-realm limits in Add sign-in to your app bound them. Configure any other sign-in methods again with configure_realm, as Manage end users describes. The development schedule declarations remain, and the schedules run again after the next development deploy.

After a deletion, call submit_manifest again before the first deploy to development. The deletion removed the development database, and only a submission creates it again.

Clearing the development database

clear_development_database empties the development database and keeps everything else, and it also needs browser approval. It drops the database with every table and row in it, then creates it again empty under the same role. The role keeps its password, so the development credential and the connection string in .env stay valid.

Afterwards, start your local run again, so the application's migrations rebuild its tables. Where development is turned on and deployed, also call restart_application on the development environment, or deploy, so the deployed copy's migrations rebuild them. The action refuses production with invalid_request, and an application with no development database with not_found. Add a database describes the steps.

Renaming an application

rename_application takes the application identifier and a new name. The name has at most forty characters: a lowercase letter, then lowercase letters, digits, or hyphens. It must differ from the current name, or the call is refused invalid_request. It must also differ from the name of every other live application in the account, or the call is refused name_taken.

Renaming needs browser approval because it permanently retires both of the application's hostnames, production and development. The approval description names both hostnames, the current name, and the proposed name. It counts the passkeys and the invitation links that stop working. Rename the application lists every effect, among them these effects on users:

  • Existing passkeys stop working.
  • Users must sign in at the new hostname.
  • Invitation URLs that contain the old hostname stop working.

After approval, the platform creates new hostnames from the new name and a fresh suffix, and retires the old ones. read_pending_action returns the outcome with the new hostname. The serving router starts serving the new hostnames within its refresh interval, so requests may take a short time to switch. The previous name becomes available for another application.

The rename retires exactly the hostname the approved description named. If another rename or a deletion changed the application after the approval, the outcome is renamed: false with the reason, and nothing changes. Read the application with read_status, and request the rename again if it still applies.

Renaming keeps the application identifier, plan, manifest, environments, databases, end-user realms, storage areas, and secrets. The rename restarts each running container, so its APP_PUBLIC_HOST setting gives the new hostname. Where that restart is refused, the container keeps the old setting until restart_application or the next deploy or promote of its environment.

Environments

An application has one environment, production, or two, development and production. A new application has one. You turn development on with create_environment at any time, and off again with delete_environment, which needs browser approval. The manifest must not declare environments. A manifest that does is refused environment_unsupported.

Stay on one environment unless the builder wants each version tried before production. On one environment, each deploy goes straight to production. Asked only to take an application to production, your tool deploys and calls no create_environment. Where the builder wants each version tried first, call create_environment: each deploy then goes to development, and promote moves a tried version to production.

create_environment takes the application and environment: "development", and completes in the call. Naming production is refused 400 invalid_request. It declares development's schedules. Where the manifest declares the accounts kind, it creates the development realm, a separate list of end users with its own size limit. Local data that names production's end users then matches no tester signed in there.

create_environment also applies the manifest's realm member to the development realm, and the push entry's providers to development with Apple's sandbox gateway. It creates nothing hosted: development's copy starts at its first deploy. On an application that already has development, it returns created: false and only repairs what an earlier failed call left.

create_environment and submit_manifest work in either order. The submission creates development's database and credentials, and turning development on creates neither.

The platform keeps every record for an application separately per environment. Each environment has its own:

  • database and role, on a development server or a production server;
  • platform credential, the value a process presents to the platform;
  • secret scope, so a development request never reads a production value;
  • partition in every storage area;
  • end-user realm, hostname, and version history.

Every application keeps development records for its local runs, even with one environment. They are a development database and its role, a development platform credential, a development secret scope, a development partition of each storage area, and the local log stream. So local test data never lands in the live database, and production's credentials never reach your machine.

What an application with one environment lacks is a hosted development environment: it has no development realm (a realm is one environment's list of end users) and nothing hosted in development. The testers of a local run sign in on production's realm, the application's only list of end users.

On one environment, a deploy goes straight to production, with the same wait and health check. There is nothing to promote: promote is refused 409 environment_not_created. roll_back puts an earlier production version back.

Once development is turned on, a deploy targets the development environment. deploy with environment: "production" is then refused 409 environment_unavailable, because production receives a version only through promote. A promote applies a version from the history to production, with production's own settings and credentials. Without a version argument it promotes the development environment's serving version. roll_back promotes an earlier version. So every build runs first in development.

An action on the hosted development environment of an application with one environment, such as read_status, halt_environment, or a realm action, is refused 409 environment_not_created, naming create_environment. The actions on the development records still work: the secret actions at the development scope, such as store_secret and rotate_secret, and read_logs with local.

Where each environment runs

Where development is turned on, it runs in one of two ways, and list_applications shows which in grain:

  • As one pod in a development group on the hosting cell's cluster, where the cell has a group open to new environments with room left.
  • As its own container where the cell has no open group. A deploy into a group that is full is refused 409 group_full.

Either way it runs the same image with the platform's settings, and a pod also sets HOME to /tmp and runs the process as user ID (uid) 1000. The grain_note of read_status says what each environment's grain means.

On the Free and Standard plans a development pod stops thirty minutes after its last request, and a development container also stops when no request reaches it. Platform staff can change that interval. A stopped development environment starts again on the next request, the next scheduled run, or a deploy. On the Pro plan it keeps running until the platform halts it, as The halted state describes.

The production environment runs as its own container at the plan's minimum replica count. Each environment runs one replica, and two only while a deploy or promote replaces it. A Pro production replica has 0.5 virtual CPU (vCPU) and 1 GiB of memory. Every other container replica has 0.25 vCPU and 0.5 GiB, and a development pod takes its group's settings.

The platform's settings are the same in every environment. Every deploy, promote, and redeploy injects the settings below into the environment's container. For a local run, the provision line writes only the ones a local run reads, as Run locally lists. Settings under names you chose are added beside them. An upstream's base-URL setting arrives under the name you declared for it, as a plain setting, not a secure one. The bound settings your manifest declares and the egress keys of your upstreams are secure settings.

Setting When What it contains
TURNZERO_CLOUD_API always the origin of the platform's application programming interface (API), for Open Authorization (OAuth) sign-in, account reads, the verification route, and management calls
TURNZERO_CLOUD_TOKEN always, secure the environment's platform credential
TURNZERO_CLOUD_APPLICATION always the application's identifier
TURNZERO_CLOUD_GATEWAY_URL where the platform sets a separate gateway origin the origin for storage, egress, and logging calls
TURNZERO_CLOUD_REALM_KEYS where the environment's realm exists the realm's public key set as one JSON string, its keys empty before the first sign-in
APP_ENVIRONMENT always development or production
APP_PUBLIC_HOST always the environment's public hostname, from which a deployed copy builds its public addresses: the request's Host header names the platform's internal address for the environment (What the router sets on each request)
APP_VERSION always the version number that the deploy, promote, or redeploy applied
APP_ASSETS_BASE always the public base of the version's published files
APP_DATABASE_URL where the environment has a database, secure the connection string
APP_DATABASE_CONNECTION_LIMIT where the environment has a database the plan's connection limit, your pool's maximum
HOSTING_WINDOW_REQUEST_SECONDS, HOSTING_WINDOW_SCHEDULE_SECONDS, HOSTING_WINDOW_GRACE_SECONDS always the execution window per invocation kind and the grace, read by the runtime harness
HOSTING_SCHEDULE_PATHS always the handler paths your manifest's schedule entry declared at the time of that deploy, promote, or redeploy
EGRESS_PROXY, EGRESS_PLATFORM_ENDPOINTS where the platform runs an egress proxy the tunnel's proxy and the platform endpoints the harness excludes
ROUTER_MARK_SECRET where the platform keeps a router mark, secure the router mark, which the runtime harness checks on each incoming request

Your code reads the settings that the backend packages' integration guides list. The runtime harness, which the platform loads into your process, reads the rest.

Which environment an action uses

Actions that take an optional environment default to production when you leave it out: the schedule reads, read_logs, the realm actions, store_secret, rotate_secret, and delete_secret. read_counters requires an explicit environment. The logging reads also accept the local stream. Any other name is refused.

A schedule is declared in the manifest's schedule service entry. It runs in each environment that has received a deploy or promote at or after the declaration. Each plan sets a minimum interval between a schedule's runs. It does not run while the environment is halted.

Where an application runs during development

While you build, the application runs in up to three places, and each works differently:

  • A local process on your machine, the local run, runs under the development records, on one environment or two.
  • Where development is turned on, the deployed development copy runs on the platform after a deploy to it. On one environment there is no such copy, and every deploy reaches production.
  • The application's tests run against the test doubles that the backend packages ship, with nothing provisioned.
Local process Deployed development copy Tests over the doubles
Environment development, under the environment file the provision line writes development, under the settings the deploy injects none: a double reaches nothing outside the process
Database the development database, from any address under the developer network rule the development database a PostgreSQL engine in the test process, with your migration files applied when it is created
Platform credential the development credential the development credential none
Storage partition the development partition of each area the development partition of each area the storage double, in memory
Secrets the development scope's values the development scope's values none
Log stream local development the logging double's entries
Hostname and router none: the process listens on your machine the development hostname, behind the serving router none
Runtime harness not loaded loaded by the platform's image not loaded
Realm keys and scheduled runs none injected and run by the platform where the manifest declares them the account double signs under a key pair of its own; the schedule double starts a run

With development turned on, the local process and the deployed copy share the development environment's data and credential. Both use the same development database, the local process over the server's public endpoint. Both write the same development partition of each storage area and read the same development secrets. Both present the development platform credential. The deployed copy keeps the credential value from its last deploy. The provision line mints a new value, so deploy again after you run it.

Only the deployed copy runs behind the platform's router and runtime harness:

  • It serves under the development hostname, behind the router that applies the manifest's audience and serves the sign-in pages under /__account/.
  • It receives the realm's public keys where the manifest declares the accounts kind.
  • It receives scheduled runs where the manifest declares schedules.

A local process has none of these. It listens on your machine at the port its code chooses, PORT where you set it, and the environment file sets no port. No audience check applies to it, and no scheduled run reaches it.

The environment file contains no realm key set. So a local process whose verification client reads the key set only from the injected setting verifies an end-user session through the verification route, under the development credential.

On one environment the application has one list of end users, production's realm, and the route checks a local run's sessions against it. Your testers sign in at the production sign-in pages, as your live users do, so they are end users of the live application. The route checks a session the tester already has, and starts none. With development turned on, a local run's testers sign in on the development realm instead.

A local process's log lines go to the local stream, which read_logs reads with environment: "local". Run locally lists the file's settings, and the provision line writes the file. The Node.js Runtime package lists the protections only a deployed copy receives.

The tests are the third place. Each backend package with a client ships a test double at its testing subpath. The application's test suite runs against the doubles with no account, no connection, and no environment file. Test your application locally shows each double in use. A double is for tests only and is not a mode of a running application.

A process started with no environment file is neither a development run nor a test. An application written as the Database package's integration guide describes stops when it starts and reports the missing APP_DATABASE_URL. An application that reads no database setting starts, but each call it makes to the platform is refused because it has no credential. The provision line writes the file for either kind of application. Where no development database exists, the line mints a new platform credential only, and writes the five settings that need no database.

The platform never creates the schema. A new database is empty, and the application creates its tables from its migration files when it starts, through the Database package's migration function. The same files are applied to every database the application uses. The development database receives them at a local or deployed start, production at the start after a production release, and the database double when it is created. Add a database states the rules.

The development hostname

An application's production hostname is <label>.ai.host, and its development hostname is <label>-dev.ai.host, from the same label. The label's unique suffix never contains a hyphen, so the two forms cannot collide.

The domain after the label belongs to the platform that created the application. The platform at https://turnzero.ai serves applications under ai.host, the domain these pages show. Turn Zero's development platform at https://dev.turnzero.ai serves them under dev.ai.host: <label>.dev.ai.host for production and <label>-dev.dev.ai.host for development. That dev names the platform, not the environment. Read a hostname from the answer that returns it, list_applications, create_environment, deploy, or promote, rather than composing it.

The router serves the development hostname from the moment the application is created. Before the first development deploy, it returns 404 not_deployed on every path except /__account/. On an application with one environment, that path returns 404 too, naming create_environment, because there is no development realm. Once development is turned on, it serves the development realm's sign-in pages, so an end user can sign in to the development realm before the environment has a running copy.

Every response on the development hostname includes the header X-Robots-Tag: noindex, nofollow, and the platform publishes no list of development hostnames. The development environment serves your build under the manifest's audience. Where the audience is public, anyone who has the development hostname can read the development environment's data. Manage end users explains what that means for test data.

The version history

Every deploy, promote, restart, and platform redeploy writes one row of the application's version history. list_versions returns the rows newest first. It takes an optional environment, a limit of 1 to 200 rows (50 by default), and a cursor from a previous result's next_cursor. The list_versions reference page lists every member of a row.

Each row has its environment, its version, the artifact_hash, and the times started_at and ended_at. The other members explain what the row did:

  • kind is deploy for a deploy's row and promote for a promote's or rollback's row. It is restart for a row written when restart_application, a rename, or the platform re-created the running copy under current settings, with the same version and image. A restart changes nothing of yours, with one exception. For an application deployed before the platform stored one platform credential for each environment, a restart ends its older credential once, as a deploy does.
  • state is deploying, deployed, or failed. On a failed row, outcome gives the failure. After a failed health check, outcome also includes gate, the evidence that Deploy an application describes, in both list_versions and read_status.
  • outcome is null while the row is deploying. On every ended row it starts with result: succeeded, failed, interrupted, or superseded. After a failed image build, it also includes build, the last lines of the build's output.
  • timings lists the steps the row entered, in order, each with its started_at and ended_at.
  • serving is true on the row of the version each environment runs.
  • promotable is true on a deployed row whose image the platform still keeps, so promote and roll_back can name its version. It says the image still exists, not that promoting it is advised.
  • harness_hash is the SHA-256 hash of the platform's runtime harness in the row's image, or null where the platform did not record it. harness_current is true where that harness is the one the platform puts in new images today.

A deploy takes the next number of one sequence per application, shared by development and production. A promote row has the number and the harness of the deploy it promotes, because it applies that deploy's image. So a version gets the current harness only through a new deploy. A restart row has the number and harness of the row it re-created, and once it finishes it is its environment's serving row, which a promote can name. The same number can therefore appear on a development deploy row, a production promote row, and a restart row of either environment.

On one environment, a deploy's row is production's own deploy row. An environment's serving version is its newest deployed row. Rows that delete_environment retired are not returned and never serve.

The halted state

halt_environment and resume_environment take application and environment, and both finish before the call returns. Each returns the environment's halted member, { at, by } or null while it runs, and an outcome: halted, resumed, or unchanged. The outcome is unchanged where a halt found the environment already halted, or a resume found it already running.

A halted environment keeps its deployed version, its data, its credentials, and its schedule declarations, but serves nothing. Its hostname returns 503 environment_halted on every path, including the sign-in path /__account/. Its schedules do not run, and each schedule's next_due stays where it was.

What a halt stops:

  • A halt of production stops the production container.
  • A halt of a Free or Standard development environment stops nothing more, because it already stops when no request reaches it.
  • A halt of a Pro development environment stops its compute.

halt_environment refuses an environment with no deployed version, 409 environment_never_deployed. It also refuses an environment with a deploy, promote, or platform redeploy in progress, 409 deploy_in_flight.

Halting production needs your signed-in session or a token minted for the whole account. A token limited to one application is refused 403 account_credential_required, so a leaked application token cannot stop production. A halt of development, and resume_environment on either environment, are accepted under a token limited to one application.

Ending a halt

Two actions end a development halt, whoever halted the environment:

  • A deploy to the environment. The deploy is accepted and ends the halt after its checks, before it writes its history row.
  • resume_environment, which ends the halt without a deploy.

Only resume_environment ends a production halt, and it also starts the production container. A deploy or a promote to a halted production environment is refused 409 target_environment_halted, and run_schedule on a halted environment is refused the same way. Each is accepted after the resume.

A resume restarts every schedule of the environment from the moment of the resume. A schedule whose due time passed during the halt moves to its first due time after the resume, and no missed run is recorded. read_status shows halted for each environment, read_schedules shows it beside the environment, and list_applications shows the state halted.

Halts the platform makes

Where development is turned on, the platform halts the development environment itself, with by set to platform, when its halt interval has passed. The interval runs from the later of two moments: the end of the deploy that made the environment's serving version, and the environment's last resume. So a successful deploy or a resume_environment starts the interval again, and a deploy that ends failed does not.

The interval comes from the platform value development-halt-after-days, which platform staff can change without a release. It is currently seven days on every plan. A daily check applies the rule, so the halt happens within one day after the interval ends. The platform never halts production.

The rule stops the compute charge for a development environment you have stopped using.

The platform also re-creates an environment's running copy after it changes its router mark. This writes a restart row and one event in your log stream, and leaves the version and everything else of yours unchanged. A halted environment is re-created after its resume.

Backend versions and snapshots

The application applies its own migration files when it starts, and neither a deploy nor a promote takes a snapshot. roll_back moves code only: it promotes an earlier version and changes no data. Across a data-model change, you decide how the data is migrated or restored. Do not assume the platform has taken a snapshot or can reverse a schema change.

The catalog's two actions for this, apply_migration and restore_snapshot, are served by no build: the tool list leaves them out, and a call to either over the management route answers 501 not_yet_provisioned.

The release skill guides promotion and rollback, and the develop-then-promote skill guides deploys to development and promotes to production. The diagnose skill reads the version history together with status, logs, and counters.

  • Deploy an application creates an application, deploys it to production, and turns on a development environment to promote from.
  • Plan and usage explains the results of set_plan and read_usage.
  • Manage end users describes a realm's sign-in methods and what a public development hostname means for test data.
  • Management action tiers and approvals explains the browser approval that delete_application, delete_environment, clear_development_database, and rename_application need.
  • Test your application locally explains how to run the application's tests against the backend packages' test doubles, the third place an application runs during development.
  • Actions lists every management action with its inputs and outputs.