Standing Up Support for a New App in One Prompt

Think about how support actually gets added to a project. Not how it should be — how it is.
Month one is the build. Month two is polish and a landing page. Month three you launch, and the contact link points at a personal Gmail address because that was the fastest thing to type. Month four, someone hits a bug that costs them an afternoon, writes a careful message explaining exactly what happened, and sends it to that address — which is buried under newsletters and receipts and a Google Calendar digest. You find it eleven days later. By then they've moved on, and their careful bug report, the most valuable thing anyone has sent you all quarter, has gone stale in a promotions tab.
So you finally sit down to do support properly. Except now it isn't a fifteen-minute job. You have live users, an inbox with real history in it, an address you can't change without breaking the link in three places, and no help centre, so every question gets answered from scratch. Support in month four costs five times what it costs in month zero, and the reason is not the software — it's the migration and the accumulated debt of every question you answered privately and never wrote down.
The argument here is narrow: support belongs in the scaffolding step, next to the database and the auth provider and the error handler. Not because you'll use it in week one — you almost certainly won't — but because the setup is cheap now and expensive later. Here's the concrete sequence, and then the one part of it that actually matters.
The sequence, in order
Say you're building Ledgerly, invoicing for freelancers. The repo exists, the schema is drawn, nothing is deployed. With an agent connected to Helmdesk over MCP, this is one paragraph in your editor:
Set up Helmdesk for this app. It's called Ledgerly — invoicing for freelancers.
Create the project, mint a key limited to it with just the scopes this app
needs, write them into .env.local, and show me the widget snippet.
What comes back is four tool calls and two file edits, and none of it emails anyone.
- The project.
create_projectmakes one project for this one app — its own ticket queue, help centre, email templates, error log and sandbox plane. The response hands back the environment line rather than making the agent guess at the slug. Note that a project is a real thing on your bill, so the agent should be asking you for the name rather than inventing one. - The key.
create_api_key, scoped to this project alone. More on this below; it's the whole point. - The environment file. Two lines in
.env.local: the key, andHELMDESK_PROJECT=ledgerly. That second line is quietly the most useful thing here — any future agent session opened in this repo reads it and knows which project this codebase belongs to, so you never have to say "the Ledgerly one" again. - The widget.
get_projectreturns the install snippet with your real slug already in it, plus the public support and help-centre URLs. It needs no API key at all — the slug is enough — so it's safe in client-side layout code. - The first few articles. "Draft articles for the five questions a new invoicing app gets, and leave them as drafts."
create_articledefaults to draft, so nothing is public until you publish it deliberately.
Elapsed time, maybe two minutes. What you now have is an address that is a real queue, a help centre with something in it, and a place for your app's errors to go.
The part that actually matters: two keys, not one
If you take one thing from this post, take this. The key your agent holds and the key inside your app are not the same key, and treating them as one is the most common mistake in this whole flow.
Your agent's key is deliberately broad. It reaches every project, because you want to be able to ask "where is the queue worst this morning?" across all of them, and it holds management scopes because you want it to be able to do the thing this post is about. That is the correct shape for a credential that lives on your laptop, behind your own approval prompts, in a session you're watching.
It is completely the wrong shape for a credential that ships inside a deployed web app. That key sits in a production environment, gets read by every process on the box, appears in whatever your platform calls environment variables, and survives every deploy. It should reach exactly one project and hold exactly the scopes that app's own code calls:
emails:send
logs:write
tickets:write
customers:write
That's it. No projects:manage. No api_keys:manage. No ability to mint further keys, delete a knowledge base, or read the ticket queue of the other app you're running. If Ledgerly's environment is ever exposed — a leaked build log, a misconfigured error reporter, a contractor's laptop — the blast radius is Ledgerly's own data and nothing else.
Two properties make this workable rather than merely virtuous. A minted key can never exceed its caller: it only reaches projects the caller reaches and only holds scopes the caller holds, so there's no escalation path. And a live key can mint a sandbox key, which is what belongs in your dev and staging configuration — an sk_sandbox_ key can never touch live data, and mail sent through it renders and is logged but is never delivered to anyone.
This is also a reasonable thing to enforce yourself with any provider that supports scoped tokens — the practice matters more than whose dashboard you do it in. What makes it stick is doing it at the moment the key is created, because nobody has ever gone back six months later and narrowed a working production credential. That is not a discipline problem; it is that a key doing real work is frightening to touch.
The raw secret comes back once, in that one response. It goes into the environment file and nowhere else — not into a commit, not echoed back into the chat, not into a README. Lose it and you revoke and mint another.
The honest concession
Now the part where this advice fails.
If you have no users, most of what you just set up will sit idle for months. The help centre gets no traffic. The ticket queue is empty. The widget is a button nobody clicks. If you're the sort of person who feels obligated to maintain everything you install, this is four things to feel vaguely guilty about, and the argument that "it's cheaper now than later" is the same argument people use to justify setting up Kubernetes for a landing page.
So be honest about which parts are genuinely load-bearing on day zero. The error log is, immediately — your app will throw exceptions before it has a single customer, and having those grouped and searchable from the first deploy is worth it on its own. The scoped key is, because key hygiene is only easy before there is a key in production doing important work. The rest — articles, templates, the widget — is real but deferrable. You can add the widget the week before launch and lose nothing.
What you can't cheaply defer is the shape. Month-four support is a migration; month-zero support is a config file. Two minutes of scaffolding buys you an address that is already a queue, so the first careful bug report anyone writes you lands somewhere it will be read.
Wire support in while you're still scaffolding
One prompt creates the project, mints a key scoped to just that app, writes your .env and hands you the widget snippet.