Build your own apps on Mu

Updated 1 hour ago · Mu ·

Mu is a set of everyday services you own — news, mail, markets, weather, and the rest — with an agent that drives them. But not everything belongs in the core. You shouldn’t have to fork Mu to get a bookmarks tool, a reading list, or whatever small thing fits your day. That’s what apps are for.

A Mu app is just an HTML page with a little JavaScript. What makes it more than a static page is the SDK — a global mu object that gives the page real backend building blocks, without you standing up a backend.

<script src="/apps/sdk.js"></script>

Who’s using it

mu.user() tells you who is signed in, so an app can greet them and keep their data separate from everyone else’s:

const u = await mu.user();   // { account: 'alice', admin: false }

Storage that knows who you are

mu.db is a small database, not just a key-value bucket. Each record has an owner (you) and a public flag, so one app can hold your private data and a shared public set at the same time:

await mu.db.create('notes', { title: 'Idea', body: '...' });            // private to me
await mu.db.create('notes', { title: 'Public tip' }, { public: true }); // shared

await mu.db.list('notes');                       // my notes
await mu.db.list('notes', { scope: 'public' });  // everyone's public notes
await mu.db.list('tasks', { where: { done: false, priority: { gte: 2 } } });

The owner is set on the server from your session — never from the page — so an app can’t read or write someone else’s private data even if it tries.

Reach the web, server-side

mu.web.fetch makes an HTTP request from the server, so your app gets past CORS and can keep API keys off the client. It’s SSRF-guarded — public hosts only:

const res = await mu.web.fetch('https://api.example.com/data');
const data = JSON.parse(res.body);

The agent, in your app

mu.ai(prompt) for a one-shot answer, mu.agent(prompt) for the full tool-using agent — plus typed wrappers for every service (mu.weather, mu.markets, mu.news, and more):

const tldr = await mu.ai('Summarise this', { context: text });
const answer = await mu.agent('What changed in the markets today and why?');

A real example: bookmarks

Here’s the whole backend of an app that saves links — privately or shared — and fetches each page’s title for you. Three primitives, working together:

async function add(url, isPublic) {
  const res = await mu.web.fetch(url);                                  // read the page
  const title = (/<title[^>]*>([\s\S]*?)<\/title>/i.exec(res.body) || [])[1] || url;
  await mu.db.create('bookmarks', { url, title }, { public: isPublic }); // save it
}
const mine   = await mu.db.list('bookmarks', { scope: 'mine' });
const shared = await mu.db.list('bookmarks', { scope: 'public' });

No server to deploy, no database to provision, no CORS proxy to run. The Bookmarks and Notes apps ship built-in — open them, or fork them from the editor to make your own.

How to build one

  • Describe it at /apps/new and Mu builds a working app.
  • Ask the agent — “build me a reading list” — it makes the app and gives you a URL.
  • Write it yourself — paste HTML at /apps/new, or hand-edit any app at /apps/{slug}/edit.

Pin the ones you use to the top of your home screen. Keep them private, or make them public for anyone on your instance.

It runs on your Mu — your instance, your data, your account. Same idea as the rest of Mu: instead of renting a service from a platform that keeps your data, you own the whole stack, and apps are how you extend it.

Full SDK reference: /docs/apps.


Comments

Login to add a comment

No comments yet. Be the first to comment!