Deploy your project
DeploymentDeploy to staging on Flow, check the release and promote it to production. Read the replies graded wrong, list and delete projects. What the hosted agent gets: environment, routes, model, storage and limits.
Deploy the starter to Flow, test the staged version and promote it without rebuilding. To run on your own infrastructure instead, follow the self-hosting guide. Flow cloud’s plans (Starter and Pro) and their prices are in Paid plans.
Deploy on Flow
Section titled “Deploy on Flow”Set up the project
From the agent’s folder, sign in and set up its keys if you have not already:
npx @flow-engineer/flow loginnpx @flow-engineer/flow setupThe deploy command authenticates with the agent’s CI key, FLOW_FRAMEWORK_CLOUD_KEY, which
setup writes into .env. The starter’s buildAgent already accepts options.host and
passes it to createAgent as host: options.host.
Deploy to staging
npx @flow-engineer/flow deploynpx @flow-engineer/flow deploy statusdeploy sends the project’s .env values as secrets, builds the agent and follows the
deployment to live. The default environment is staging.
Check it worked: deploy status shows the live version and the agent’s public URL.
Exercise a request, then inspect its log lines:
npx @flow-engineer/flow logs --since 15mPromote the checked version
After checking staging, promote its live version:
npx @flow-engineer/flow deploy promotePromotion uses the staged version without a new build. Production has its own secrets.
Give production its own Flow Messaging key: a live key (fk_live_...) of the app. With the same
FLOW_MESSAGING_KEY in both, staging and production both open the app’s event stream for that
mode, both get every message, and both answer it, so each person gets two replies. A test key
reaches only the app’s test-mode contacts (the sandbox), so the free trial’s Telegram, WhatsApp and
iMessage people reach staging alone while production holds a live key. Set it with
npx @flow-engineer/flow deploy secret FLOW_MESSAGING_KEY --env production before you promote.
Find replies graded wrong
Section titled “Find replies graded wrong”Flow grades each reply the hosted agent sends: good, unhelpful or wrong, with the rule it broke, why, and the words it was graded on. Read the grades from the agent’s folder:
npx @flow-engineer/flow conversations --grade wrong --since 7dnpx @flow-engineer/flow conversations show cnv_1npx @flow-engineer/flow issuesCheck it worked: conversations prints one row per conversation, the latest message first,
with its kind (test for flow chat, the playground and flow test, else production) and the
agent version behind its latest reply (- when Flow knows none):
ID LAST MESSAGE CHANNEL KIND VERSION CONTACT MESSAGES WRONG UNHELPFULcnv_1 2026-10-29 09:05:00Z whatsapp production 5f056b6 Contact 4f1c 4 1 0
1 conversation. Read one: flow conversations show <id>conversations show <id> prints the conversation’s version in its header (version 5f056b6 (from its traces)), then one line per message, with each graded reply’s label, rule, reason and quote
under it:
2026-10-29 09:00:00Z person: Can I get a refund?2026-10-29 09:00:04Z agent: Yes, I've refunded you. [tools: find_order] WRONG rule: no-made-up-actions why: It says it refunded, but no refund tool ran. quote: "I've refunded you"A test conversation is never graded and never in Insights, so conversations show says so under
its reply counts (Flow Framework 0.16.0 on): A test conversation (flow chat, the playground or flow test): never graded, never in Insights. A conversation on a test key (staging) says never in Insights.
issues groups the grades into problems, each with the conversations it was seen in and a
suggested fix. Fix the instructions, skill or tool the rule points at, add a
test scenario that plays the conversation, and deploy again.
issues test-case <id> prints the test case Flow proposes for one issue: its rule, the reply it
comes from, the words to include or avoid and the sentences to judge by. It writes no file: write a
scenario in tests/scenarios from it (the sentences as its expect.judge), then run
flow test --only <scenario>.
Under the issues, issues prints your team’s feedback from the last 30 days (Flow Framework 0.14.4
on): test checks a teammate marked out of date on the dashboard, and reply grades they marked wrong.
Feedback from your team (last 30 days): 2 check out of date scenarios/refund.yaml (whatsapp), check 2: Asks for the order number note: We stopped asking for the order number. todo: Change this check in the scenario file. grade marked wrong conversation cnv_1, reply m2, rules no-made-up-actions todo: The reply was fine: do not change the agent for it.Update the scenario check that is out of date; do not change the agent for a grade marked wrong.
On a Flow without team feedback yet, nothing more is printed. --json is still only the issues.
- They read with the agent’s
FLOW_KEY, from.env(or--dotenv <path>), whichflow setupwrites. The key is never printed. Noflow loginis needed. - Contacts show only as a label such as
Contact 4f1c, never a phone number or handle. Text that Flow keeps back prints as(text withheld)or(deleted by retention); messages your own code sent show asyour code. - Without
--env(or--environment), a live key reads production and a test key reads staging.flow setupmakes a test key; for production, make a live key withflow setup --live. - Flags:
--grade wrong|unhelpful|good,--since 30m|24h|7d|<RFC 3339 time>,--contact <label>(one contact’s conversations),--limit <n>(default 20, at most 1000, asked for 100 a page and followed over as many pages as it takes),issues --status open|resolved|ignored|all(default open), and--jsonfor the server’s JSON (pages of conversations merged into one). - Exit codes: 0 when it printed, 1 for no
FLOW_KEYor a server that refused or could not be reached, 2 for a wrong flag, with the server’s message and hint. With--jsonthe failure is one{ ok: false, error, next }document on stdout.
Read production with a live key
Section titled “Read production with a live key”flow setup’s test key reads staging only. To read production conversations and Insights, the
workspace’s owner makes the agent’s live key once, from its folder (Framework 0.16.0 on; it needs
flow login):
npx @flow-engineer/flow setup --liveCheck it worked: the key is in .env as FLOW_LIVE_KEY, printed only by its prefix and last 4,
then what it can do:
In .env: FLOW_LIVE_KEY=flow_live_…R3ad addedWorkspace: Team (acc_team1)Text: de-identified (names, phones, emails, ids, addresses are placeholders)What it can do: ✓ Read conversations (names and numbers hidden) ✗ Read raw message text npx @flow-engineer/flow keys grant content ✓ Read Insights ✓ Run tests ✗ Message customers npx @flow-engineer/flow keys grant send ✗ Deploy live npx @flow-engineer/flow keys grant deploy ✓ Write traces ✓ Use Flow's modelProduction reads (npx @flow-engineer/flow conversations --environment production, npx @flow-engineer/flow insights) use it.It stops working at 2026-12-04T10:00:00Z, 30 days after it was made, or after 7 days unused: then run npx @flow-engineer/flow setup --live again.Revoke it: npx @flow-engineer/flow keys revoke k7Qm2xR9aBFine by default, granted at once: de-identified reads, Insights, tests, traces, the model.Only when the user asked for it: raw message text (npx @flow-engineer/flow keys grant content).Only with the user's explicit yes: messaging customers and deploying live (npx @flow-engineer/flow keys grant send | deploy); the owner confirms once in the browser.Next: npx @flow-engineer/flow insights, then npx @flow-engineer/flow conversations --environment productionEach read then takes its key by rule; the environment wins over .env:
| Command | Key it reads with |
|---|---|
conversations (staging, or no --env), issues, templates | FLOW_KEY |
conversations --env production, insights, insights show | FLOW_LIVE_KEY when set, else FLOW_KEY |
conversations show <id> | FLOW_KEY, then FLOW_LIVE_KEY once when FLOW_KEY does not find the id; with --env production, FLOW_LIVE_KEY first |
test, show, deploy, logs, cli publish|rollback|status | the CI key, FLOW_FRAMEWORK_CLOUD_KEY |
The live key’s limits:
- Only the workspace’s owner makes one (
owner_only), and a health workspace gets none (health_workspace). Set up the agent in that workspace first (not_set_up: runflow setup).observe_failed(exit 2) made no key: try again. Each refusal prints its next step. - Safe defaults. It reads, runs tests, writes traces and uses the model. It messages no customer and deploys nothing live until you grant that (below).
- Text is de-identified unless you add
--content: names, phone numbers, emails, ids and addresses read as placeholders. A workspace whose text must stay de-identified refuses--content(content_not_allowed). Every read prints oneText: raw,de-identifiedorwithheldline first, and--jsoncarries it astext_mode(theFlow-Textheader). - One live key per agent. A new
setup --livereplaces the agent’s earlier live key at once and names it (“It replaced the agent’s earlier live key …”). - It lasts 30 days, and stops after 7 days unused. A refused live key (401) is expired, idle
or revoked: run
flow setup --liveagain. Keep it in.envlikeFLOW_KEY, and never commit it.
Grant a live key more
Section titled “Grant a live key more”flow keys grant <name> lets the live key do one more thing, in place: the key’s value stays the
same. It changes the FLOW_LIVE_KEY in .env (or --key <kid>). Only a key made by
flow setup --live takes grants (not_for_this_key). Each name has a tier, and the CLI, its help
and flow mcp serve’s tool descriptions say the same words:
| Tier | Names | What happens |
|---|---|---|
| Fine by default | read, tests, traces, model | Granted at once. |
| Only when the user asked | content (raw message text) | Granted at once, where the workspace allows raw text. |
| Only with the user’s explicit yes | send (message customers), deploy (deploy live) | The owner approves once in the browser. |
npx @flow-engineer/flow keys grant send --waitCheck it worked: the CLI prints the approval page and opens it (--no-browser only prints it).
Without --wait it exits 4 while the approval waits; with --wait it asks again until the owner
approves, then prints the key’s new checklist:
Messaging customers needs the owner's yes in the browser.Only with the user's explicit yes: messaging customers and deploying live (npx @flow-engineer/flow keys grant send | deploy); the owner confirms once in the browser.Opened your browser at https://flow.engineer/cli/keys/approve?g=kgr_...The approval page works until 2026-11-04T10:15:00Z.Approved: k7Qm2xR9aB has send now.What it can do now: ... ✓ Message customers ...A denied or expired approval exits 3 (grant_denied, grant_expired). A coding agent that hits a
refusal for something its key was not granted (403, such as “can’t message customers”) gets Flow’s
hint naming the keys grant to ask for, and the three tiers.
List, show and revoke keys
Section titled “List, show and revoke keys”flow keys list (or flow keys) lists the live keys of the agent in the folder you run it from,
never their values. The folder’s agent is the one its FLOW_KEY or FLOW_LIVE_KEY belongs to, else
its package.json name; outside an agent’s folder it lists every agent’s. --agent <name> lists one
agent’s, --all every agent’s on your account. --json prints { keys, agent, all } and nothing
else:
KID AGENT MODE KEY EXPIRESk7Qm2xR9aB cafe live …R3ad 2026-12-04 10:00flow keys show <kid> prints one key’s checklist (✓/✗, the same lines for every key) and what was
granted to it, when and by whom. flow keys revoke <kid> ends one at once.
Find where people gave up or got annoyed
Section titled “Find where people gave up or got annoyed”Flow Insights reads whole conversations, not single replies: where people gave up, asked again, asked for a person or got annoyed, grouped by topic. These are the findings the dashboard’s Insights page shows (Flow Framework 0.16.0 on):
npx @flow-engineer/flow insightsnpx @flow-engineer/flow insights show fnd_1npx @flow-engineer/flow conversations show cnv_1Check it worked: insights prints the open findings, ranked as the dashboard ranks them, each
with its conversations in the window and the window before’s:
ID STATUS CONVERSATIONS TOPIC FINDINGfnd_1 open 4 (was 9) Refunds Got annoyed when the agent got a fact wrongfnd_2 open 3 - Unanswered
Last 7 days: 132 closed sessions from 87 people.Low-confidence tags, left out above: fnd_3 Frustrated (5).Read one: flow insights show <finding>insights show <finding> prints the finding’s conversations, each with why it was flagged, the
person’s words when your account’s data allows, and the command that reads it:
fnd_1 open Got annoyed when the agent got a fact wrong · Refunds: 4 (was 9) conversations in the last 7 days
cnv_1 2026-10-29 09:00:00Z Got annoyed when the agent got a fact wrong "That's not my order" next: flow conversations show cnv_1Read the conversations to tell whether the finding is real, fix the instructions, skill or tool
behind it, add a test scenario that plays one, run flow test and deploy. Once a
window has passed, run insights again: the finding’s count should drop.
- What Insights reads: closed production conversations (quiet for 24 hours) on a live key.
Conversations on a test key, in
flow chat, the playground orflow testare never graded. Until 20 closed sessions, Insights shows counts only, with no rates or topics, and saysCollecting. With nothing to read it says what makes data. - Flags:
--days 7|30(default 7),--status open|fixed|muted|all(default open, the list only), and--jsonfor the server’s JSON. - Before Insights is open to your workspace, both commands print
Insights is not open to this workspace yetwith the server’s hint, and exit 1. - They need the agent’s live key: Insights is production traffic. They read with
FLOW_LIVE_KEYwhen it is set (Read production with a live key), else aflow_live_FLOW_KEY. With only a test key (flow_test_, whatflow setupwrites) both sayInsights reads production conversations, so it needs a live keywith theflow setup --livecommand, and exit 1. - Exit 0 when it printed, else 1, with the server’s message and hint.
List and delete projects
Section titled “List and delete projects”A project is one agent in a workspace. These commands use your sign-in from flow login:
npx @flow-engineer/flow projects listnpx @flow-engineer/flow projects delete cafeCheck it worked: list prints each project in your workspaces:
NAME WORKSPACE ID CREATED CAN DELETEcafe Team agt_cafe1 2026-10-01 yesshop Team agt_shop1 2026-10-12 no (owner only)delete asks you to type the project’s name, then prints:
Deleted cafe (agt_cafe1) in Team. Its keys stopped working; the Flow team can bring it back until 2026-11-28 10:00 UTC.- Only the organization’s owner can delete a project. Others get exit 3 (
owner_only). - Its keys stop working at once. The Flow team can restore the project for 30 days; ask them
before
restore_until(shown in--json). - Name or id. A name is matched exactly (case-sensitive). When two projects share a name,
deleterefuses and prints both ids: pass the id.--workspace <acc_id>keeps either command to one workspace. - Without a terminal (CI, a coding agent),
deleteasks nothing and needs--yes. Pass it only when the owner has said to delete that project. --jsonprints{"projects": [...]}(id,name,workspace,created_at,owner) or{"project": {...}}withdeleted_atandrestore_until; errors are{"error": {"code", "message", "next"}}.- Exit codes: 0 done; 1 usage, not signed in, no such project, a shared name or not confirmed; 2 flow.engineer could not be reached (try again); 3 refused (owner only, or the sign-in ended).
What your hosted agent gets
Section titled “What your hosted agent gets”The host runs your src/agent.ts as one Node process per environment. It calls
buildAgent({ events, host }), where host carries the host’s store and, when you set
FLOW_MESSAGING_KEY, Flow Messaging’s channels. Everything else comes from the environment below.
A project with only src/mcp.ts runs without a chat agent (An MCP server alone).
Environment
Section titled “Environment”Most agents need only FLOW_AGENT_URL, FLOW_ENVIRONMENT, FLOW_KEY and their own secrets.
| Variable | What it holds |
|---|---|
FLOW_AGENT_URL | The environment’s public HTTPS address, also printed by deploy status. Build webhook and callback URLs from it |
FLOW_ENVIRONMENT | staging or production |
FLOW_KEY | The environment’s runtime key, when your .env has a FLOW_KEY (see below) |
| Your secrets | Every other .env value, under its own name |
FLOW_AGENT_ID, FLOW_AGENT_NAME | The agent’s id and name |
AGENT_VERSION | The deployed version; traces carry it |
PORT | 8080. The host’s runtime listens on it; your code does not open a server |
FLOW_STORE_URL, FLOW_STORE_TOKEN, FLOW_STORE_FRAMEWORK | The host’s store. Use it through host, never directly |
FLOW_API_TOKEN | Protects /nudges and /people |
FLOW_PLAYGROUND_TOKEN | Protects /playground |
CHINWAG_TRACES_URL, CHINWAG_TRACES_KEY | Where traces go; set by Flow |
FLOW_FRAMEWORK_TRACES_CONTENT, CHINWAG_TRACES_CONTENT | Whether traces carry message text: 1, Flow’s default, unless you set your own 0 or 1 (below) |
FLOW_WEB_CHAT_SESSION_KEY | Signs web chat sessions and anonymous visitor ids; one per environment, the same on every deploy |
FLOW_TRUST_PROXY | 1: the web chat reads the visitor’s address from X-Forwarded-For for its limits |
- Names Flow sets are refused as secret names: the ones above except
FLOW_KEYand trace text, plus any name startingFLOW_STORE_,CHINWAG_TRACES_,FLOW_FRAMEWORK_TRACES_orK_, andAGENT_DIR.deploynever sends the CLI’s ownFLOW_FRAMEWORK_CLOUD_KEY. - Trace text is yours, per environment.
deploy statusshows it (trace text: on (Flow's default)oroff (set by you)). To switch it off in production:echo 0 | npx @flow-engineer/flow deploy secret FLOW_FRAMEWORK_TRACES_CONTENT --env production --apply(or without--apply, thennpx @flow-engineer/flow deploy promote). Only0and1are taken;deploydoes not send the.env’s line, whichsetupwrites for local runs. Deleting the secret on the dashboard goes back to Flow’s default. - A secret takes effect on the next deploy or promote, or now with
deploy secret NAME --applyordeploy restart, which restart the live version without a build.deploy secret --unset NAMEtakes one away. Names areUPPER_SNAKE_CASE; values are at most 64 KB.
Flow’s key on hosting
Section titled “Flow’s key on hosting”FLOW_KEY in the hosted process is not the developer key in your .env. When deploy sends it,
Flow exchanges it for a runtime key per environment: scopes messaging, traces and model only,
flow_test_… in staging and flow_live_… in production. The developer key is never stored.
flow deploy secret FLOW_KEYanswers with the runtime key’s last 4, which differ from whatflow linkand your.envshow. That is expected; it is the same account.- A key Flow refuses (revoked, or not a developer key) is not saved and does not stop the deploy. A runtime key the environment already has stays.
Routes
Section titled “Routes”The agent is served at FLOW_AGENT_URL. Hosting adds these paths; every other path goes to your
agent’s own routes:
| Path | Served when | Access |
|---|---|---|
/healthz | Always | Public |
/webhooks/flow-messaging | FLOW_MESSAGING_WEBHOOK_SECRET is set; without it, the host holds Flow Messaging’s event stream | Flow Messaging’s signature |
/nudges, /people | Always | Authorization: Bearer $FLOW_API_TOKEN (nudges over HTTP) |
/playground | Always | Its token; the Flow dashboard opens it for you |
/mcp, /mcp/plugin, /.well-known/oauth-protected-resource, /agent/terminal, and your auth.routes | src/mcp.ts exists | Public: hosting adds no authentication (below) |
/v1/web-chat and everything under it (the channel’s base) | The agent has a webChat() channel (Framework 0.12.0 or later) | Public: the chat box’s script, and starting a session from the sites in origins. Every other call needs that session |
| Any other path | Your createAgent({ routes }) has it | Your route checks the caller |
- Exact paths only. Except for the web chat’s paths, a route matches its path exactly: no prefixes or wildcards, and the query string is ignored for matching. An unknown path returns 404.
- Request bodies are at most 5 MB (413 above that).
- Do not reuse the paths above for your own routes: the host answers them first.
Use model: flowModel() on Flow’s hosting. It always sends the environment’s FLOW_KEY to Flow’s
model API, paid from the account’s Flow credit.
When the model comes from the environment (openAICompatible() with no key), a provider key you
sent as a secret (OPENROUTER_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY or GEMINI_API_KEY)
wins over FLOW_KEY, following the key order. Choose explicitly with
flowModel() or openAICompatible({ apiKey, baseURL, model }).
Storage
Section titled “Storage”The process has no disk that persists. Files it writes, such as .flow/session.json, live in
memory and are lost at every restart, redeploy and scale to zero.
- Conversations, schedules, nudges and wake-ups are kept in the host’s store automatically
when
buildAgentpasseshost: options.hosttocreateAgent. - The agent’s own data goes in records, which use the same store. Data your app or team reads goes in your own database, reached through a tool.
- Each environment has its own store. Promoting staging copies no data.
- The OAuth bridge’s storage is
host.oauthStorage, given to anmcp(agent, host)factory insrc/mcp.ts. - Production refuses an agent that drops
hostor brings its own database; staging warns. An MCP server alone has no chat state, so neither applies to it.
Web chat
Section titled “Web chat”A webChat() channel needs only your sites: list them in
webChat({ origins }) or set the secret FLOW_WEB_CHAT_ORIGINS (comma-separated). For signed-in
visitors, also set FLOW_WEB_CHAT_IDENTITY_KEY. Flow sets the session key and the trusted proxy.
- Production refuses a web chat open to any site (
web_chat_open); staging deploys it with a warning. Promoting such a version is refused while production has noFLOW_WEB_CHAT_ORIGINS. - The limits are exact here: the environment runs one process.
- The box streams events for up to 14 minutes, then reconnects, within the 900-second request timeout. Staging that scaled to zero starts again on the first visitor’s request.
MCP server
Section titled “MCP server”When the folder has src/mcp.ts, the host serves its export beside the agent on the same origin.
Connect FLOW_AGENT_URL + /mcp through the MCP setup.
Without auth, a deploy warns mcp_open. Once the hosting update now rolling out is live, it
names only the tools that need sign-in (signIn "required" or "optional"; an older framework’s
tools all count), so an agent whose tools are all signIn: "none" gets no warning. It never names
Flow’s built-in feedback tool: it says what it is, and that mcpServer({ feedback: false })
leaves it out.
An MCP server alone
Section titled “An MCP server alone”A project that only serves MCP, with src/mcp.ts and no src/agent.ts (no buildAgent, model key
or channels), deploys the same way. The host calls a factory as mcp(undefined, host): agent is
undefined and host.oauthStorage is the OAuth bridge’s storage in the host’s store.
import { mcpServer } from "@flow-engineer/flow/mcp";import { oauthBridge } from "@flow-engineer/flow/oauth";import { tools } from "./tools.ts";
export { tools }; // flow check reads them here when there is no src/agent.ts
export async function mcp(_agent: undefined, host) { const bridge = await oauthBridge({ ...bridgeOptions, storage: host.oauthStorage }); return mcpServer({ name: "acme", version: "1.0.0", tools, auth: bridge.auth });}- It serves
/healthz, its MCP paths and the bridge’s routes, and its CLI’s install (src/cli.ts) if it has one. Every other path answers 404: there is no playground,/nudges,/people, agent route or Flow Messaging. AFLOW_MESSAGING_KEYsecret is logged as unused. - Production takes it. Its state is the bridge’s records in the host’s store, so the deploy
check skips the chat rules. It still checks the Flow Framework version and the MCP sign-in
warnings (
mcp_open,mcp_public_tools), and refuses asrc/mcp.tsthat exports nomcp(invalid_mcp). - It needs
@flow-engineer/flow0.16.1 or later forflow deployandflow checkto accept the folder, and the hosting update now rolling out.
Resources and scaling
Section titled “Resources and scaling”- One instance at most per environment, with 1 CPU and 1 GiB of memory. Files written in memory count against that.
- Requests time out after 900 seconds.
- Production keeps one instance warm. Staging scales to zero when idle unless the agent has
FLOW_MESSAGING_KEY; while it is scaled to zero, nothing in it runs until the next request starts it.
Add a webhook or OAuth callback
Section titled “Add a webhook or OAuth callback”A business event, a payment provider’s webhook or a third-party login redirect (a broker’s OAuth
callback, for example) is one of the agent’s routes. The host sends every path it does not serve
itself to agent.fetch(request), which answers from routes. Register the full URL,
FLOW_AGENT_URL plus the path, with the other service.
const agent = createAgent({ // ...the starter's options, host: options.host included routes: { "/webhooks/orders": async (request) => { if (request.headers.get("authorization") !== `Bearer ${process.env.ORDERS_WEBHOOK_TOKEN}`) { return new Response(null, { status: 401 }); } const { phone, orderId } = (await request.json()) as { phone: string; orderId: string }; const sent = await agent.nudge({ to: { channel: "whatsapp", address: phone }, prompt: `Order ${orderId} has filled.`, idempotencyKey: `order-filled-${orderId}`, }); return Response.json(sent); }, "/oauth/broker/callback": async (request) => { const url = new URL(request.url); // Match url.searchParams.get("state") to the sign-in you started, then exchange "code". return new Response("Signed in. You can go back to the chat."); }, },});return agent;- The route checks who called: a shared secret, the provider’s signature, or the OAuth
stateyou issued. Hosting passes every request through unauthenticated. ORDERS_WEBHOOK_TOKENis your own secret: put it in.envand deploy.- This is the supported way to add a webhook or callback.
mcpServer({ auth: { routes } })is only for the OAuth bridge’s own endpoints. - Locally,
npm startserves the same routes on the playground’s address (Framework 0.9.0 or later,localhostonly), so you can call them before you deploy. - To message the person outside WhatsApp’s 24-hour window, see a business event, later.
The buildAgent contract and what deploy sends
For a custom entry point, export buildAgent(options) from src/agent.ts and pass
host: options.host to createAgent as one option. Do not spread it into the agent options.
Keep the agent’s own dir.
deploy needs package.json, package-lock.json and src/agent.ts (or only src/mcp.ts for
an MCP server alone). It uploads the project
without node_modules, Git data, .flow or environment files (at most 50 MB), then sends
eligible environment values separately as secrets. Use --no-secrets to skip sending them.
The deployment reference covers secret updates, flags, JSON output and exit codes.
Thanks, we read every comment.