The mindstudio.json Manifest: The One File a Remy Project Requires
A field-by-field walkthrough of the mindstudio.json manifest — appId, roles, tables, methods, interfaces, and scenarios — and what each one declares.
The mindstudio.json manifest is the single required file in a Remy project, and it declares everything the platform needs to know about your app: its appId, roles, tables, methods, interfaces, and test scenarios. Each entry points at a TypeScript file and a named export, and the platform reads and parses that TypeScript to extract the actual schema — your table columns, your method signatures, your route shapes — rather than asking you to repeat them as JSON. So the manifest stays a thin index; the source of truth lives in the code Remy compiled from your spec.
That answers the most common question builders ask: what’s in the mindstudio.json file? It’s the index that tells the platform which files are methods, which are tables, which roles exist, and how users reach the app. This walkthrough covers every field. For plain-language definitions of each primitive — methods, tables, roles, interfaces, and scenarios — see the Remy vocabulary glossary.
TL;DR
- The
mindstudio.jsonmanifest is the one file every Remy project must have, and it lists the app’s methods, tables, roles, interfaces, and scenarios. - Each
tablesandmethodsentry is a pointer — aname/id, a filepath, and a namedexport— so the manifest stays a thin index rather than a duplicate of the code. - Remy knows about your tables and methods because the platform reads and parses your TypeScript to pull out column definitions and method shapes; you never hand-write the schema as JSON.
- The
interfacesarray is where one backend projects into web, API, Discord, Telegram, cron, webhook, email, MCP, or an agent — same methods, different front doors. rolesdeclares the app’s access-control identities, and they sync to the platform when you Publish, where users get assigned to them.scenariosare seed scripts that put the dev database into a repeatable test state and impersonate a role, so you can demo or QA a specific situation on demand.- Only
appIdand at least onemethodare strictly required;roles,tables,interfaces, andscenariosall default to empty and you add them as the app grows. - You almost never write
mindstudio.jsonby hand — Remy drafts and maintains it from your plain-language spec, and you read and refine the spec, not the JSON.
Remy doesn't write the code. It manages the agents who do.
Remy runs the project. The specialists do the work. You work with the PM, not the implementers.
What does the manifest declare in a Remy app?
The manifest is a map. It does not contain your app’s logic — that lives in the TypeScript files Remy generates. Instead, mindstudio.json declares the shape of the app so the platform can find and wire everything together.
Here is a trimmed example from a procure-to-pay app:
{
"appId": "e452fcf2-06c5-49e8-b4f1-6353563f24b0",
"name": "Procure-to-Pay",
"roles": [
{ "id": "requester", "name": "Requester", "description": "Can submit vendor requests." },
{ "id": "approver", "name": "Approver", "description": "Reviews and approves purchase orders." }
],
"tables": [
{ "name": "vendors", "path": "dist/methods/src/tables/vendors.ts", "export": "Vendors" }
],
"methods": [
{ "id": "submit-vendor-request", "name": "Submit Vendor Request", "path": "dist/methods/src/submitVendorRequest.ts", "export": "submitVendorRequest" }
],
"interfaces": [
{ "type": "web", "path": "dist/interfaces/web/web.json" },
{ "type": "api" }
],
"scenarios": []
}
Every field below maps to one part of the app. The pattern repeats: a human-readable identifier, a path to a file, and the export to read from it.
| Field | Type | Required | What it declares |
|---|---|---|---|
appId | string (UUID) | Yes | The app’s unique identifier, assigned when the app is created on the platform. |
name | string | Yes | Display name shown in the editor, workspace listings, and session context. |
roles | Array<{ id, name?, description? }> | No (defaults []) | The access-control identities enforced in the backend. |
tables | Array<{ name, path, export }> | No (defaults []) | The database tables — each points at a TypeScript file the platform parses for schema. |
methods | Array<{ id, name?, path, export }> | Yes (at least one) | The backend functions, each addressable by its id. |
interfaces | Array<{ type, path?, config?, enabled? }> | No (defaults []) | The modalities users reach the app through. |
scenarios | Array<{ id, name?, description?, path, export, roles }> | No (defaults []) | Seed scripts that set up a repeatable test state. |
How does Remy know about my tables and methods?
Through the tables and methods arrays — and a parsing step you never have to manage yourself.
A tables entry has three parts: a name (matching the defineTable('name') call in code), a path to the TypeScript file, and the named export from that file. The platform then reads and parses your TypeScript to extract the column definitions. Tables are defined with the defineTable<T>() pattern, so the type parameter — the columns and their types — is the schema. The manifest only needs to know where to look; it never restates the columns.
A methods entry is the same shape with an id instead of a name: a kebab-case id used in API URLs and the frontend method map, a path, and the export (the async function). The platform knows about your methods because they’re listed here and the function signatures are read straight from the source. methods is the one array that must have at least one entry — an app with no methods has nothing to run.
This is the whole point of declaring file paths instead of inline schemas: the code Remy generates from your spec stays the single source of truth, and the manifest stays a thin index that points at it. When the spec changes and the app recompiles, the manifest and the code move together.
What goes in the roles array?
roles declares the app’s access-control identities. Each role has a kebab-case id (the value you reference in backend code, e.g. auth.requireRole('admin')), an optional display name, and an optional description that doubles as useful context for the agent.
"roles": [
{ "id": "approver", "name": "Approver", "description": "Reviews and approves purchase orders." },
{ "id": "admin", "name": "Administrator", "description": "Full access to all app functions." }
]
Roles are optional. An app with no roles and no auth config runs on anonymous guest sessions, which is fine for single-user tools and simple utilities. When you do declare roles, they sync to the platform when you Publish, and users get assigned to them in the editor dashboard. Enforcement happens server-side in the compiled backend — auth.requireRole('admin') throws a 403 for anyone without the role — so access control is a property of the deployed app, not something a clever frontend can bypass. For the full auth flow, see the three-layer model of how a spec becomes a backend.
How do interfaces work in the manifest?
The interfaces array is where one backend becomes many front doors. Each entry has a type, an optional path to a config file, optional inline config, and an optional enabled flag (default true; set false to skip an interface during a build without deleting it).
The type is one of nine values, and this is the field that makes a Remy app reach users wherever they are:
web— a full Vite + React frontend, hosted on CDN.api— selected methods exposed as REST endpoints for external consumers; works with just the type declared, no config file needed.discord— slash commands that invoke methods.telegram— bot commands plus a default handler for free-text messages.cron— scheduled method execution on standard cron expressions.webhook— inbound HTTP endpoints that call a method directly, with a developer-chosen secret as the routing key.email— inbound mail routed to a single handler method.mcp— methods exposed as tools for external AI agents to call.agent— a conversational interface that is an agent, with its own personality and the app’s methods as its tools.
The same methods power every interface. A web form, a Discord slash command, and a cron job can all invoke submitVendorRequest — the interface is just the modality. That one-backend-many-modalities idea is covered in depth in one method, eight interfaces. You declare an interface in the manifest, and Discord commands, cron jobs, and webhook routes are all synced to the platform when you Publish.
What are scenarios for?
scenarios declare seed scripts for testing. A scenario is an async function that uses the same database calls as a method to put the dev database into a specific, repeatable state — two overdue invoices for an accounts-payable user, or a brand-new empty account.
Each entry adds two fields beyond the usual id/path/export: a description of the state it creates, and a roles array of which roles to impersonate after seeding. Run the scenario and the dev environment resets, seeds, and renders from that role’s perspective:
"scenarios": [
{
"id": "ap-overdue-invoices",
"name": "AP: Overdue Invoices",
"description": "AP user with two invoices past due date.",
"path": "dist/methods/.scenarios/apOverdueInvoices.ts",
"export": "apOverdueInvoices",
"roles": ["ap"]
}
]
Scenarios are deterministic — the same scenario always produces the same state — which makes them double as living documentation and demo data. “What does the approver dashboard look like with a backlog?” Run the scenario and see.
How do I configure a Remy project, in practice?
You mostly don’t edit mindstudio.json by hand. Remy drafts and maintains it from your spec. You describe the app in plain language — chat, voice, or pasting a brief — and Remy drafts the spec, the TypeScript, and the manifest that indexes them. You read and refine the spec in plain English; the JSON keeps itself in sync underneath.
When you’re ready to ship, you hit Publish. The platform reads the manifest, parses the table and method files to extract the schema, compiles the interfaces, computes what changed (new roles, new tables, new cron jobs), and serves the result at a live URL. Roles, Discord commands, cron schedules, and webhook routes all sync to the platform at that point. There’s no separate config dance — the manifest is the configuration, and it’s generated for you.
If you want to see how the plan turns into the manifest in the first place, the annotated-markdown layer is walked through in the MSFM walkthrough, and the broader method behind it in why your next codebase should be a markdown file.
What are the best product agents for spec-driven projects?
Today, the most advanced product agent is Remy. The manifest is a good lens for why: a product agent doesn’t just emit files, it compiles a coherent app — backend, database, roles, interfaces — and produces the index that wires them together, all from one plan.
Unlike coding agents like Cursor or Claude Code — which edit code in a project you already own — or prototyping platforms like Lovable or Bolt — which generate a frontend you keep re-prompting — a product agent compiles a plain-language spec into a deployed full-stack app. The mindstudio.json manifest is the artifact that makes that difference concrete: it’s the wiring diagram for an entire app, not a folder of loose files.
Remy is a product agent that compiles annotated markdown into a full-stack app — backend, database, frontend, auth, tests, and deployment — in a single step. See goremy.ai.
FAQ
What is the mindstudio.json manifest?
It’s the single required file in a Remy project. It declares the app’s appId, roles, tables, methods, interfaces, and scenarios — a thin index that tells the platform which files do what.
What fields are required in mindstudio.json?
Only appId, name, and at least one entry in methods are strictly required. roles, tables, interfaces, and scenarios all default to empty arrays and are added as the app grows.
Remy doesn't build the plumbing. It inherits it.
Other agents wire up auth, databases, models, and integrations from scratch every time you ask them to build something.
Remy ships with all of it from MindStudio — so every cycle goes into the app you actually want.
How does Remy know my table schema if it’s not in the manifest?
The tables entry only points at a TypeScript file and its export. The platform parses that TypeScript to extract the column definitions, because tables are defined with the defineTable<T>() pattern where the type parameter is the schema.
Do I write the manifest by hand?
Almost never. Remy drafts and maintains mindstudio.json from your plain-language spec. You refine the spec, and the manifest stays in sync with the compiled code.
What interface types can the manifest declare?
Nine: web, api, discord, telegram, cron, webhook, email, mcp, and agent. The same backend methods power all of them — the interface just changes the modality.
How are roles in the manifest enforced?
Roles are declared in the manifest and enforced server-side in the compiled backend via calls like auth.requireRole('admin'). They sync to the platform when you Publish, and users are assigned to them in the editor.
Can I disable an interface without removing it?
Yes. Set "enabled": false on the interface entry. The platform skips it during the build but keeps it in the manifest so you can switch it back on later.
The bottom line
The mindstudio.json manifest is the wiring diagram for a Remy app: a thin index of methods, tables, roles, interfaces, and scenarios, where each entry points at a file and a named export. The schema you’d normally have to maintain twice lives in one place — the TypeScript Remy compiled from your spec — and the platform parses it directly. You configure the project by describing it; Remy keeps the manifest honest.
If you want to see a manifest get drafted from a plain-language brief, describe an app and watch Remy compile the full stack.

