MojoPad

The Local API

MojoPad has a local API, and anything running as you on this Mac can use it. A Shortcut that files a note into today’s journal. A shell script that pulls every page of a kind into a report. A Keyboard Maestro macro that searches your wiki by meaning from any app. Another program you wrote, reading a page by name. None of it needs an AI, an account, or the internet.

Not to be confused with the mojo API, which is a different thing with a similar name. That one runs inside a page, in scriptlets and plugins, and is described under Scripting. This one is spoken to from outside MojoPad, over a connection on your own machine. If you are writing something that is not a MojoPad page, this is the one you want.

The same door an assistant uses is open to anything else you run. When Let agents reach the wiki that’s open right now is on, MojoPad answers a small set of requests on your own machine — so a shell script, a Shortcut, Keyboard Maestro, or any app you write can read from and add to the wiki you have open. Nothing on the internet can: the door is on 127.0.0.1, it needs a key, and it refuses anything that looks like it came from a web page.

Finding it. Each time MojoPad starts it writes ~/.mojopad/bridge.json — the port it is listening on and a fresh key, readable only by you. A script reads that file and puts the key in an Authorization: Bearer header. The key changes every launch, so nothing can hold one from last week.

PORT=$(python3 -c "import json;print(json.load(open('$HOME/.mojopad/bridge.json'))['port'])")
TOK=$(python3 -c "import json;print(json.load(open('$HOME/.mojopad/bridge.json'))['token'])")

curl -s -H "Authorization: Bearer $TOK" http://127.0.0.1:$PORT/info

What you can ask for

Everything below is POST with a JSON body, except /info. ref means a page’s name or its id.

AskBodyAnswers with
/infothe app version, the contract version, and which wiki is open
/pages{"limit": 200, "offset": 0}every page’s name, id, type and when it changed
/page{"ref": "Lend Lease"}that page’s words, tags and other names
/props{"ref": "Lend Lease"}its typed properties, each with where its value came from
/search{"query": "…", "k": 6}pages ranked by meaning
/ask{"question": "…"}an answer from your local model, with its sources
/add{"title": "…", "content": "…"}makes a page
/append{"ref": "…", "text": "…"}adds to the end of a page
/today{"text": "…"}adds to today’s note

The three marked ✎ change your wiki, and they are refused unless Allow agents to modify wikis you already have is also on. Reading is never affected by that switch.

The rules it keeps, so you don’t have to

  • A locked page stays locked. Reading one tells you it exists and that it is locked; it does not hand over the words. Nothing can be added to one either.
  • Text that arrives this way cannot run. A script may put words on your page; it may not make your page do things. Text that would add a scriptlet is refused outright — not cleaned up and accepted. That distinction is the whole of it: tidying the text away can be worked around by sending it in two halves, or in a shape that rebuilds itself once the middle is removed, whereas a refusal cannot. MojoPad works out what the page would become and asks the part of itself that actually runs scriptlets how many it can see; if the answer went up, the whole addition is turned down.
  • A page that is a program is not a page to add a line to. Nothing can be added to an Event: or Plugin: page from outside — their words are the code, and an Event: Open page runs every time the document is opened.
  • A board is a layout, not text. Storyboards and mind maps refuse an addition rather than have a line of prose written into the shape that holds their cards.
  • It answers for the wiki you have open. There is no way to name a different one. For a document that isn’t open, the file-based tools an assistant uses are the right door — see the rest of this chapter.

The contract has its own version. /info reports api alongside the app version. The app version moves every release; the api number moves only when the shape of a request or an answer changes, so a script can tell the difference between MojoPad being newer and MojoPad being different.