Skip to main content
MindStudio
Pricing
Blog About
My Workspace
Remy one method multiple interfacesMCP tool from backend

One Method, Eight Interfaces: How Remy Projects Your Backend Everywhere

A single Remy method powers a web button, Discord bot, Telegram command, MCP tool, cron job, webhook, email trigger, and REST endpoint—no integration shims.

MindStudio Team RSS
One Method, Eight Interfaces: How Remy Projects Your Backend Everywhere

At a Glance

  • One method, nine projections — the same TypeScript function powers web, API, Discord, Telegram, cron, webhook, email, MCP, and conversational agent interfaces
  • No integration shims — methods don’t know which interface invoked them; the platform handles routing, auth, and serialization
  • Real examplesubmitVendorRequest becomes a web form submit, /submit Discord command, Telegram bot action, MCP tool, scheduled job, webhook endpoint, inbound email handler, and REST POST in one deploy
  • Architecture — methods are the universal unit of backend logic; interfaces are projections of the contract into different modalities
  • Zero duplication — business logic lives in one place; add a new interface by declaring it in the manifest, not by writing adapter code

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. One of its most distinctive architectural choices is that methods don’t know or care which interface invoked them. This piece walks through what that means in practice, using a concrete example method projected to all nine interface types.

What Is a Method in Remy?

A method is a named async TypeScript function that runs on the platform. It’s the universal unit of backend logic. Every interface — web app, REST API, Discord bot, Telegram bot, cron job, webhook, inbound email, MCP tool server, conversational agent — is just a different way to invoke a method.

Here’s a real method from a vendor approval workflow:

import { db, auth } from '@mindstudio-ai/agent';
import { Vendors } from './tables/vendors';

export async function submitVendorRequest(input: {
  name: string;
  contactEmail: string;
  taxId: string;
}) {
  auth.requireRole('requester');

  const vendor = await Vendors.push({
    name: input.name,
    contactEmail: input.contactEmail,
    taxId: input.taxId,
    status: 'pending',
    requestedBy: auth.userId,
  });

  return { vendorId: vendor.id, status: vendor.status };
}

This method:

  • Checks that the caller has the requester role
  • Inserts a row into the vendors table
  • Returns the new vendor’s ID and status

Nothing in this code knows whether it was called from a web form, a Discord slash command, or a Telegram bot. The method is interface-agnostic. The platform handles the rest.

How Does One Method Power Nine Interfaces?

The platform provides nine interface types. Each one is a different projection of the same backend contract. You declare which interfaces your app uses in mindstudio.json, and the platform wires them up on deploy.

Let’s walk through all nine, using submitVendorRequest as the example.

1. Web Interface

The web interface is a React app (Vite scaffold by default, but any framework with a build step works). The frontend SDK provides typed RPC to backend methods:

import { createClient } from '@mindstudio-ai/interface';

const api = createClient<{
  submitVendorRequest(input: {
    name: string;
    contactEmail: string;
    taxId: string;
  }): Promise<{ vendorId: string; status: string }>;
}>();

const { vendorId } = await api.submitVendorRequest({
  name: 'Acme Corp',
  contactEmail: 'billing@acme.com',
  taxId: '12-3456789',
});

The SDK serializes the input, posts to /_/methods/submit-vendor-request, and deserializes the response. The method runs in an isolated sandbox. The web interface is hosted on CDN. No servers to manage.

For more on how AI agents can integrate with web interfaces, see What Is OpenClaw? The Open-Source AI Agent That Actually Does Things.

2. REST API Interface

The API interface exposes selected methods as REST endpoints with clean URLs and HTTP methods. You declare routes in src/interfaces/api.md:

## Vendors

### Create vendor
POST /vendors → submitVendorRequest
~~~
Submit a new vendor for approval.
body: name (string, required) — vendor name
      contactEmail (string, required) — billing contact
      taxId (string, required) — tax identifier
~~~

Remy compiles this into dist/interfaces/api/api.json. On deploy, the platform registers the route. External consumers call it:

curl -X POST https://app.mindstudio.ai/_/api/vendors \
  -H "Authorization: Bearer sk_..." \
  -H "Content-Type: application/json" \
  -d '{ "name": "Acme", "contactEmail": "billing@acme.com", "taxId": "12-3456789" }'

The platform extracts the request body, invokes submitVendorRequest(input), and returns the method’s output as JSON. Same method, different transport.

3. Discord Bot Interface

The Discord interface maps slash commands to methods. Config lives in dist/interfaces/discord/interface.json:

{
  "commands": [
    {
      "name": "submit-vendor",
      "description": "Request a new vendor",
      "method": "submit-vendor-request"
    }
  ]
}

On deploy, the platform syncs the command to Discord via the bot API. A user types /submit-vendor in a Discord channel. Discord sends a webhook to the platform. The platform invokes the method. The method’s return value becomes the bot’s reply.

For related patterns on controlling AI agents from messaging apps, see What Is Claude Code Dispatch? How to Remote Control Your AI Agent from Your Phone.

4. Telegram Bot Interface

Same pattern, different platform. Config:

{
  "commands": [
    {
      "command": "/submit",
      "description": "Submit a vendor request",
      "method": "submit-vendor-request"
    }
  ]
}
Wondering what the Hermes hype is about? Free 60-minute primer
The free Hermes Agent crash courseReserve your spot

A user sends /submit to the bot. Telegram posts to the platform’s webhook. The platform invokes the method. The method’s output is formatted as a Telegram message and sent back.

For a step-by-step guide on setting up Telegram integrations with AI agents, see How to Set Up Claude Code Channels with Telegram: Step-by-Step Guide.

5. Cron Interface

Scheduled method execution. Config:

{
  "jobs": [
    {
      "schedule": "0 9 * * 1",
      "method": "submit-vendor-request",
      "description": "Auto-submit weekly vendor batch every Monday at 9am"
    }
  ]
}

Standard cron expression. The platform runs the method on schedule. No input needed (or the method can read from a table of pending items). The method’s side effects (database writes, emails sent via the SDK) happen automatically.

6. Webhook Interface

Inbound HTTP endpoints that invoke methods. Config:

{
  "endpoints": [
    {
      "method": "submit-vendor-request",
      "description": "Vendor submission webhook",
      "secret": "whk_abc123..."
    }
  ]
}

Endpoint URL: https://app.mindstudio.ai/_/webhook/whk_abc123...

An external service (Zapier, Stripe, GitHub) posts to this URL. The platform invokes the method with { method, headers, query, body } as input. The method parses the payload and does its work. Same method, triggered by an external system.

7. Email Interface

Inbound email triggers. You register a custom email address:

POST /email/register
Body: { "name": "vendors" }

Creates vendors@mindstudio-hooks.com. Config:

{
  "method": "submit-vendor-request"
}

An email sent to that address invokes the method with the email content (subject, body, attachments) as input. The method parses the email and creates the vendor record. Same method, triggered by email.

8. MCP (Model Context Protocol) Interface

MCP exposes methods as AI tools. Config:

{
  "methods": ["submit-vendor-request"]
}

Each listed method becomes an MCP tool. The method’s name and description (from the manifest) become the tool’s name and description. An AI model (Claude Desktop, Cursor, any MCP client) can call the tool. The platform invokes the method and returns the result to the model.

This is the same architectural pattern that makes AI agents for product managers viable — the agent has structured access to backend logic without needing to write integration code.

9. Agent (Conversational Interface)

A conversational interface where an LLM has access to the app’s methods as tools. Unlike MCP (which exposes methods for external agents to call), the agent interface IS the agent — it has its own personality, system prompt, and model config, and orchestrates tool calls against the app’s methods internally.

You author the agent’s character in src/interfaces/agent.md:

---
name: Vendor Assistant
model: {"model": "claude-4-5-haiku", "temperature": 0.5}
description: Conversational agent that helps users submit vendor requests.
---

You are a helpful assistant for vendor onboarding. When a user wants to add a vendor, collect the required information (name, contact email, tax ID) and submit the request on their behalf.

Remy compiles this into dist/interfaces/agent/agent.json with a system prompt and tool descriptions. The platform runs the agent. A user chats with it. The agent calls submitVendorRequest as a tool when appropriate. Same method, invoked by an LLM.

Why This Architecture Matters

Zero Duplication

REMY IS NOT
  • a coding agent
  • no-code
  • vibe coding
  • a faster Cursor
IT IS
a general contractor for software

The one that tells the coding agents what to build.

Business logic lives in one place. Add a new interface by declaring it in the manifest, not by writing adapter code. If the vendor approval rules change, you update the method. All nine interfaces get the change automatically.

Interface-Agnostic Auth

auth.requireRole('requester') works the same way regardless of interface. The platform resolves the current user from the session cookie (web), API key (REST), Discord user ID (Discord bot), Telegram user ID (Telegram bot), or impersonation context (cron, webhook, email). The method doesn’t care.

Composability

Methods can call other methods. A cron job can invoke the same method a web form calls. A webhook can trigger the same workflow a Discord command triggers. The interfaces compose naturally because they’re all projections of the same contract.

Testing

Test the method once. If it works via the web interface, it works via Discord, Telegram, MCP, cron, webhook, email, API, and agent. The interface layer is thin and declarative. The method is where the logic lives.

What Gets Generated When You Describe an App

When you describe an app to Remy (“I need a vendor approval workflow with a web UI and a Discord bot”), the agent generates:

  1. The spec (src/app.md) — annotated markdown describing the domain, the rules, the workflows
  2. The methods (dist/methods/src/*.ts) — one TypeScript file per method
  3. The table definitions (dist/methods/src/tables/*.ts) — typed schemas
  4. The web interface (dist/interfaces/web/) — React app with forms, tables, buttons that call the methods
  5. The Discord config (dist/interfaces/discord/interface.json) — slash commands mapped to methods
  6. The manifest (mindstudio.json) — declares everything

You push to git. The platform builds and deploys. The web app and Discord bot are live. Same methods, two interfaces. No integration shims.

How Does This Compare to Other AI Builders?

Most AI app builders (Lovable, Bolt, Replit Agent, v0) generate a frontend and a set of API routes. If you want a Discord bot, you write a separate bot that calls the API. If you want MCP tools, you write an MCP server that wraps the API. The API is the integration surface.

Remy inverts this. Methods are the integration surface. Interfaces are projections. The platform handles the routing, serialization, and auth. You declare which interfaces you want; the platform wires them up.

This is the structural difference between spec-driven compilation and prompt-driven code generation. The spec is the source of truth. The code (including the interface configs) is compiled output. When you add a new interface, you’re not editing code — you’re updating the manifest and letting the platform regenerate the wiring.

When Would You NOT Use This Pattern?

If your app is interface-specific — a game with real-time WebSocket state, a mobile app with platform-specific UI, a desktop app with native OS integration — the “one method, many interfaces” pattern doesn’t help. You’re building for one interface, and the interface IS the app.

Remy’s architecture wins when the app is data-and-logic-shaped, not interface-shaped. Workflow systems, internal tools, approval processes, CRMs, dashboards, vertical SaaS — these are all “backend contract projected to interfaces” workloads. The interface is a view into the contract, not the app itself.

FAQ

Can I add a new interface without changing method code?

Hermes Crash Course — free 1-hour live workshop
The free Hermes Agent crash courseReserve your spot

Yes. Declare the interface in the manifest, push to git, and the platform wires it up. The method doesn’t change.

What if I need interface-specific behavior?

Methods can inspect the execution context (web, API, Discord, etc.) via the SDK if needed, but this is rare. Most business logic is interface-agnostic. If you find yourself writing if (context.interface === 'discord') inside a method, consider whether that logic belongs in the interface config instead.

Do all nine interfaces ship by default?

No. You declare which interfaces your app uses in the manifest. An app can have just a web interface, or just an API, or all nine. It’s opt-in.

Can I customize the interface behavior?

Yes. Each interface type has a config file where you declare routes, commands, schedules, etc. The web interface is a full project directory where you write React components. The platform provides the scaffold; you customize from there.

What happens when a method throws an error?

The platform catches it, logs it, and returns an error response appropriate to the interface. Web: JSON error. Discord: ephemeral error message. Telegram: error reply. API: HTTP 500 with error body. MCP: tool error. The method doesn’t handle interface-specific error formatting.

Can I stream responses?

Yes. Methods can stream token-by-token output (useful for AI-generated content). The platform handles the SSE transport for web and API interfaces. Discord and Telegram get the final accumulated output.

How does auth work across interfaces?

The platform resolves the current user from the interface-specific auth mechanism (session cookie, API key, Discord user ID, Telegram user ID) and provides it to the method via auth.userId and auth.roles. The method calls auth.requireRole('requester') and the platform enforces it regardless of interface.

Can I call methods from other methods?

Yes. Import and call them like normal TypeScript functions. The execution context (database, auth, SDK) is shared.

What’s the performance overhead of this architecture?

Negligible. The interface layer is a thin routing and serialization step. The method runs in the same isolated sandbox regardless of interface. The database, auth, and SDK calls are the same. The overhead is one extra HTTP hop (interface → platform → sandbox) compared to a monolithic server, but the latency is sub-10ms for the routing step.

Can I use this pattern outside Remy?

The pattern (methods as the universal backend contract, interfaces as projections) is general. You could build it yourself with a routing layer, a method registry, and interface adapters. Remy’s contribution is making it declarative and automatic — you describe the app, the agent generates the methods and configs, and the platform handles the rest.

What Is Remy?

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. The “one method, many interfaces” architecture is one of the load-bearing primitives that makes spec-driven compilation viable at the application layer.

Start building with Remy →

Presented by MindStudio

No spam. Unsubscribe anytime.