Frontend Launch Kit
Vibe-code a Next.js frontend while SteelEngine runs your deployed backend workflows.
Vibe-code the product experience while SteelEngine handles the backend workflows. The Frontend Launch Kit exports every deployed workflow in a workspace as version-pinned TypeScript fetch functions, cURL examples, React Query mutations, and a secure Next.js proxy that you can drop into an app.
Browser UI → React Query mutation → Next.js server proxy → deployed SteelEngine workflow
Coding agent → SteelEngine MCP → edit, test, and deploy → export a refreshed clientThe browser never receives your workspace API key. Deployment IDs remain pinned in server code, so a frontend keeps calling the version it was built and tested against until you deliberately refresh the export.
What the export contains
Choose Export client code once and SteelEngine downloads one ZIP for the workspace. It includes all currently deployed workflows and every available deployment version.
| File | Purpose |
|---|---|
workflows.ts | Server-side fetch functions for every version, plus an alias for the active version at export time |
react-query.ts | Client-side mutation hooks and stable workflowMutationKeys factories |
client.ts | Server-only fetch client and typed error class |
contracts.ts | Browser-safe input types generated from each workflow's Start block |
nextjs/.../route.ts | Same-origin proxy that keeps the workspace key private and allowlists exported versions |
examples.curl.sh | Ready-to-run request for every deployed version |
manifest.json | Workflow IDs, deployment IDs, version descriptions, and input inventory |
package.json and tsconfig.json | Type checking, cURL, shadcn/ui scripts, and peer requirements |
AGENTS.md | Instructions for coding agents working with the generated client and SteelEngine MCP |
.env.example | STEELENGINE_API_URL plus an intentionally empty WORKSPACE_API_KEY |
Generated input types come from the Start block's input format. Give workflows, deployments, and input fields clear descriptions before exporting; those descriptions become useful context for developers and coding agents.
Build the app
Build and test the workflow in SteelEngine. Define the public input contract in the Start block, describe what the workflow and deployment do, and then deploy it.
Deployed versions are immutable snapshots. Draft changes do not affect an app until you create a new deployment and export the client again. Learn more in Execution.
In the workspace sidebar, find Workflows, open More actions (…), and choose Export
client code. Extract the downloaded ZIP into the root of the frontend repository and name the
folder steelengine-client.
my-app/
├── app/ or src/app/
├── steelengine-client/
├── package.json
└── tsconfig.jsonIf you need a new app, create one first:
npx create-next-app@latest my-app --typescript --tailwind --eslint --app --src-dir
cd my-appWith steelengine-client in the app root, install React Query and initialize every shadcn/ui
component with one command:
npm install @tanstack/react-query && npm --prefix steelengine-client run ui:setupTo start with a palette and font system from shadcn/create, use its preset code instead:
npm install @tanstack/react-query && npm --prefix steelengine-client run ui:init -- --preset YOUR_PRESET_CODE && npm --prefix steelengine-client run ui:add-allFor an existing shadcn/ui app, apply only a new theme and fonts:
npm --prefix steelengine-client run ui:apply -- --preset YOUR_PRESET_CODE --only theme,fontCopy the example into the Next.js environment file:
cp steelengine-client/.env.example .env.localCreate a workspace execution key under Workspace Settings → API Keys, then complete the file:
STEELENGINE_API_URL="https://YOUR_STEELENGINE_HOST"
WORKSPACE_API_KEY="YOUR_WORKSPACE_API_KEY"Never prefix the key with NEXT_PUBLIC_ or expose it through browser code. The generated React
Query hooks call your own Next.js route, not SteelEngine directly.
Copy the generated route into the matching App Router location:
steelengine-client/nextjs/app/api/steelengine/workflows/[workflowId]/execute/route.ts
→ src/app/api/steelengine/workflows/[workflowId]/execute/route.tsOmit src/ when the app uses a root-level app/ directory. Keep the generated deployment map
on the server; it prevents a browser from requesting an arbitrary workflow or version.
Keep the generated folder replaceable by importing it through an alias. Merge this path into the
app's tsconfig.json:
{
"compilerOptions": {
"paths": {
"@/*": ["./src/*"],
"@steelengine-client/*": ["./steelengine-client/*"]
}
}
}If the app does not use src/, keep its existing @/* value and add only the
@steelengine-client/* entry.
Create one client provider with a stable QueryClient:
// src/app/providers.tsx
'use client'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { useState, type ReactNode } from 'react'
export function Providers({ children }: { children: ReactNode }) {
const [queryClient] = useState(() => new QueryClient())
return <QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
}Render it once from the root layout:
// src/app/layout.tsx
import type { ReactNode } from 'react'
import { Providers } from './providers'
export default function RootLayout({ children }: Readonly<{ children: ReactNode }>) {
return (
<html lang="en">
<body>
<Providers>{children}</Providers>
</body>
</html>
)
}Generated browser hooks are mutations because workflow execution uses POST and can have side
effects. Import the active-version alias shown in react-query.ts:
'use client'
import { useCustomerSummary } from '@steelengine-client/react-query'
import { Button } from '@/components/ui/button'
export function RunCustomerSummaryButton({ accountId }: { accountId: string }) {
const summary = useCustomerSummary()
return (
<Button
disabled={summary.isPending}
onClick={() => summary.mutate({ accountId })}
>
{summary.isPending ? 'Building summary…' : 'Build summary'}
</Button>
)
}The names and inputs depend on the exported workflows. Use mutateAsync when subsequent UI
logic needs the result, and invalidate app-owned query keys in onSuccess when the workflow
changes data displayed elsewhere.
Run the generated type check from the application root:
npm --prefix steelengine-client run checkYou can also inspect manifest.json, use the version comments in workflows.ts, or test the
requests from a shell with npm --prefix steelengine-client run curl:examples. The cURL command
executes the workflows, so use test inputs and a non-production workspace when appropriate.
Vibe-code safely with SteelEngine MCP
The exported AGENTS.md tells a coding agent how this folder works and where custom application
code belongs. It also separates the two SteelEngine surfaces:
- Execution data plane: the generated REST client calls immutable deployed workflow versions.
- Management control plane: SteelEngine MCP lets an authorized agent inspect,
edit, test, deploy, and manage workflows through the
steelengine_workflowstool.
When the UI needs a different workflow input or behavior:
- Ask the coding agent to inspect the consuming component and
manifest.json. - Connect the agent to
/api/mcp/steelengineif SteelEngine MCP is not already available. - Authenticate with OAuth or a dedicated SteelEngine MCP API key sent in
X-API-Key. - Let the agent update and test the workflow, then deploy a new immutable version.
- Export the client again, replace
steelengine-client, run its check, and update the UI.
A SteelEngine MCP key and WORKSPACE_API_KEY serve different purposes. Keep both out of browser
code, grant the MCP key only the permissions the agent needs, and treat call-time permission
denials as authoritative.
Server Components and backend jobs
Client components should use react-query.ts. Server Components, Route Handlers, Server Actions,
and backend jobs can call the versioned functions from workflows.ts directly:
import { runCustomerSummaryV2 } from '@steelengine-client/workflows'
const summary = await runCustomerSummaryV2({ accountId: 'account_123' })The version suffix is the strongest reproducibility guarantee. The unsuffixed alias is convenient, but it is only the active deployment at the moment the ZIP was created—it does not silently follow future deployments.