Everything aeria does is a tool. Your MCP client calls it on /mcp;
the same tool is a route under /api/v1; every call is an event.
The levels
Section titled “The levels”Each tool has one level in your workspace:
allow called at once
ask held until you allow or deny it
deny not offered; a call is refused unknown_toolA tool marked none below is never offered to an MCP client: it is a
value you type, your own word (a sign-in, a consent), or an operator’s
decision. You do it on app.aeria.dev.
- Change a level:
tool_level_set {tool, level}. It is ataskitself: a raise is answered by an owner only, so your agent never widens its own powers. Your client is told to list its tools again. - A held call pauses your client’s call until you answer: in the
client itself when it can ask (Claude Code), else on
app.aeria.dev/held/<call>. Allowed, it runs as you; denied, it is refuseddenied, with who and when.
Finding and calling tools
Section titled “Finding and calling tools”tools/listholds aeria’s own tools not atdeny.tool_search {keyword}finds aeria’s tools and every connection’s operations, each with its level.tool_call {tool, params}calls an operation (a connection’s or an app’s) at its own level.
A tool that lists is <group>_search: it takes keyword, page and
per_page (20 by default, 100 at most) and answers page, per_page
and total_count.
Sign-in and workspaces
Section titled “Sign-in and workspaces”| Tool | Level | What it does |
|---|---|---|
user_whoami |
allow | you and your workspaces |
grant_search |
allow | the MCP clients you allowed, each its workspace |
grant_revoke |
none | a client’s grant ended, its tokens with it |
workspace_create |
none | a workspace, you its owner |
workspace_search |
allow | your workspaces |
workspace_show |
allow | its name, members, apps’ count and public key |
workspace_set |
allow | its display name; never its slug |
workspace_archive |
none | its apps archived, its tokens ended, nothing deleted |
tool_search |
allow | aeria’s tools and connections’ operations, each its level |
tool_level_set |
ask | one tool’s level in the workspace |
event_search |
allow | the workspace’s events: by app, branch, person, tool |
exec_wait |
allow | a running exec, answered when it ends |
held_search |
allow | the calls waiting for a person |
held_answer |
none | a held call allowed or denied |
session_search |
allow | the open branches and artifacts, each its sandbox and preview |
member_search |
allow | the workspace’s members |
member_invite |
ask | an email invited, with its role |
member_role_set |
ask | a member’s role |
member_archive |
ask | a member removed, their record kept |
billing_show |
allow | its plan, balance, limit, reload, card’s last digits |
billing_limit_set |
ask | its spending limit, within the plan’s |
usage_search |
allow | its usage by meter, app, branch or day |
Also yours alone, on app.aeria.dev: terms_accept, user_logout,
passkey_add, invitation_accept, billing_reload_set (each none).
An app and its code
Section titled “An app and its code”Every code tool names an open branch of its app and runs as an exec in that branch’s sandbox, one at a time (The flow).
| Tool | Level | What it does |
|---|---|---|
app_create |
allow | an app from the seed, its production running |
app_show |
allow | its host, open branches, previews, last deployments |
app_search |
allow | the workspace’s apps |
app_archive |
ask | hidden, its schedules stopped, nothing deleted |
app_access_set |
ask | private (its workspace’s members) or public (anyone) |
app_branch_create |
allow | a branch cut from main; the same name joins it |
app_branch_search |
allow | its branches, each its sandbox’s state and preview |
app_branch_close |
ask | closed unpromoted and purged; its commits and events kept |
app_code_search |
allow | its files at a branch, no sandbox |
app_file_read |
allow | one file at a branch, no sandbox |
app_file_write |
allow | checkout, write, commit, push |
app_file_delete |
allow | checkout, remove, commit, push |
app_file_move |
allow | checkout, move, commit, push |
app_command_run |
allow | any command in the checkout, its changes pushed |
app_seed_update |
allow | the seed’s changes since the app’s fork merged into a branch |
Build, preview, promote
Section titled “Build, preview, promote”| Tool | Level | What it does |
|---|---|---|
app_test |
allow | the tests |
app_check |
allow | the lint and types |
app_preview |
allow | built, deployed on the branch’s own host |
app_promote |
ask | the preview’s bundle made production, main moved, the branch purged |
app_branch_rebase |
allow | the branch rebased onto main |
app_deployment_search |
allow | production’s deployments, the current one |
app_rollback |
ask | an earlier deployment served again |
app_database_restore |
ask | production’s D1 back to a point in time (30 days) |
app_log_search |
allow | the app’s logs |
An app’s data and files
Section titled “An app’s data and files”| Tool | Level | What it does |
|---|---|---|
app_sql_run |
ask | any statement on production’s D1 or a preview’s |
app_model_search |
allow | its models, read from the code at a branch |
app_model_show |
allow | one model, and whether production runs it |
app_object_url |
none | a signed URL for one object of the app’s bucket |
app_backup_create |
allow | production’s D1 exported |
app_backup_search |
allow | its backups |
app_backup_load |
allow | a backup loaded into a preview’s D1, never production’s |
Settings, secrets and connections
Section titled “Settings, secrets and connections”No tool takes or answers a secret’s value: you type it on
app.aeria.dev (Security).
| Tool | Level | What it does |
|---|---|---|
app_setting_ask |
allow | a link for you to type a secret setting |
app_setting_set |
none | one setting, a secret sealed in your browser |
app_setting_search |
allow | its settings, the missing ones named |
app_setting_archive |
ask | a setting removed, its record kept |
app_secret_rotate |
none | the app’s own key replaced, by the owner |
connection_ask |
allow | a link to a connection’s setup page |
connection_set |
none | the setup page’s: its fields, its secrets sealed |
connection_search |
allow | the workspace’s connections, never a value |
connection_show |
allow | one connection, never a value |
connection_archive |
ask | archived, its tools and secrets no longer used |
Schedules and webhooks
Section titled “Schedules and webhooks”| Tool | Level | What it does |
|---|---|---|
app_schedule_search, app_schedule_show |
allow | read from the code at a branch |
app_schedule_run_search, app_schedule_run_show |
allow | its runs |
app_schedule_pause, app_schedule_resume |
allow | production’s |
app_schedule_trigger |
allow | one run now, production or a preview |
app_webhook_search, app_webhook_show |
allow | read from the code |
app_webhook_delivery_search |
allow | its deliveries, asked of the app |
Publishing, installing, calling operations
Section titled “Publishing, installing, calling operations”| Tool | Level | What it does |
|---|---|---|
app_publish |
ask | listed for other workspaces once an operator’s review passes |
app_public_search |
allow | the public apps |
app_install |
ask | a public app installed in another workspace |
tool_call |
allow | an operation called, at its own level |
Artifacts
Section titled “Artifacts”| Tool | Level | What it does |
|---|---|---|
artifact_pull |
allow | a new artifact of a kind, or the one of that name |
artifact_file_read |
allow | one file of it, no sandbox |
artifact_file_write |
allow | written, committed, pushed in its sandbox |
artifact_command_run |
allow | any command in its checkout |
artifact_save |
allow | built, checked, kept as its next version |
artifact_search |
allow | the workspace’s artifacts, newest first |
artifact_access_set |
ask | self, workspace or public |
artifact_tags_set |
allow | its tags |
artifact_archive |
ask | hidden, its link refused, nothing deleted |
artifact_unarchive |
allow | found again |
Generated by connections
Section titled “Generated by connections”A connection adds one tool per operation of its service, named
<connection>_<operation> (Connections). An app adds
its own the same way, from its production’s /openapi.json. Each is
found by tool_search, called by tool_call, and starts at deny
until you expose it with tool_level_set.
| Tools | Made from | Level |
|---|---|---|
stripe_* |
Stripe’s OpenAPI, pinned | deny |
shopify_* |
Shopify’s GraphQL schema | deny |
<connection>_* |
its OpenAPI or GraphQL | deny |
<app>_* |
its production’s /openapi.json |
deny |
The generators
Section titled “The generators”Each changes an app’s code by one of the seed’s own commands, run in the
branch’s sandbox (checkout, command, test, commit, push); then
app_preview shows it.
| Tool | Level | The seed’s command |
|---|---|---|
app_add |
allow | bun run add pages|storage |
app_remove |
ask | bun run remove pages|storage |
app_model_create |
allow | bun run model create <name> <attribute>... |
app_model_change |
allow | bun run model change <name> <change> <args> |
app_namespace_create |
allow | bun run namespace create <name> --sign-in <methods> |
app_namespace_change |
allow | bun run namespace change <name> <change> <args> |
app_page_create |
allow | bun run page create <name> --path <path> --namespace <name> |
app_page_change |
allow | bun run page change <name> <change> <args> |
app_schedule_create |
allow | bun run schedule create <name> "<cron expression>" |
app_schedule_change |
allow | bun run schedule change <name> <change> <args> |
app_webhook_create |
allow | bun run webhook create <service> --verify <how> --secret <SETTING> |
app_webhook_change |
allow | bun run webhook change <service> <change> <args> |
Their reads, each allow: app_namespace_search, app_namespace_show,
app_page_search, app_page_show.
Operators
Section titled “Operators”aeria’s own staff’s tools, each none, refused not_operator to anyone
else: app_takedown, app_reinstate, artifact_takedown,
artifact_reinstate, app_review, app_limits_set, user_erase.
Refusals
Section titled “Refusals”A refusal says why: {error, message} with its HTTP status, one code
per refusal in every tool.
| Code | HTTP | Meaning |
|---|---|---|
busy |
409 | the sandbox runs another exec |
no_branch |
404 | no open branch of that name in the app |
behind_main |
409 | main moved since the branch was cut |
preview_stale |
409 | commits after the branch’s last preview |
conflict |
409 | a rebase’s conflict, its files named |
migration_clash |
409 | two migrations with the same number |
sandbox_limit |
429 | the plan’s sandboxes at once, each running an exec |
app_limit |
429 | the plan’s apps |
branch_limit |
429 | the plan’s open branches per app |
payment_required |
402 | the workspace is stopped until paid |
taken |
409 | a name or a host already taken |
saving |
409 | the artifact has a save running |
build_failed |
422 | the build failed, its last lines answered |
no_output |
422 | a declared output missing or empty |
too_large |
413 | an output past 100 MB |
unopened |
409 | a secret sealed to a lost key: set it again |
host_refused |
403 | a secret’s host not declared or not allowed |
app_host |
403 | a host on aeria.run, where agent-written code runs |
restore_failed |
502 | the point in time was not restored |
public_suffix_pending |
409 | aeria.run is not on the Public Suffix List yet |
top_up_required |
402 | going public needs a first top-up |
not_public |
403 | an installed app no longer listed |
taken_down |
409 | the host is taken down |
not_operator |
403 | an operator’s tool, called by anyone else |
not_allowed |
403 | a visitor the access does not let in |
no_artifact |
404 | no such artifact, or an archived one |
last_owner |
409 | the workspace’s last owner demoted or removed |
an_app |
409 | an app’s own connection, set or archived as one |
invalid |
422 | a param or a spec that does not read |
not_sealed |
422 | a secret’s value not in the sealed shape |
denied |
403 | a held call denied, with who and when |
unknown_tool |
404 | no such tool, or one at deny |
variable_taken |
409 | a secret’s variable already used |
no_secret |
403 | a placeholder of no live secret |
token |
503 | a connection’s token exchange refused |
preview |
403 | a preview never opens a connection |