Skip to content

Host API ​

Extensions talk to the launcher over newline-delimited JSON on stdio (NDJSON), UTF-8 without BOM.

Handshake ​

Host → extension:

json
{"type":"hello","host":"1.1.37","dataDir":"C:\\...\\PCL"}

Extension → host:

json
{"type":"ready","name":"Hello Go"}

After that both directions use {"type": "...", "id": "...", "payload": {...}}. Requests carry an id and must be answered with the same id; the default timeout is 10 seconds.

Message types ​

Extension → host ​

TypePayloadNotes
ready{name}Handshake done
notify{title, text, level}info / warn / error
log{text}Write to the extension log
fs.read{path}Needs fs.read
fs.write{path, data}Needs fs.write, base64 data
http{method, url, headers, body}Needs net
instances{}Instance list
versions{}Version list
launch{instance, version}Needs launch
ui.page{title, html}Needs ui
settings.get{key}Read a launcher setting
settings.set{key, value}Write a launcher setting

Host → extension ​

TypePayloadNotes
hello{host, dataDir, locale}First message
resp{ok, data, error}Response to a request
event{name, data}launch.before, launch.after, instance.created, shutdown
ping{}Every 30 s; answer with pong

Permission failures look like:

json
{"type":"resp","id":"7","payload":{"ok":false,"error":"permission denied: net"}}

Go example ​

go
package main

import tmlext "github.com/TYWStudio/TML/extensions/sdk/go"

// 业务入口:两个方法都可以留空
type ext struct{}

func (ext) Ready() {
	tmlext.Log("info", "拓展已加载")
	tmlext.Toast("Hello")
}

func (ext) OnEvent(e tmlext.Event) {
	tmlext.Log("info", e.Type)
}

func main() { tmlext.Run(ext{}) }

Rust example ​

rust
use tml_ext::{Event, Ext, Handler};

struct Ext0;

impl Handler for Ext0 {
    fn ready(&mut self, ext: &mut Ext) {
        ext.log("info", "拓展已加载");
        ext.toast("Hello");
    }

    fn event(&mut self, ext: &mut Ext, ev: Event) {
        ext.log("info", &ev.kind);
    }
}

fn main() { tml_ext::run(Ext0); }

Rules that save you pain ​

  1. Answer hello with ready quickly; do heavy work later.
  2. Keep the main loop reading stdin; push long tasks to a worker thread.
  3. Handle shutdown and exit on your own.
  4. Never print debug output to stdout — it is the protocol channel. Use log or stderr.

Limits ​

  • 1 MiB per message.
  • 10 s per request.
  • 4 concurrent requests per extension.
  • ui.page HTML is sanitised: no <script>, no on* attributes, no external iframes.