Skip to content

Building a Todo App ​

A small app is one MEL domain plus one activated runtime plus one presentation layer.

This page is a map of the pieces. For the full hands-on walkthrough, use Building a Todo App.

Domain ​

mel
domain TodoApp {
  type Todo = {
    id: string,
    title: string,
    completed: boolean
  }

  state {
    todos: Array<Todo> = []
    filterMode: "all" | "active" | "completed" = "all"
  }

  computed todoCount = len(todos)
  computed completedCount = len(filter(todos, $item.completed))
  computed activeCount = todoCount - completedCount
  computed hasCompleted = completedCount > 0

  action addTodo(title: string)
    dispatchable when trim(title) != "" {
    onceIntent {
      patch todos = append(todos, {
        id: $runtime.random.uuid,
        title: trim(title),
        completed: false
      })
    }
  }

  action toggleTodo(id: string)
    available when todoCount > 0
    dispatchable when len(filter(todos, $item.id == id)) > 0 {
    onceIntent {
      patch todos = map(todos,
        $item.id == id
          ? { id: $item.id, title: $item.title, completed: !$item.completed }
          : $item
      )
    }
  }
}

Runtime ​

typescript
import { createManifesto } from "@manifesto-ai/sdk";
import TodoMel from "./todo.mel";

export const app = createManifesto(TodoMel, {}).activate();

await app.action.addTodo.submit("Write a domain");

Presentation ​

typescript
function renderTodos() {
  const snapshot = app.snapshot();
  console.log(snapshot.state.todos);
  console.log(snapshot.computed["todoCount"]);
  console.log(snapshot.computed["activeCount"]);
}

renderTodos();
app.observe.state((snapshot) => snapshot.state.todos, renderTodos);

Keep framework code outside MEL. The same domain can sit behind React, a backend route, a CLI, or an agent turn.

Next ​

Try the hands-on todo tutorial, then add Bundler Setup and Code Generation. After that, connect React and compare with Runnable Examples.