Typora has no plugin API. The best-known community plugin system, typora_plugin, runs on Windows and Linux only. There Typora is an Electron app, and a plugin can reach Node and the file system from the page. On macOS Typora is a native app built on WKWebView, with no Node inside. Typora Plugin Lite starts from that gap. A short injected loader starts an ES module core, and a platform layer maps file, shell and path calls to Typora’s own bridge on macOS and to Node on Windows and Linux. Plugins never call either directly.

It is for people who write in Typora every day and want a few things it lacks: a file finder that ranks by how you work, code blocks you can copy from, margin notes, adjustable writing width, links between notes. It is also for people who want a script or an agent to read and drive the open note. The remote-control plugin puts a JSON-RPC interface on the local loopback, so an external process can read the document, open files, switch folders and run plugin commands.

For
Typora users who want plugins on macOS as well as Windows and Linux, and anyone who wants a script or agent to drive Typora
Runs on
macOS (WKWebView), Windows and Linux (Electron); every screenshot here is Typora 1.14.9 for macOS
Latest
v0.1.3, 12 August 2026; main has moved on since, as the log below shows
License
MIT
Built with
TypeScript, esbuild, and Node’s own test runner with happy-dom
Install
from source with pnpm and Node 22 or later, then the installer for your platform

How it gets into Typora

The installer finds Typora, backs up its window.html, adds one <script> tag for loader.js, and copies the core and the plugins next to it. On macOS that means inside Typora.app, because WKWebView loads file:// scripts only from within the app bundle. The installer then re-signs the bundle so macOS still opens it.

The loader is an IIFE of about 70 lines with comments. It finds its own script tag, works out where it lives, adds core.js as another script tag, and calls bootstrap(). Everything else lives in the core.

graph TD
    App[Typora window.html] --> Loader[loader.js]
    Loader --> Core[core.js]
    Core --> Plat[Platform layer: fs, shell, path]
    Core --> PM[Plugin manager]
    Core --> UI[Plugin Center, toasts]
    Plat --> Mac[macOS: Typora bridge]
    Plat --> Node[Windows and Linux: Node]
    PM --> Plugins[Plugins, each its own ES module]

Plugins load lazily, in the manner of lazy.nvim. Each one declares in its manifest.json when it should start: at startup, on an event, on a command or on a hotkey. Title Shift, which moves headings up or down a level, does nothing until you press its key:

{
  "id": "title-shift",
  "name": "Title Shift",
  "version": "0.1.0",
  "description": "Increase or decrease heading levels",
  "main": "main.js",
  "loading": {
    "startup": false,
    "hotkey": ["Mod+Shift+Up", "Mod+Shift+Down"]
  }
}

The manager binds the hotkey to a stub. The first press loads the module, removes the stub, and replays the key, so the first use behaves like every later one. Settings, logs and caches live outside Typora’s own files, under ~/Library/Application Support/abnerworks.Typora/plugins/data/ on macOS and ~/.local/Typora/data/ on Linux, so a Typora update does not wipe them.

The Plugin Center

Cmd+` opens the Plugin Center, shown at the top of this page. The left column lists every plugin with its version, a switch, and how it loads. The right column shows the selected plugin’s settings. The core draws them from a schema each plugin declares, so a plugin author writes no UI: switches, text and number fields, choices and masked secrets, in groups, with validation and error states. A setting is saved before the panel closes, and a newer value is never overwritten by an older write that finished late. The footer lists every hotkey in use. The panel reads the theme’s --tpl-ui-* colours, so with the Claude-like theme it matches the rest of the window in light and dark.

These are the twelve plugins that ship:

PluginWhat it doesLoads
Quick OpenFinds files, folders and text by name, path or contentstartup, Cmd+. or Cmd+‘
Fence EnhanceRenders every code block early; line-number gutter, copy button, tab markers, indent guidesstartup
Code ViewerOpens non-Markdown text and code files read-onlystartup
SidenoteTurns sidenote spans into numbered margin notes in the editorstartup, Cmd+Opt+S
WiderDefault, wide and full writing widthsstartup, Cmd+[ and Cmd+]
Note AssistantRenders [[wiki-links]] and opens a related-notes palettestartup, Cmd+;
Tree GuidesDraws the file tree’s guide lines and lights the branch of the open filestartup
TrailBack and forward across the last notes you visitedstartup, Cmd+Alt+← and →
Title ShiftRaises or lowers heading levelsCmd+Shift+↑ and ↓
Markdown PaddingPuts a space between CJK and Latin textstartup, Cmd+Shift+Space
Theme PackKeeps a theme from GitHub in Typora’s themes folderstartup
Remote ControlLoopback JSON-RPC for scripts and agentsstartup

Writing with it

Code blocks

Typora renders only the first eight code blocks of a note up front and leaves the rest grey until you scroll onto them. Fence Enhance renders all of them in the background, top to bottom, so a long technical note does not jump while you scroll.

A note called Build pipeline in Typora. A TypeScript code block has line numbers 1 to 14 in a narrow gutter and a Copy button in its top right corner. A Makefile block below shows each leading tab as a small arrow followed by a thin vertical guide.
The Copy button appears when the pointer is over a block. In the Makefile, each tab shows as an arrow, so a line indented with spaces stands out.

It adds a Copy button, marks tabs and draws indent guides. It also sizes the line-number gutter to each block: a 14-line block gets two digits, a 1,200-line block four. The theme reads that width from a CSS variable the plugin sets.

Writing width

Wider gives the writing column three widths. Default keeps the column at up to 860 pixels, a comfortable line for long reading. Wide and full open it up for tables, code and logs. Cmd+] widens, Cmd+[ narrows, and a short toast names the mode. There is no button on the page. The widths come from the space Typora actually gives the editor, not from the window, so with the sidebar open or the window narrow, wide and full shrink to fit instead of adding a horizontal scroll bar.

Margin notes

A sidenote is plain inline HTML: <span class="sidenote">...</span>. Typora shows the class only as text, so CSS alone cannot find these spans inside the editor. The Sidenote plugin finds them, numbers them, and moves them into a layer beside the text when the window is wide enough.

Typora with the words Shorter lines break the reading rhythm selected in a paragraph. A small floating menu above the selection holds a plus button, the label Add sidenote and the shortcut Cmd+Opt+S.
Select text, and Add sidenote turns it into a margin note.

In a narrow window they stay inline. A note inside a table is drawn in the outer margin, so the table keeps its horizontal scroll. When the caret enters a paragraph, its notes return to the text so you can edit them. Cmd+Opt+S wraps the selection. The theme page shows the same notes in a wide and a narrow window.

Note Assistant draws [[target|title]] as a link anywhere in the body. It shows the title and opens the target on click. It never changes a character of the file: it splits the text into spans whose combined text is byte for byte the original, and hides the brackets and path with CSS.

A paragraph in Typora that ends with Related reading: Line length and rhythm and the build notes in Build pipeline. Both titles are drawn as underlined links in the accent colour. Two margin notes sit inline in the paragraphs above.
Line length and rhythm and Build pipeline are wiki links. The file still holds the full [[path|title]] text.

The block holding the caret goes back to raw Markdown, the way Typora treats its own inline syntax. A link whose target is missing from the index is drawn dashed.

The source of that last line, as it sits on disk:

Related reading: [[reading/line-length|Line length and rhythm]] and the build notes in [[projects/static-site/build-pipeline|Build pipeline]].

Cmd+; opens a palette of related notes for the open file, and Alt+Enter inserts a link to the chosen one at the caret. Both read .note-assistant/graph.json at the root of the vault. The script that builds that file is not part of this repository.

Code files

Open a .py or .ts file in Typora and it is parsed as Markdown: # comment becomes a heading and backticks disappear. Code Viewer opens text and code files read-only instead, with line numbers, highlighting and a language picker.

A read-only view in Typora of a TypeScript file called render.ts, with a language picker set to TypeScript. Every line has a number; spaces show as faint dots and nested lines have thin vertical indent guides.
render.ts in Code Viewer, with whitespace markers and indent guides switched on.

It never touches Typora’s document model, and it blocks saving for any file that is not Markdown, so the original cannot be rewritten by autosave or by quitting. An early version did put a fenced copy into the editor, and Typora wrote that copy back to disk on quit. The current design follows from that.

Finding files

Quick Open opens with Cmd+. and has three views over one search core: files, folders and content. With an empty box it lists recent files, ranked by how recently and how often you opened them. The index covers every text file it can open safely, not only Markdown. A small query language works in every view:

You typeYou get
pipeFiles whose names match, best match first
type:content scope:ops/ redisA ripgrep search for redis in the Markdown files under ops/
/ then a pathWalk the open folder by path; Tab completes to the common prefix
// or ~/Walk from the file system root or the home folder

The labels in Quick Open’s panel are in Chinese for now, so this page has no screenshot of it.

The rest

Tree Guides draws the file tree’s guide lines as one path per folder and lights the branch that holds the open file. While it runs, the theme’s own CSS connectors step aside. Trail keeps the last three notes in each direction and shows two quiet arrows in the corner.

The Typora file tree for a folder called field-notes. Thin grey guide lines join each folder to its children. The line from the reading folder down to margin-notes.md, the open file, is drawn in the accent colour.
The open file’s branch is lit.

Markdown Padding puts a space between Chinese and Latin characters. Theme Pack keeps a theme from a GitHub repository in Typora’s themes folder, fetching only the files its theme-pack.json lists. It adds choices to the Themes menu and never switches the theme you use.

Remote control

remote-control starts a small Node process, the sidecar, that listens on 127.0.0.1:5619. Every Typora window connects to it as a session, and so does every client. A client must authenticate with a random token stored in the plugin’s settings.json. Calls to typora.* are forwarded to the window in focus; when that window closes, the sidecar falls back to the window used most recently before it. The sidecar watches Typora’s process and exits within five seconds of Typora dying, so a crash does not leave the port held.

The public typora-plugin-remote-skill packages a Node client and a CLI as an agent skill for Claude Code, Codex and other clients that read skills. This is the CLI against the demo vault used for the screenshots:

$ node scripts/typora-remote-cli.mjs ping
"pong"
$ node scripts/typora-remote-cli.mjs context | jq 'del(.commands)'
{
  "filePath": "/private/tmp/tpl-demo/field-notes/journal/2026-10-21.md",
  "fileName": "2026-10-21.md",
  "mountFolder": "/private/tmp/tpl-demo/field-notes",
  "watchedFolder": null,
  "sourceMode": false,
  "hasUnsavedChanges": false
}
$ node scripts/typora-remote-cli.mjs document | jq -r .markdown
<<<TPL_DOC_START id="848210745e7f" trust="untrusted">>>
# Tuesday 21 October
 
The render step now skips drafts. Next: the deploy checklist in [[projects/static-site/deploy-checklist|Deploy checklist]].
 
<<<TPL_DOC_END id="848210745e7f">>>

The markers around the document are there for agents. Each read gets a fresh random id and is labelled untrusted, so an agent can treat a note that says “ignore your instructions” as quoted data rather than as part of its conversation.

An agent with this connection can read the open note and the folder it sits in, replace the document or insert text at the caret, switch between source and rendered mode, open a file or folder, list and switch plugins, and run any Typora or plugin command. system.listMethods returns the whole surface as data, with each method’s tier and whether it is reachable now, so a client does not have to guess. The 25 methods sit in five tiers:

Tier, and what it needsMethods
open: nothingsession.authenticate
auth: a valid tokensystem.ping, system.getInfo, system.listMethods, system.shutdown, session.claimTypora
typora: a token and a connected Typora window14 typora.* methods: context, document, selection, insert, source mode, open file or folder, commands, plugins
exec: a token and allowExecexec.run, exec.start, exec.kill, exec.list
eval: a token, a connected window and allowEvaltypora.eval

Shell and eval stay off

Running shell commands and evaluating JavaScript in Typora are separate switches, and both are off by default. The settings say plainly which is worse: JavaScript in the renderer can start a shell whatever the shell switch says. On macOS typora.eval runs as indirect eval in the page.

The Security section of Remote Control's settings in the Plugin Center: a masked bearer token with Reveal, Copy and Regenerate buttons, then two switches, Allow shell execution (DANGEROUS) and Allow JS evaluation in Typora (MAXIMALLY DANGEROUS), each with a paragraph explaining the risk.
Both switches are on in this install. They ship off.

A synchronous infinite loop cannot be interrupted there, so its timeout applies only to async code. Forwarded typora.* calls time out after 30 seconds, so a window that hangs returns an error instead of a request that never ends.

Session archive

The repository also ships a command-line tool that turns a Codex or Claude Code session into a Markdown note for Typora. It keeps the visible turns, tool calls and results, and leaves out hidden reasoning and instructions. It replaces the home folder with ~, redacts common API keys, tokens and private keys, turns raw HTML into text, and writes the note with 0600 permissions through a temporary file. A long session can be split into an index and parts of a size you choose:

$ npm run build
$ node dist/tools/session-archive/index.mjs codex <session-id> --output-dir ~/Notes/Agents --max-file-size 4MiB
$ node dist/tools/session-archive/index.mjs claude <session-id> --mode answers -o session.md

How it is built and tested

The repository is a pnpm workspace. esbuild builds the loader as an IIFE, the core, each plugin, and the sidecar. Plugins import the core through a shim that the build script generates from the core’s real export table. Before that, a plugin could compile against a name the core no longer exported and get undefined at run time inside Typora.

The tests run on Node’s own test runner with happy-dom for the DOM. They cover the parts that break quietly: Quick Open’s scoring, query parser, path mode and recent-file ranking; the remote-control gates, timeouts and boundary markers; the sidecar’s watch on its parent process; sidenote geometry and lifecycle; Wider’s layout; and how the Plugin Center saves settings. On 22 October 2026:

$ npm test
# tests 382
# suites 0
# pass 382
# fail 0

Before v0.1.3 the release ran 261 tests, the type check, a production build and a manual check of Quick Open, Wider and Sidenote in Typora on macOS.

Install

  1. Build it. You need Node 22 or later and pnpm. Run git clone https://github.com/lr00rl/typora-plugin-lite.git, then pnpm install and pnpm build inside the folder.
  2. Run the installer. On macOS, ./packages/installer/install.sh, or -p /path/to/Typora.app if Typora is not in /Applications; macOS may ask for your password while it re-signs the app. On Linux, sudo ./packages/installer/install.sh. On Windows, an administrator PowerShell runs packages\installer\bin\install-windows.ps1.
  3. Restart Typora. The developer console (Option+Cmd+I on macOS, Shift+F12 elsewhere) should print [tpl:loader] done. Cmd+` opens the Plugin Center.
  4. Update or remove it. To update, pull, build and run the installer again. To remove it, copy window.html.tpl-backup back over window.html in Typora’s resources folder, or reinstall Typora.

Limits

The project is still under active development, and the README says so: the architecture and the plugin API can change without notice. There is no prebuilt download; you build from source.

The installer edits Typora’s own files. On macOS it re-signs Typora.app with an ad hoc signature, which replaces Typora’s own. A Typora update restores the original window.html, so after each update you run the installer again.

Some panels are only in Chinese for now: Quick Open, the Note Assistant palette, Trail’s tooltips and Code Viewer’s read-only badge. The Plugin Center, settings and the plugins’ editor behaviour are in English. Note Assistant’s palette needs a graph.json that this repository does not build.

The remote-control token is the only thing between a local process and your editor. Anyone who holds it can pose as a Typora window and take over routing, or call system.shutdown. It sits in a settings file in your user’s application data, so on a shared machine, whoever can read that file can drive Typora. Regenerate in the Plugin Center makes a new token, restarts the sidecar and drops every session.

The theme half of this work is the Claude-like theme, which Theme Pack installs by default; each works without the other. Working on both is what led to Noto, an editor where these choices are made from the start.