Mihe

Quickstart

From a new app in the dashboard to an assistant that runs an action.

This gets one screen and one action working end to end. Each step links to the page that covers it properly.

1. Create an app and its keys

In the dashboard, create an app, then Create key pair on its page. You get two keys:

  • The public key (pk_…) identifies the app. It is safe in a browser.
  • The secret key (sk_…) signs user tokens. It is shown once. Put it in your backend's environment, and never in a browser bundle.

2. Install the SDK

npm install @mihe-dev/react

Not using React? Install @mihe-dev/js instead, or load it with one script tag. Steps 3 and 6 are the same; for steps 4 and 5, the JavaScript SDK has the same integration as function calls: createMihe, setScreen, registerAction and mountWidget.

3. Sign a user token on your backend

The assistant learns who the user is, and what they may do, only from a token your backend signs with the secret key. Add a route that signs one for the signed-in user:

// app/api/mihe-token/route.ts (Next.js), or any route in your backend
import jwt from "jsonwebtoken";

export async function GET() {
  const user = await currentUser(); // your own session
  const token = jwt.sign(
    { sub: user.id, permissions: user.permissions },
    process.env.MIHE_SECRET_KEY!,
    { algorithm: "HS256", expiresIn: "15m" },
  );
  return new Response(token);
}

User tokens covers the claims and the one-hour limit.

4. Wrap your app

import { AssistantProvider, AssistantWidget } from "@mihe-dev/react";
import { useRouter } from "next/navigation";

export function Providers({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  return (
    <AssistantProvider
      url="wss://runtime.mihe.dev/v1/ws"
      publicKey={process.env.NEXT_PUBLIC_MIHE_PUBLIC_KEY!}
      getUserToken={() => fetch("/api/mihe-token").then((r) => r.text())}
      navigate={(route) => router.push(route)}
    >
      {children}
      <AssistantWidget />
    </AssistantProvider>
  );
}

5. Declare a screen and an action

On a page, say where the user is, and handle an action the assistant may run:

import { useAssistantScreen, useAssistantAction } from "@mihe-dev/react";

function OrdersPage() {
  useAssistantScreen({
    screenId: "orders",
    route: "/orders",
    title: "Orders",
    visibleData: { openOrders: orders.length },
  });

  useAssistantAction({
    name: "show_unpaid_orders",
    handler: () => {
      setFilter("unpaid");
      return { shown: unpaidCount };
    },
  });

  return <OrdersTable />;
}

6. Publish the registry

The hooks supply the code. What the assistant is allowed to know about and do is the registry, which you publish from your build, so it is reviewed with the code that implements it. Write it as a file:

mihe-registry.json
{
  "screens": [
    { "screenId": "orders", "route": "/orders", "title": "Orders",
      "description": "Every order, with its payment and delivery status." }
  ],
  "actions": [
    {
      "name": "show_unpaid_orders",
      "description": "Filter the orders list to unpaid orders. Use when the user asks what is unpaid or overdue.",
      "label": "Show unpaid orders",
      "risk": "low",
      "inputSchema": { "type": "object" },
      "executionType": "frontend",
      "screens": ["orders"]
    }
  ]
}

Then, on the app's page in the dashboard, Create publish key, keep it in your CI's secrets, and publish:

curl -X PUT https://runtime.mihe.dev/v1/registry \
  -H "Authorization: Bearer $MIHE_PUBLISH_KEY" \
  -H "Content-Type: application/json" \
  --data @mihe-registry.json

Actions covers the registry and publishing from CI.

7. Try it

Open your app, open the assistant, and ask it to show the unpaid orders. It runs your handler, and the page changes.

Next: how it works, then going live before real users see it.

On this page