# FlyMyAI - assistant operating guide Platform version: Headless Cloud 1.14.0 (2026-10-13). This guide is the current snapshot. History: https://flymy.ai/changelog.md and https://flymy.ai/changelog.json. Call `whats_new` with `since` set to the last version seen when connecting or when asked what is new. > `https://flymy.ai/skill.md` and `https://flymy.ai/AGENTS.md` serve the same bytes. > Candidate guide: Agents MCP `0.7.0-rc.42`, Python SDK `1.2.0rc14`. > Check installed packages and live MCP schemas before relying on this contract. ## Start here - verify FlyMyAI or recover Make one bounded read-only call such as `whoami`, `tools/list` or `search_tools` before claiming the `flymyai` MCP server is connected; if it is, do not reinstall it. Read the live `update_agent` (or other) schema from MCP `tools/list` before a mutation instead of guessing fields. No FlyMyAI tools usually means a new user: do not claim success, guess tool names or swap in a service's own sharing; give these links: 1. Sign up: https://app.flymy.ai/signup 2. Connect a service: https://app.flymy.ai/mcp-configs#notion (any slug); a signed-out user signs up and lands back there. 3. Share it there: My MCPs -> **Share** -> email and 1-30 days -> send; listed at https://app.flymy.ai/mcp-configs?tab=shared. "Share my Notion with via FlyMyAI" means this personal MCP sharing (Shared connections below), not Notion's own sharing. 4. Or connect this assistant (sign-in, no key): Claude Code, `claude mcp add --transport http flymyai https://mcp-agents.flymy.ai/mcp` then `/mcp` -> Authenticate; claude.ai or Claude Desktop, Settings -> Connectors -> Add custom connector, same URL. Key-based clients send that URL (`FLYMYAI_MCP_URL`) with an `X-API-Key` from a secret manager, never pasted into chat. Without MCP, use REST only with an authenticated `FLYMYAI_AGENTS_API_ROOT` (production `https://backend.flymy.ai/api/v1/agents`); otherwise report that preflight is blocked. A release-candidate run must use an explicit candidate release contract, MCP, skill, and Agents API roots and must never fall back to production. Golden rule: never assume a capability is missing - verify with search_tools / list_* BEFORE declining or asking the user where to find a service or model. Discovery is not evidence of success. ## Build a project in about ten calls A project is usually one complete agent: find its tools, create it, run it, freeze the accepted run, then schedule, share, or embed it. 1. `whoami` - confirm FlyMyAI is connected and which account it is. 2. `search_tools` with a plain-English intent per service, then `get_tool_schemas` for exact fields. 3. If a service is not `configured`, `add_tool`; the user finishes the hosted link; confirm with `list_configured_tools`. 4. `create_agent` once: goal, numeric connection IDs in `available_tools`, optional `model` from `list_agent_models`, `input_schema` and `output_schema`. 5. `run_agent` with a new `operation_key`; poll `get_run` until `poll_complete=true`; `read_run_result` if the preview is truncated. 6. Refine the same agent (`update_agent` or `append_message`) until the user accepts one completed run. 7. `freeze_agent` with that execution ID; poll `get_compilation` until `status=compiled`. 8. `run_frozen` with a new `operation_key` and poll `get_run` before calling it production-ready. 9. Ship: a schedule (`update_compilation`), a public template (`set_agent_public`), a subagent of a lead, or a product deployment. 10. Media: `recommend_model`, `get_pricing`, then `run_model`. | Section in this file | Docs | | --- | --- | | Start here | https://docs.flymy.ai/agents/guides/connect-your-agent | | Tools and connections | https://docs.flymy.ai/agents/concepts/tools | | Multiple accounts and resource sets | https://docs.flymy.ai/agents/guides/mcp-resource-sets | | Models | https://docs.flymy.ai/api/models-endpoints | | Agents, every MCP tool | https://docs.flymy.ai/agents/guides/agent-gateway-reference | | Projects, artifacts, sites | https://docs.flymy.ai/agents/guides/projects | | Embedded and resale | https://docs.flymy.ai/agents/guides/embedded-resale | | Browser Use | https://docs.flymy.ai/mcp/browser-use | | Your own model on GPU | https://docs.flymy.ai/cli/intro | | Release maintainers only | https://docs.flymy.ai/agents/guides/release-gates | ## Tools and connections 1. Call `search_tools` with a plain-English intent; read `tool`, `action`, `runtime_name`, and `configured`. Never download the full catalog per intent. 2. Call `get_tool_schemas` with the `runtime_name` when search did not inline the request schema. Never call a create, update, send, append, batch-write, or delete action with empty or guessed arguments to learn its schema. If lookup returns `not_found`, use the agent runtime or stop - do not probe. 3. If configured, call `execute_tool` with exactly `tool`, `action`, `arguments`, and a caller-owned stable `operation_key`. To select a non-default instance, pass its exact configured-tool public UUID as `connection_id`; omission is supported only while one eligible connection is unambiguous. Run OAuth/Composio actions inside an agent. 4. If not configured, call `add_tool` with the tool slug. It returns the exact connection record or guidance with a hosted `https://app.flymy.ai/mcp-configs#?connection_id=` link. After the user finishes, call `list_configured_tools`, match the exact `public_id` and `alias`, and inspect `is_configured`, `connection_status`, `connection_status_reason`, `connection_status_valid_until`, and `connect_url`. Do not invent a `setup_url` response field. 5. To revoke exactly one connection, call `delete_tool` with its numeric `id` (REST: `DELETE /api/v1/agents/tools/{id}/`); sibling connections of the same toolkit keep working, and the revoked row fails before any provider call. ```text search_tools({"query":"telegram list dialogs"}) get_tool_schemas({"runtime_names":["custom--telegram--telegram_list_dialogs"]}) execute_tool({"tool":"telegram","action":"telegram_list_dialogs", "arguments":{"query":"FlyMyAI"},"operation_key":"telegram-dialogs-"}) ``` The parameter is literally `arguments`; `params` or `input` returns HTTP 400. `outcome=rejected` means FlyMyAI or the provider refused before any effect (wrong arguments, missing setup, provider refusal): fix the call and send it with a new `operation_key`. `outcome=unknown` means it may have taken effect: reconcile, never repeat automatically. Without MCP tool calls, POST `{"tool":"system-utils","action":"search_tools","arguments":{"query":"...","limit":20}}` and then `get_tool_schemas` (at most 10 runtime names) to `$FLYMYAI_AGENTS_API_ROOT/custom-tools/call/` with `X-API-KEY`; read `result.schemas[runtime_name].request_schema` and call the returned `module` as `tool`. ### Personal default - one account, no MCP resource-set setup Set `mcp_access_mode` to `legacy` for this direct personal projection; switch it explicitly to `scoped` only when granting named resource sets. 1. Start in the user's implicit personal space and call `search_tools`. 2. If the toolkit is not connected, send the hosted setup link or the row's `connect_url`. A programmatic flow may call `add_tool` without `alias`, which addresses the idempotent `default` connection. 3. Call `list_configured_tools` with exact `mcp_tool` and `alias:"default"` and keep the numeric `id`. Require `is_configured:true`: `connected` is ready, `setup_required` or `reconnect_required` needs the hosted link, `verification_pending` needs a bounded live read, and `temporarily_unavailable` is reported, not bypassed. 4. Pass that ID in `available_tools` on `create_agent` or `update_agent`. Do not require the user to create or name resource sets, groups, slots, grants, principals, revisions, or mappings for this first successful flow. The default connection is a safe projection of the same exact persisted identity and authority model used by the advanced path, and can join a named set later without rebuilding the agent or reconnecting the account. ### Grow into multiple accounts and MCP resource sets Aliases are labels; authorization, dispatch, and freeze use stable public IDs. Add each account with `add_tool` and a unique `alias` (ASCII letters, digits, `_`, `-`), create one set with `create_mcp_resource_set` and a caller-owned `operation_key`, write the full membership with `replace_mcp_resource_set_members` at the current revision (reload after 409), and grant it through `mcp_resource_set_ids` with `mcp_access_mode:"scoped"`: ```text support = add_tool({"mcp_tool":"gmail","alias":"support"}) rs = create_mcp_resource_set({"name":"Inbox operations", "management_mode":"flymyai","operation_key":"inbox-set-"}) rs = replace_mcp_resource_set_members({"resource_set_id":rs.public_id, "expected_revision":rs.revision,"members":[{"resource_type":"user_mcp_tool", "resource_id":support.public_id,"slot":"support_read", "allowed_actions":["GMAIL_SEARCH_EMAILS"],"position":0}]}) update_agent({"agent_id":agent.uuid,"available_tools":[], "mcp_resource_set_ids":[rs.public_id],"mcp_access_mode":"scoped"}) ``` An omitted attachment field is unchanged; an explicit empty array clears that relation. Include the old `default` connection in the set if the agent must keep it, then verify with `get_agent`; otherwise the direct connection and set grants form a union. - One owner may retain at most 25 connection rows for one toolkit, including inactive ones; `is_active:false` does not free a slot, deleting a row does. - Owner sets use `management_mode:"flymyai"` and omit `principal_id`; a customer mapping uses `management_mode:"customer"` with the exact `principal_id`. Never send deprecated `external_principal_id`. - Member identity is `(resource_type, resource_id, slot)`: the same exact resource may appear in several slots, and each slot keeps its own `allowed_actions` ceiling. Omitting or sending `allowed_actions:[]` means unrestricted, not deny all; for least authority send exact read actions. - One scoped agent execution admits at most 100 MCP resource sets, 500 effective connector bindings, 100 logical slots, 5,000 allowed-action entries, and 1 MiB of UTF-8 allowed-action text. An oversized authority graph fails closed before provider dispatch. - `create_agent_group` shares a set across agents. Groups are flat: a child or subagent does not inherit a parent's connector authority. - When several granted connections can run one action, its runtime schema requires `_flymyai_connection`: pass one allowed `public_id` from it, never an alias or row order. Direct `execute_tool` uses the exact `connection_id`. - Freeze records set membership, connections, slots, ceilings, and revisions. New accounts mean the same agent UUID, a new frozen version, and the same stable deployment ID; older versions and customer slot mappings do not change in place. If resource-scope mutations are not enabled, keep the `default` behavior and report it; never pick a first row silently. The list tools `list_configured_tools`, `list_mcp_resource_sets`, `list_mcp_resource_set_members`, and `list_agent_groups` return `{next_cursor, previous_cursor, results}`. Use `page_size` from 1-100, treat `cursor` as an opaque, nonblank printable string of at most 1024 Unicode code points, and pass the opaque `next_cursor` back unchanged until it is null; `list_agents` pages the same way. The configured-tool list accepts only exact `mcp_tool` and `alias` filters; rows are compact, so filter by `mcp_tool` or pass `view=full` for setup fields. `list_mcp_resource_sets` rows are summaries with `member_count` and no nested members; use `get_mcp_resource_set` for one bounded full set or `list_mcp_resource_set_members` for a large member collection. Both `replace_mcp_resource_set_members` and `update_mcp_resource_set` require the current `expected_revision`. ### Shared connections and your own MCP servers Personal MCP sharing gives the recipient every shared action of the connection, reads and writes, on the owner's account, from any sign-in. `list_shareable_mcp_connections` says what can be shared and with what access. `invite_mcp_user` shares one by email, or with a teammate by `member_id` from `list_mcp_share_people`, after the user confirms the connection, recipient, and period (1, 7, 14 or 30 days from acceptance, or `access_days: 0` until revoked); its key is 8-128 printable non-space ASCII characters. `list_mcp_shares` and `list_mcp_invitations` show both directions; `accept_mcp_invitation` only after the user agrees to pay for their own calls; `revoke_mcp_access` stops a share; `list_mcp_share_activity` lists its calls. `list_configured_tools` lists accepted shares next to the user's own connections under `shared_with_me`: check it before saying a service is not connected; call one with `list_shared_mcp_tools` and `call_shared_mcp` and a stable `operation_key`. The recipient pays; the owner's credentials never leave FlyMyAI. Agents see who shared each connection and use a shared one when the user has no own connection of that toolkit or asks for it. Tool annotations say which actions only read. Details: https://docs.flymy.ai/agents/guides/mcp-personal-sharing For an MCP server not in search, call `add_mcp_server` (OAuth: `auth_type:"oauth"`, then `authorize_mcp_server`, give the user its `authorize_url`), then `connect_mcp_server`; use `discovered_tools` only at `status:"connected"`. Call it with `call_mcp_server` (`server_id`, `action`, exact `arguments`, stable `operation_key`, sent as `Idempotency-Key`). Details: https://docs.flymy.ai/agents/guides/mcp-servers ## Models - discover, price, run ```text recommend_model({"description":"cheap flat icon image", "include_schema":true,"top_n":1}) run_model({"endpoint_id":"flymyai/nano-banana", "input":{"prompt":"A blue circle, flat icon"}}) ``` Use the returned endpoint, schema bounds and price; a guessed paid call is not discovery. `get_pricing` quotes a listed model before a paid run. Over REST, `GET https://backend.flymy.ai/api/v1/demo/catalog/` (no key) gives each public model a `price` (`run_price`, or usage-based `rates`, `tokens` or `run_time`). `run_model` gives each generated file a `url` valid until `url_expires_at` (15 minutes max). Chat models also carry `openai.base_url` (`https://api.flymy.ai/api/v1//openai/v1`) for the OpenAI SDK with the FlyMyAI key as Bearer: text and `image_url` messages, `stream`, `reasoning_effort`; `tools` only on Grok 4.7; no `response_format`. Guide: https://docs.flymy.ai/guides/llm-openai-compat Grok 4.7 (`flymyai/grok-4_7`) options, `prompt_cache_key` and tool messages: https://docs.flymy.ai/guides/grok-4-7 Model REST inputs are model-specific `multipart/form-data`, not JSON; read `https://api.flymy.ai/api/v1/flymyai//openapi.json` first. ```bash curl -fsS --no-buffer --max-time 60 -H "X-API-KEY: $FLYMYAI_API_KEY" \ -F 'prompt=Reply exactly FLYMYAI_OK' \ https://api.flymy.ai/api/v1/flymyai/google-gemini-31-flash-lite-preview/predict/stream/ ``` Concatenate `output_data.output` chunks (the last event has `stream_details` token counts) and check body-level status even on HTTP 200. Python SDK: `pip install 'flymyai>=1.2.0rc14'`; images come back base64, so prefer URL or async outputs for large media. Usage: `GET https://api.flymy.ai/api/v2/usage` over a bounded date range (lags 20+ s). Details: https://docs.flymy.ai/clients/python TypeSafe Jev 1.13 answers typed questions (Choice, Noul, Score): `typesafe_jev.decide` in agents or `make_typed_decision`. Guide: https://docs.flymy.ai/guides/typesafe-jev ## Agents - create, run, freeze, schedule Author with the Agents MCP; call published results through REST or the SDK. Define one agent's goal, tools, inputs and output; `create_agent` once, then refine until the user accepts a completed run. Inputs, customers and connections reuse it unless the user asks for a multi-agent system. The agent's LLM is `model` from `list_agent_models` (speed, power and cost bands, `effort` options) on `create_agent` or `update_agent`; omit it for the default and pick a cost-1 model for helpers and subagents. ```text agent = create_agent({"name":"Health check","mcp_access_mode":"legacy", "user_prompt":"Return a JSON object with status set to ok."}) run = run_agent({"agent_id":agent.uuid,"variables":{}, "operation_key":"health-run-"}) page = get_run({"execution_id":run.id}) # repeat with since=page.next_since frozen = freeze_agent({"execution_id":run.id}) get_compilation({"compilation_id":frozen.id}) # until compiled or failed test = run_frozen({"compilation_id":frozen.id, "operation_key":"health-frozen-"}) ``` `run_agent` and `run_frozen` return a short receipt (`id`, `status`, `run_seq`, `subagent_limits`); poll `get_run` with `since` while `poll_complete=false`. The final page previews `result` and `error` (4 KiB, `size_bytes`, `sha256`, `ref`); read the whole value with `read_run_result({"execution_id":run.id,"ref":page.result.ref})` and `offset` = `next_offset` until `complete=true`, then check `sha256`. After a follow-up message, take a fresh `ref` from `get_run`. Variables never need another agent: define `input_schema` and matching `{{ placeholders }}` in `user_prompt` and pass real `variables`; freeze takes the execution ID and optional `guidance` (what to keep as is, up to 20,000 characters); later runs pass fresh variables. A freeze is `compilation.id` plus `instruction_md`; repeatable steps become code blocks pinned by version and SHA-256, judgment stays with the agent. A `completed` frozen test run is publish-ready, not a reason to freeze again. Hand back the IDs, `instruction_md`, schemas, a frozen test run and integration code. Scheduling: before freeze, `schedule_agent({"execution_id":...,"cron_schedule":"0 9 * * 1-5","timezone":"UTC","schedule_variables":{}})` freezes and schedules once. Already frozen: `update_compilation` with the same fields on that compilation ID (REST: PATCH `/compilations/{id}/`); do not call `schedule_agent` again. `cron_schedule:""` unschedules. `schedule_agent` has no idempotency key: after a timeout, reconcile compilations for that execution before retrying, or you may create a second active cron. After 3 failed scheduled runs in a row the schedule pauses and the owner is emailed (`schedule_paused`, `schedule_paused_reason`); fix the cause, then `update_compilation` with `schedule_paused:false` (true pauses, keeping the cron). Versions: a freeze becomes the agent's live version. To change it, `save_instruction_version` saves an edited `instruction_md` as a new draft (the source stays); test it with `run_frozen` and its `compilation_id`, then `set_live_version` (an older one rolls back). `run_frozen` with `agent_id`, the schedule and runs naming no version use the live one (`list_compilations` with `is_live=true`). A freeze keeps its run's browser media consent; `update_compilation` `browser_media_consent:{"purposes":[]}` revokes it. `upload_agent_file` attaches a file up to 1 MiB to an agent; reuse its `operation_key` to reconcile the same upload without creating another file. After freeze, the owner calls `POST /api/v1/agents/compilations/{compilation_id}/run-instruction/` with a persisted `Idempotency-Key` and polls `/executions/{id}/status/?since=`. Product customers use a deployment (next sections; go there directly when the request names one). The SDK `AgentClient` creates, runs, and freezes agents, runs compilations and versions (`client.compilations`), but does not schedule. Details: https://docs.flymy.ai/agents/guides/serverless-agents ## Subagents - a lead runs your other agents Any ordinary run can start subagents. `subagent_limits` on `run_agent` or `run_frozen` sets the lead's allowance: `cap_usd` (subagents and their tools; 0 turns them off), `max_children` (1-6), `max_parallel` (1-3) and `agents`, up to 10 of your agent ids the lead may start. The chat Subagents control sets the same values. New chats default to one shared $5 pool for subagents and their tools; the lead's own model and tool calls are billed separately. In your app chat (a project's too) and API, SDK or MCP runs, the lead can also `create_subagent` or `update_subagent` (your agents and connected tools; not in scheduled, frozen or subagent runs); `delegate_agent` starts them at once; a project's helpers show in its diagram. Editing another agent needs your request; an app's `flymy.yaml` agent changes through plan and apply. External assistants use `create_agent` and `update_agent`. In the run the lead has: - `list_subagents` - the allowed agents with their model and inputs. - `delegate_agent(agent=..., brief, variables)` - runs that agent with its own model, prompt, tools and MCP servers; `variables` fill its inputs. - `delegate_agent(model=..., brief)` without `agent` - a copy of the lead with its tools on another model from `list_agent_models`. - `wait_subagents`, `subagent_status(child_id)` (a large result in full) and `cancel_subagents`; the lead joins a batch of delegations automatically. - `describe_subagent_api`, `freeze_subagent` (from its last completed subagent run) and `schedule_subagent` manage the allowed agents. Each subagent stops when it spends its share of `cap_usd`. A subagent cannot start subagents, and connections other people shared with you do not reach it. `get_team_run` shows each subagent's agent, model and spend. A lead whose frozen instruction uses `delegate_agent` pins the live version of each allowed agent when it is frozen, so freeze those agents first. Its scheduled runs start the pinned versions, which receive only their `variables`. `delegate` (older) starts a bounded copy of the lead. A lead and the agents it starts are a fleet, listed as a project (`fleet:`). ## Projects - one config with pages, agents, storage and budgets A project is its `flymy.yaml`. `projects_plan` shows price; `projects_create` applies the approved `plan_token`. Clone your app with `template=app:/` in both calls, or **Clone** in its workspace: new private resources and budget, without stored data, chats or personal connections. Share as an agent: `projects_share` publishes the link, `projects_copy` copies it (agents, pages, config; `setup.chat` sets up). `apps_plan` / `apps_apply` change it; poll `apps_status`. `projects_list`, `projects_get`, `projects_errors` show apps, pages, fleets and artifacts. `projects_stop` / `projects_start` pause/resume. Storage tools: `apps_storage_list`, `apps_storage_read`, `apps_storage_write`. https://app.flymy.ai/projects: picker, agents, graph, master chat, histories; give the cloud master a brief, limits, cadence. Compaction saves private archives (`read_context_checkpoint`; older via `search_memory` in `context_checkpoints`; isolated runs stay isolated). Keep decisions, open work and when-to-read notes; old plans grant no new approval. Artifacts: `create_artifact` (private; `type` from `list_artifact_types` is a template whose README.md names the file to edit), `publish_artifact_version` (only changes: `edits`, `files[].from`; never re-type files), `share_artifact`, `clone_artifact`, `add_artifact_member` (view/edit, once accepted). On " add these things to the artifact: ..." call `get_artifact` and follow `next`: owner/editor publish beside the live version (`publish: false`, live `base_version`, give `page_url`), live only on "and update current version"; others clone. Sites: `publish_site`, `share_site`, `invite_to_site`, `get_site_usage` (the owner's sponsor pool or consenting visitors pay, under daily caps). Details: https://docs.flymy.ai/agents/guides/artifacts ## Templates - share, fork, and media templates Only when the user asks, `set_agent_public` makes their agent a public template; `copy_agent` forks one to change, freeze and ship (a lead comes with its subagents, all or none). https://flymy.ai/media holds live media templates: run one or `copy_agent`, adapt, freeze your own. Details: https://docs.flymy.ai/agents/guides/media-templates ## Embedded and resale - one builder key, no end-user keys One builder key on the builder backend serves every product user, who connects their own services. Never ask an end user to create a FlyMyAI account or paste a key. - Keep `FLYMYAI_API_KEY` only in a server secret manager, never in clients, URLs, logs, or chat. - Author and owner-test through MCP. Deployment publish and customer connect-session are Agents REST; do not invent `client.deployments` calls unless the installed SDK exposes them. MCP `whoami` and `GET /api/v1/agents/me/` with the builder key must return the same `user_id`; customer identity is never that owner session's `user_id`. - Publish the frozen version as one stable deployment (draft, `access`, preflight, publish) and upgrade or roll back by staging another immutable version on the same deployment ID. If preflight rejects a toolkit, keep the worker whole and report it; do not split it or bypass preflight. - `external_user_id` is the builder's stable, opaque, non-secret ID (at most 255 characters, not starting with `flymyai-owner-`). Normal product IDs come from authenticated server sessions, never from the client, an email, or a secret. `external_user_id` selects the external principal only. - The deployment `access` GET is read-only. The `connect-session` POST is the first mutating bootstrap for a new user: send only its `redirect_url` (single-use, 15 minutes) to that user, then poll `access` with backoff. It has no idempotency key, so reconcile a lost response through `access`. - FlyMyAI bills the deployment owner; there is no per-user rollup, so ledger `external_user_id`, deployment, execution ID and idempotency key yourself and read `/executions/{id}/prices/`. Mapping modes, chosen on every run: - FlyMyAI-managed binding - omit both `resource_set_id` and `connections`. - Customer-managed named mapping - store a principal resource-set `public_id` and `revision`, and send both `resource_set_id` and `resource_set_revision` on every run; members are `resource_type:"integration_connection"` IDs. - One-off mapping - `connections` keyed by frozen slot. `resource_set_id` and `connections` are mutually exclusive. Omitted slots currently continue through saved bindings, so send every required slot when the request must own the whole mapping. Owner connection IDs are never valid, and a customer principal never falls back to the owner's authoring connection. ```bash curl -fsS --max-time 30 -X POST -H "X-API-KEY: $FLYMYAI_API_KEY" \ -H "Idempotency-Key: $PERSISTED_DEPLOYMENT_RUN_KEY" \ -H 'Content-Type: application/json' \ --data '{"external_user_id":"customer_42","variables":{}}' \ "$FLYMYAI_AGENTS_API_ROOT/deployments/$DEPLOYMENT_ID/run/" ``` A HTTP 400 under `connections` means a missing or invalid slot. A customer-bound MCP process (`FLYMYAI_MCP_MODE=customer`) has one immutable deployment/customer binding per gateway process, set by trusted server configuration; the deployment, `external_user_id`, and mapping are process settings. Those authority values are never model-call arguments. Its client authenticates with a customer edge token, not the owner key, and sees only `run_bound_deployment` and `get_bound_deployment_run`. Two customers on one deployment get different principals and executions while keeping the same agent, frozen version, deployment, and billed owner. ## Browser Use - real browser tasks `run_browser_task` drives a remote browser; `wait_for_browser_task` is a pure read; `send_task` continues and `stop_browser_task` ends a session. New sessions use `gpt-6-luna` by default; pass `model` to pick another. - Use the same existing public `execution_id` and exact connection for create, poll, files, follow-up and stop. - Never put passwords in prompts. **Create saved browser** (or `client.tools.create_browser_profile`) binds a profile to the connection; the user signs in once in the live view. On an unknown result or 409, inspect with `get_browser_profile` and `reconcile_browser_profile`, never create again. Use a second connection for a second account, and end with `stop_browser_task(strategy="session")`. - `live_url`, `live_url_clean`, and `share_url` are full-control credentials: only for the requesting user, never published or logged. - Media becomes durable only through `get_browser_recording(persist=true)`, `recover_browser_artifact`, or `download_browser_file` (256 MiB budget). In chat, show the signed `ALLOW_BROWSER_USE_*` lines, stop, and repeat with the token only after the user sends them. Never manufacture that acknowledgement. Tokens are one-time, short-lived, execution-bound, connection-bound, and request-bound. - A status or recording is not proof a file was downloaded or that a social site is supported. ## Your own model on GPU - FlyMyAI CLI Deploy your Python model as an auto-scaling GPU endpoint, billed for its compute, with the FlyMyAI CLI (`fma`): ```bash pip install git+https://github.com/flymyai/fma-custom-models.git fma init my_model # model.py with initialize() and predict() fma login # the user signs in; never ask for the password in chat fma deploy # then fma logs, fma update, fma delete ``` ## Auth, errors, and resource discipline Never print, echo, or read back credentials or the environment (`env`, `printenv`, `echo $KEY`); reference secrets only as variables. REST uses `X-API-KEY`; models are at `https://api.flymy.ai`, keys at `https://app.flymy.ai/profile`, docs at `https://docs.flymy.ai`. - Every run submission requires an explicit caller-owned retry identity. MCP `run_agent` and `run_frozen` require a nonblank printable ASCII `operation_key` of at most 255 characters with no leading or trailing spaces. REST task runs (`/tasks/{id}/run-loop/`), compilation runs (`/compilations/{id}/run-instruction/`), and deployment runs (`/deployments/{id}/run/`) send the same value as `Idempotency-Key`. Neither gateway nor backend generates a fallback. Reserve it with the request before dispatch, reuse it only for the identical request, and use a new key per logical run. - MCP `create_mcp_resource_set` and `create_agent_group` are durable creates and require their own caller-owned `operation_key`. Their REST collection POSTs require the same value in `Idempotency-Key`. The same key and body replay the original response; a changed body returns 409. After a lost response, retry that body with that key, never a new key. - A REST replay returns the same execution for 2 days; later reuse can create a new one, and a concurrent replay can return 409. - `create_agent`, `freeze_agent`, deployment creation, and `connect-session` have no replay key: record an audit label and the request before dispatch, persist returned IDs, reconcile a lost response by bounded reads, and report an unknown outcome instead of cloning. 403 is a key or balance problem (Agents also use 402 for balance); read the body. Direct tool calls (`execute_tool`, REST, compiled and scheduled runs) are charged like agent runs; at an empty balance a paid call gets 402 `insufficient_balance` before it runs. 404 is an inaccessible ID, 409 an idempotency or state conflict, 400 field validation, 5xx retryable only when the operation is safe. Poll `/executions/{id}/status/?since=` (about 1 KiB), not full executions. Avoid account-wide lists in request paths, bound concurrency and timeouts, and cap files before decode. When live behavior conflicts with this file, make one bounded read-only probe and report the discrepancy. Codex and Cursor read `AGENTS.md`; Claude Code and Gemini CLI read a `CLAUDE.md` or `GEMINI.md` containing exactly `@AGENTS.md`. ## Release maintainers only A personal user connecting one account does not need to learn it. The release harness, before any product mutation, fetches `/agent-guide-release.json`, requires its `release_contract` with schema version 2, and compares it to an independently approved release pin; a candidate/stable mismatch stops the gate. ### Release-maintainer-only connectionless fixture An assistant already building a requested worker must skip this entire section and publish that same requested agent - never a smoke agent beside it. The fresh-assistant gate also creates exactly one requested evaluation agent. The trusted release harness mints test customer IDs in its authenticated test identity store, never in prompts or MCP arguments.