Scaffold an app with support
Support is normally the thing you add in month four, after the first angry email arrives at an address nobody is watching. It does not have to be. If your agent is connected to Helmdesk while you are still scaffolding the app, the whole support layer is one prompt at the start of the project.
This page walks through what that prompt does, step by step, so you know what you are agreeing to before you run it.
What this needs
A key that reaches all projects and holds projects:manage (to create the project) and api_keys:manage(to mint the app's own key). The second is outside every preset — add it deliberately. See Safety & approvals.
The prompt
Said in your editor, with the new project open:
Set up Helmdesk for this app. It is called Ledgerly — invoicing for freelancers.
Create the project, mint a key limited to it with the scopes this app needs,
write the key and project into .env.local, and show me the widget snippet.What follows is four tool calls and two file edits. None of it emails anyone.
Step 1 — the project
The agent calls create_project with the name and a description. One project per app: it gets its own ticket queue, help centre, email templates, error log, sandbox, and public support pages.
The response carries the line you want in your environment file, so the agent does not have to construct it:
{
"id": "…",
"name": "Ledgerly",
"slug": "ledgerly",
"env": { "HELMDESK_PROJECT": "ledgerly" },
"nextStep": "…"
}Agents do not invent product names
create_project is documented to be called only when you have named the app. If you have not, the agent should ask rather than guess — a project is a real thing on your bill, and a stray one called my-app is annoying to clean up.
Step 2 — a key that belongs to the app
This is the step people get wrong by hand. The key your agent holds is a broad, all-projects key. The key inside your app should be neither: it belongs to one project and holds only the scopes that app actually uses.
The agent calls create_api_key scoped to the new project. A minted key can never exceed the caller — it only reaches projects the caller reaches and only holds scopes the caller holds — so there is no privilege escalation to worry about.
emails:send
logs:write
tickets:write
customers:writeThe raw key is returned once
The secret appears in that one response and is never retrievable again. It should go straight into your environment file and nowhere else — not into a commit, not echoed back into the chat, not into a README. If it is lost, revoke it with revoke_api_key and mint another.
A live key may mint a sandbox key for your dev and staging config, which is the right thing to put in a .env.development: nothing sent from it can reach a real inbox. A sandbox key can never mint a live one.
Step 3 — the environment file
Two lines, written by the agent into .env.local:
HELMDESK_API_KEY=sk_live_…
HELMDESK_PROJECT=ledgerlyThat second line does more than it looks like. 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. On a multi-project account that is the difference between an agent that acts confidently and one that stops to ask every time.
Step 4 — the widget
get_project returns the install snippet with your real slug already in it, plus the public support and help-centre URLs. Drop it into your layout and customers have somewhere to write to:
<script src="https://helmdesk.dev/widget.js" data-project="ledgerly" async></script>It needs no API key — the project slug is enough, and the public endpoint is CORS-enabled. See Embeddable Widget for identified users and theming.
Then keep going
Everything above takes about a minute. The useful part is that the agent is still connected afterwards, so the rest of the support layer is more sentences rather than more setup:
- A welcome email."Write a welcome template for Ledgerly and preview it with my name in it" —
import_email_templatethenpreview_email, no sending. - A starter help centre."Draft articles for the five questions a new invoicing app gets, and leave them as drafts" —
create_articledefaults to draft, so nothing goes public until you say so. - Error logs. Point your app at
write_logwith the key you just minted, and errors group themselves into issues the Log Watch agent can alert you on. See Logs. - A webhook into your own stack."Register a webhook for new tickets pointing at my Slack relay, then test it" —
create_webhookthentest_webhook, which fires a synthetic event and tells you exactly what your endpoint answered.
Doing it for an app that already exists
Same flow, with one addition: you probably already have customers. If your app knows its own user ids, have the agent pre-load the directory so the first ticket from someone arrives with their history attached rather than as a stranger.
Read the users table in this repo's schema, then create Helmdesk customers for
the twenty most recent signups, setting externalId to our own user id and
tagging each one with their plan.create_customer takes an externalId, so afterwards get_customerresolves your app's user id straight to their support history. Tags are namespaced (plan:gold), and set_customer_tags can sync one namespace at a time without disturbing the others — which is what makes it safe to run on a schedule. See Customers.
Try the whole thing in sandbox first
Everything on this page except create_project works in the sandbox plane. If you want to watch the flow before pointing it at a real project, set HELMDESK_ENVIRONMENT=sandbox, run it, then reset_sandbox to wipe what you made.