Skip to content

Examples

Real-world application patterns with @manifesto-ai/app

This page provides complete, copy-paste ready examples for common application patterns.


Todo App

A classic todo application demonstrating core patterns.

Domain (MEL)

mel
domain TodoApp {
  state {
    todos: Array<{
      id: string,
      title: string,
      completed: boolean,
      createdAt: number
    }> = []
    filter: string = "all"
    status: string = "idle"
    lastError: string | null = null
  }

  // Computed values
  computed activeCount = len(filter(todos, fn(t) => not(t.completed)))
  computed completedCount = len(filter(todos, fn(t) => t.completed))
  computed totalCount = len(todos)

  // Load todos from API
  action loadTodos() {
    once(loadTodosIntent) {
      patch loadTodosIntent = $meta.intentId
      patch status = "loading"
      effect api.loadTodos({})
    }
  }

  // Add a new todo
  action addTodo(title: string) {
    once(addTodoIntent) {
      patch addTodoIntent = $meta.intentId
      let newTodo = {
        id: $system.uuid,
        title: title,
        completed: false,
        createdAt: $system.now
      }
      patch todos = append(todos, newTodo)
      effect api.saveTodo(newTodo)
    }
  }

  // Toggle completion status
  action toggleTodo(id: string) {
    once(toggleTodoIntent) {
      patch toggleTodoIntent = $meta.intentId
      patch todos = map(todos, fn(t) =>
        cond(eq(t.id, id),
          merge(t, { completed: not(t.completed) }),
          t
        )
      )
    }
  }

  // Remove a todo
  action removeTodo(id: string) {
    once(removeTodoIntent) {
      patch removeTodoIntent = $meta.intentId
      patch todos = filter(todos, fn(t) => neq(t.id, id))
      effect api.deleteTodo({ id: id })
    }
  }

  // Set filter
  action setFilter(newFilter: string) {
    once(setFilterIntent) {
      patch setFilterIntent = $meta.intentId
      patch filter = newFilter
    }
  }

  // Clear completed
  action clearCompleted() {
    once(clearCompletedIntent) {
      patch clearCompletedIntent = $meta.intentId
      patch todos = filter(todos, fn(t) => not(t.completed))
    }
  }
}

App Setup

typescript
// app.ts
import { createApp, type ServiceMap } from "@manifesto-ai/app";
import TodoMel from "./todo.mel";

const services: ServiceMap = {
  "api.loadTodos": async (params, ctx) => {
    try {
      const response = await fetch("/api/todos");
      const todos = await response.json();
      return [
        ctx.patch.set("todos", todos),
        ctx.patch.set("status", "idle"),
      ];
    } catch (error) {
      return [
        ctx.patch.set("status", "error"),
        ctx.patch.set("lastError", error.message),
      ];
    }
  },

  "api.saveTodo": async (params, ctx) => {
    await fetch("/api/todos", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(params),
    });
    return [];
  },

  "api.deleteTodo": async (params, ctx) => {
    await fetch(`/api/todos/${params.id}`, { method: "DELETE" });
    return [];
  },
};

export const todoApp = createApp(TodoMel, { services });

React Component

tsx
// TodoApp.tsx
import { useEffect, useState, useCallback } from "react";
import { todoApp } from "./app";
import type { AppState } from "@manifesto-ai/app";

interface TodoData {
  todos: Array<{ id: string; title: string; completed: boolean }>;
  filter: string;
  status: string;
}

export function TodoApp() {
  const [state, setState] = useState<AppState<TodoData> | null>(null);

  useEffect(() => {
    let unsubscribe: (() => void) | undefined;

    const init = async () => {
      await todoApp.ready();
      setState(todoApp.getState<TodoData>());

      unsubscribe = todoApp.subscribe(
        (s) => s,
        (s) => setState(s as AppState<TodoData>),
        { batchMode: "immediate" }
      );

      await todoApp.act("loadTodos").done();
    };

    init();
    return () => unsubscribe?.();
  }, []);

  const handleAdd = useCallback(async (e: React.KeyboardEvent<HTMLInputElement>) => {
    if (e.key === "Enter" && e.currentTarget.value.trim()) {
      await todoApp.act("addTodo", { title: e.currentTarget.value.trim() }).done();
      e.currentTarget.value = "";
    }
  }, []);

  const handleToggle = useCallback((id: string) => {
    todoApp.act("toggleTodo", { id }).done();
  }, []);

  const handleRemove = useCallback((id: string) => {
    todoApp.act("removeTodo", { id }).done();
  }, []);

  if (!state) return <div>Loading...</div>;

  const { todos, filter } = state.data;
  const filteredTodos = todos.filter((t) => {
    if (filter === "active") return !t.completed;
    if (filter === "completed") return t.completed;
    return true;
  });

  return (
    <div className="todo-app">
      <h1>Todos</h1>
      <input
        type="text"
        placeholder="What needs to be done?"
        onKeyDown={handleAdd}
      />
      <ul>
        {filteredTodos.map((todo) => (
          <li key={todo.id}>
            <input
              type="checkbox"
              checked={todo.completed}
              onChange={() => handleToggle(todo.id)}
            />
            <span className={todo.completed ? "completed" : ""}>
              {todo.title}
            </span>
            <button onClick={() => handleRemove(todo.id)}>×</button>
          </li>
        ))}
      </ul>
      <footer>
        <span>{state.computed.activeCount as number} items left</span>
        <div>
          {["all", "active", "completed"].map((f) => (
            <button
              key={f}
              className={filter === f ? "selected" : ""}
              onClick={() => todoApp.act("setFilter", { newFilter: f })}
            >
              {f}
            </button>
          ))}
        </div>
      </footer>
    </div>
  );
}

Form with Validation

A form example with client-side validation and server submission.

Domain (MEL)

mel
domain ContactForm {
  state {
    name: string = ""
    email: string = ""
    message: string = ""
    errors: {
      name: string | null,
      email: string | null,
      message: string | null
    } = { name: null, email: null, message: null }
    status: string = "idle"
    submitResult: string | null = null
  }

  // Computed validation
  computed isValid = and(
    and(
      gt(len(name), 0),
      isNull(errors.name)
    ),
    and(
      gt(len(email), 0),
      isNull(errors.email)
    )
  )

  // Update field
  action updateField(field: string, value: string) {
    once(updateFieldIntent) {
      patch updateFieldIntent = $meta.intentId
      patch $path(field) = value

      // Clear error when user types
      patch errors = merge(errors, { $key(field): null })
    }
  }

  // Validate field
  action validateField(field: string) {
    once(validateFieldIntent) {
      patch validateFieldIntent = $meta.intentId

      when eq(field, "email") {
        when not(contains(email, "@")) {
          patch errors = merge(errors, { email: "Invalid email format" })
        }
      }

      when eq(field, "name") {
        when lt(len(name), 2) {
          patch errors = merge(errors, { name: "Name must be at least 2 characters" })
        }
      }
    }
  }

  // Submit form
  action submit() {
    once(submitIntent) {
      patch submitIntent = $meta.intentId
      patch status = "submitting"
      effect api.submitForm({
        name: name,
        email: email,
        message: message
      })
    }
  }

  // Reset form
  action reset() {
    once(resetIntent) {
      patch resetIntent = $meta.intentId
      patch name = ""
      patch email = ""
      patch message = ""
      patch errors = { name: null, email: null, message: null }
      patch status = "idle"
      patch submitResult = null
    }
  }
}

App & Services

typescript
const services: ServiceMap = {
  "api.submitForm": async (params, ctx) => {
    try {
      const response = await fetch("/api/contact", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(params),
      });

      if (!response.ok) {
        throw new Error("Submission failed");
      }

      return [
        ctx.patch.set("status", "success"),
        ctx.patch.set("submitResult", "Thank you! We'll be in touch."),
      ];
    } catch (error) {
      return [
        ctx.patch.set("status", "error"),
        ctx.patch.set("submitResult", error.message),
      ];
    }
  },
};

export const formApp = createApp(FormMel, { services });

React Component

tsx
function ContactForm() {
  const [state, setState] = useState<AppState<FormData> | null>(null);

  useEffect(() => {
    formApp.ready().then(() => {
      setState(formApp.getState<FormData>());
      return formApp.subscribe((s) => s, (s) => setState(s as AppState<FormData>));
    });
  }, []);

  if (!state) return null;

  const { name, email, message, errors, status, submitResult } = state.data;

  return (
    <form onSubmit={(e) => { e.preventDefault(); formApp.act("submit"); }}>
      <div>
        <input
          value={name}
          onChange={(e) => formApp.act("updateField", { field: "name", value: e.target.value })}
          onBlur={() => formApp.act("validateField", { field: "name" })}
          placeholder="Name"
        />
        {errors.name && <span className="error">{errors.name}</span>}
      </div>

      <div>
        <input
          value={email}
          onChange={(e) => formApp.act("updateField", { field: "email", value: e.target.value })}
          onBlur={() => formApp.act("validateField", { field: "email" })}
          placeholder="Email"
        />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>

      <div>
        <textarea
          value={message}
          onChange={(e) => formApp.act("updateField", { field: "message", value: e.target.value })}
          placeholder="Message"
        />
      </div>

      <button
        type="submit"
        disabled={!(state.computed.isValid as boolean) || status === "submitting"}
      >
        {status === "submitting" ? "Sending..." : "Send"}
      </button>

      {submitResult && (
        <div className={status === "success" ? "success" : "error"}>
          {submitResult}
        </div>
      )}
    </form>
  );
}

Data Sync Pattern

Synchronizing local state with a remote server.

Domain (MEL)

mel
domain DataSync {
  state {
    items: Array<Item> = []
    syncStatus: string = "idle"
    lastSyncAt: number | null = null
    pendingChanges: number = 0
  }

  // Pull from server
  action sync() {
    once(syncIntent) {
      patch syncIntent = $meta.intentId
      patch syncStatus = "syncing"
      effect api.fetchItems({})
    }
  }

  // Local add with server sync
  action addItem(name: string) {
    once(addItemIntent) {
      patch addItemIntent = $meta.intentId
      let newItem = {
        id: $system.uuid,
        name: name,
        synced: false
      }
      patch items = append(items, newItem)
      patch pendingChanges = add(pendingChanges, 1)
      effect api.createItem(newItem)
    }
  }

  // Mark item as synced
  action markSynced(id: string) {
    once(markSyncedIntent) {
      patch markSyncedIntent = $meta.intentId
      patch items = map(items, fn(item) =>
        cond(eq(item.id, id),
          merge(item, { synced: true }),
          item
        )
      )
      patch pendingChanges = sub(pendingChanges, 1)
    }
  }
}

Services with Retry

typescript
const services: ServiceMap = {
  "api.fetchItems": async (params, ctx) => {
    try {
      const items = await fetchWithRetry("/api/items", 3);
      return [
        ctx.patch.set("items", items),
        ctx.patch.set("syncStatus", "synced"),
        ctx.patch.set("lastSyncAt", Date.now()),
      ];
    } catch (error) {
      return [
        ctx.patch.set("syncStatus", "error"),
      ];
    }
  },

  "api.createItem": async (params, ctx) => {
    try {
      await fetchWithRetry("/api/items", 3, {
        method: "POST",
        body: JSON.stringify(params),
      });

      // Trigger mark synced via enqueue
      return [
        // Patches applied immediately
      ];
    } catch (error) {
      // Item remains with synced: false
      return [];
    }
  },
};

async function fetchWithRetry(url: string, retries: number, opts?: RequestInit) {
  for (let i = 0; i < retries; i++) {
    try {
      const res = await fetch(url, opts);
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      return res.json();
    } catch (error) {
      if (i === retries - 1) throw error;
      await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
    }
  }
}

Multi-Branch Workflow

Document editing with draft/publish workflow.

Domain (MEL)

mel
domain Document {
  state {
    title: string = ""
    content: string = ""
    published: boolean = false
    publishedAt: number | null = null
    version: number = 1
  }

  action updateTitle(title: string) {
    once(updateTitleIntent) {
      patch updateTitleIntent = $meta.intentId
      patch title = title
      patch version = add(version, 1)
    }
  }

  action updateContent(content: string) {
    once(updateContentIntent) {
      patch updateContentIntent = $meta.intentId
      patch content = content
      patch version = add(version, 1)
    }
  }

  action publish() {
    once(publishIntent) {
      patch publishIntent = $meta.intentId
      patch published = true
      patch publishedAt = $system.now
    }
  }
}

Workflow Implementation

typescript
class DocumentEditor {
  private draftBranch: Branch | null = null;

  async startEditing() {
    // Create draft branch
    this.draftBranch = await app.fork({
      name: `draft-${Date.now()}`,
    });
  }

  async updateTitle(title: string) {
    if (!this.draftBranch) throw new Error("Not editing");
    await this.draftBranch.act("updateTitle", { title }).done();
  }

  async updateContent(content: string) {
    if (!this.draftBranch) throw new Error("Not editing");
    await this.draftBranch.act("updateContent", { content }).done();
  }

  getDraftState() {
    return this.draftBranch?.getState();
  }

  async discardDraft() {
    // Just switch back to main
    await app.switchBranch("main");
    this.draftBranch = null;
  }

  async publishDraft() {
    if (!this.draftBranch) throw new Error("No draft");

    // Get draft content
    const draft = this.draftBranch.getState();

    // Switch to main
    await app.switchBranch("main");

    // Apply changes to main
    await app.act("updateTitle", { title: draft.data.title }).done();
    await app.act("updateContent", { content: draft.data.content }).done();
    await app.act("publish").done();

    this.draftBranch = null;
  }
}

Real-Time Collaboration

Multi-user editing with session tracking.

typescript
class CollaborativeEditor {
  private sessions = new Map<string, Session>();
  private cursors = new Map<string, { x: number; y: number }>();

  join(userId: string, userName: string): Session {
    const session = app.session(userId, {
      kind: "human",
      name: userName,
    });
    this.sessions.set(userId, session);
    return session;
  }

  leave(userId: string) {
    this.sessions.delete(userId);
    this.cursors.delete(userId);
  }

  updateCursor(userId: string, x: number, y: number) {
    this.cursors.set(userId, { x, y });
    // Broadcast to other users
    this.broadcast("cursor", { userId, x, y });
  }

  async edit(userId: string, content: string) {
    const session = this.sessions.get(userId);
    if (!session) throw new Error("User not in session");

    await session.act("updateContent", { content }).done();
  }

  getCursors() {
    return Object.fromEntries(this.cursors);
  }

  private broadcast(type: string, data: unknown) {
    // WebSocket broadcast implementation
  }
}

More Examples

For more complete examples, check out the example apps in the repository:

  • todo-app — Full todo application with React
  • logistics-app — Complex multi-step workflow example

Clone the repository and explore:

bash
git clone https://github.com/manifesto-ai/core
cd core
pnpm install
pnpm dev:todo     # Run todo app
pnpm dev:logistics # Run logistics app