Dumi Download for Mac

For AI agents

The file is the API.

Everything Dumi knows is one JSON file on the Mac. Read it, edit it, write it back — Dumi notices within a second, and a task your agent finishes grows the bonsai exactly as if you had ticked it. No API keys, no server, no SDK. The same text, for pasting into a system prompt: llms.txt.

Where

~/Library/Application Support/Dumi/data.json

If the environment variable ISLAND_DATA is set when Dumi starts, that path is used instead.

Shape

A JSON object. Two keys are yours to edit; leave the others (sessions, timer, prefs, bonsai) exactly as they are.

{
  "lists": [
    { "id": "6D2B3A1C-…", "name": "My Tasks" }
  ],
  "tasks": [
    {
      "id": "F0A1…",                       // UUID, upper-case
      "listID": "6D2B3A1C-…",              // id of a list above
      "parentID": "…",                     // optional: makes this a subtask
      "title": "Reply to Sarah",
      "notes": "Re: Friday offsite",       // optional
      "due": "2026-09-18T00:00:00Z",       // optional, ISO 8601
      "starred": false,
      "createdAt": "2026-09-14T08:12:00Z",
      "completedAt": "2026-09-14T09:30:00Z", // present = done; absent = open
      "order": -3,                         // lower sits higher in its list
      "rewarded": true                     // Dumi's own bookkeeping; don't set it
    }
  ],
  "sessions": [ … ], "timer": { … }, "prefs": { … }, "bonsai": { … }
}

Read

Open tasks are those without completedAt; top-level ones have no parentID. Sort by order ascending within a list.

jq '[.tasks[] | select(.completedAt == null and .parentID == null)
     | {id, title, due, starred}]' \
  ~/Library/Application\ Support/Dumi/data.json

Add

Append an object to tasks. Only title is required: a missing id gets one, a missing or unknown listID lands in the first list, a missing order puts the task at the top, like a task typed into the island.

{ "title": "Book flights to Tokyo", "listID": "6D2B3A1C-…", "due": "2026-09-18T00:00:00Z" }

Complete, reopen, edit

Write

Read the whole file, change it, write the whole file back atomically — to a temporary file in the same folder, then rename over data.json. Dumi writes the same way. Keep the other top-level keys untouched. If Dumi is running it picks the change up within about a second and shows the growth; if not, it reads the file on launch.

import json, os, uuid, datetime, tempfile
P = os.path.expanduser("~/Library/Application Support/Dumi/data.json")
d = json.load(open(P))
now = datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")

# complete every open task whose title starts with "Reply"
for t in d["tasks"]:
    if "completedAt" not in t and t["title"].startswith("Reply"):
        t["completedAt"] = now

# add one
d["tasks"].append({"id": str(uuid.uuid4()).upper(), "listID": d["lists"][0]["id"],
                   "title": "Send the deck", "createdAt": now})

fd, tmp = tempfile.mkstemp(dir=os.path.dirname(P), suffix=".json")
with os.fdopen(fd, "w") as f: json.dump(d, f, indent=2)
os.replace(tmp, P)

Rules

← Back to Dumi