Repository navigation
Adding a host
A host is an app the editor is shown in: Obsidian, the browser editor from Claude Code and, later, the standalone app
and VS Code. The editor draws everything itself with the web page. A host gives only the few things that it alone
decides, through one interface, DisplayHost.
This page describes main, which the nightly build is made from. The latest release is 0.7.0: ✅ is in it, 🌙 is only in the nightly build, 🟡 is being built and ⏳ is planned.
flowchart LR
H["Your app<br/><i>:Host</i>"] -->|installHost, once| I{{"DisplayHost<br/><i>:Interface</i>"}}
I -->|icons, notices, menus, language| D["Display layer<br/><i>:Layer</i>"]
D --> C["Core<br/><i>:Layer</i>"]
T["Host contract<br/><i>:Contract</i>"] -->|checks| H
- Write an adapter: an object with the members below, made from your app's own icons, notices and menus.
- Call
installHost(yourAdapter)once, before anything is drawn. - Run the host contract against your adapter in your tests.
The interface is at contract version 3. The version changes with every change to DisplayHost.
Read from
packages/core/src/display/host.ts:
| Member | What it is for | |
|---|---|---|
icon |
Required | Draws the icon named name into el, replacing what it held. |
isPhone |
Required | Whether the screen is a phone's, asked each time it matters, as it can change with the window. |
notice |
Required | Tells the person something briefly, as a notice does. |
menu |
Required | Shows a menu of entries with its top left at at, in the window of doc. |
noInlineStyle |
Optional | Whether the host's content security policy forbids inline styles (style-src without 'unsafe-inline'), as the browser editor's page does (editor spec §26, cc_csp). The core writes the colours of a drawing as style attributes. Where they are forbidden the layer sets the same declarations through the CSSOM, which the policy allows. No style attribute is ever parsed from markup. Not set: styles stay attributes, as Obsidian has them. |
language |
Optional | The language the host shows itself in, as a language tag: Obsidian's own, the display language of VS Code, the system's for the app and the browser page (editor spec §42, language_follows_host). The words are said in it when a translation for it is added, else in UK English. Not set: UK English. |
direction |
Optional | The direction the host reads in, when it sets one of its own (editor spec §42, rtl_mirrors). Not set: the direction of its language, so an Arabic or Hebrew host mirrors the interface with no word from it. |
Obsidian's adapter is the shortest example:
packages/obsidian/src/display-host.ts.
The browser editor's is
packages/claude-code/page/browser-host.ts.
hostContract(make) gives every check. make returns a fresh adapter and a probe, which lets the checks see the
notices and menus your app showed.
import { hostContract } from '@thoughtknot/core/display/host-contract';
for (const check of hostContract(makeMyHost)) await check.run();- ☑ an icon is drawn into its element, once, whether the host knows its name or not
- ☑ the phone test is a true or false, asked each time
- ☑ a notice shows its message as text, as given, markup and all
- ☑ a menu shows its rows in order, with their lines, ticks and warnings
- ☑ choosing a menu row runs its action once, and no other row’s
- ☑ the style policy is said as true or false, or left unsaid
- ☑ the language is a language tag, or left unsaid
- ☑ the direction is ltr or rtl, or left unsaid
- Colours. Map your app's theme to the design tokens in one place. Your theme always wins. The tokens are listed on Writing a plug-in.
-
Language and direction. Give
language(), anddirection()if your app sets its own. The words and the mirroring follow with no other work. -
Security. If your app forbids inline styles, set
noInlineStyle. The layer then sets styles a safe way.
flowchart LR
s10(["§10 Hosts — one core, Obsidian first, VS Code later<br/><i>:Section</i>"])
subgraph g_released["✅ Released"]
host_free_core["host_free_core<br/><i>:Requirement</i>"]
format_as_library["format_as_library<br/><i>:Requirement</i>"]
lsp_shapes["lsp_shapes<br/><i>:Requirement</i>"]
one_colour_map["one_colour_map<br/><i>:Requirement</i>"]
end
s10 --- g_released
| Requirement | Where it stands | Level | Rule |
|---|---|---|---|
host_free_core |
✅ Released | must | The core must not import obsidian or vscode. |
format_as_library |
✅ Released | must | The reader, the rules, completeness and the layout source must live in their own package, which the plugin uses, and the vault must carry only a generated, read-only copy of each release. |
lsp_shapes |
✅ Released | must | Problems, fixes and suggestions must use the shapes of the Language Server Protocol |
one_colour_map |
✅ Released | should | Theme colours should reach each host through one mapping table. |
Using it
The project
Building it
Designs