Skip to content

Plugin Development Guide

Eidos Lite plugins can provide custom editors and viewers for files, add independent pages to the sidebar navigation, or register shortcuts in the Command Palette. Plugins have access to local filesystem APIs (ctx.fs), isolated storage, network access, and host interaction interfaces.


Ensure you have Node.js 22.12 or newer and a package manager (npm, pnpm, or yarn) installed. Also download Eidos Lite to run and debug plugins locally.

Scaffold a new plugin using the official tooling:

Terminal window
npx @eidos.space/plugin-tools create my-plugin
cd my-plugin
npm install # or pnpm install

The generated project structure is as follows:

my-plugin/
├── plugin.json # Manifest declaring plugin metadata, views, and entry points
├── package.json # Project dependencies and npm scripts
├── tsconfig.json # Strict TypeScript configuration
└── src/
├── main.tsx # View mount entry point
└── style.css # Stylesheet

The scaffolding configures the official toolchain in package.json:

  • @eidos.space/plugin-sdk: Complete TypeScript specification and types for Plugin 1.0.
  • npm run check: Performs static syntax, type, and manifest verification (eidos-plugin check .).
  • npm run pack:plugin: Packages a self-contained offline distribution archive (.eidos-plugin).

You do not need a build step before debugging. Eidos Lite features an on-the-fly compiler that compiles and reloads code in real time:

  1. Launch Eidos Lite and enter any Space.
  2. In the top toolbar, click the Plugins icon (located between the Search box and Space menu).
  3. Click Load development source… and select your project’s plugin.json.
  4. Review the declared permissions and enable the plugin for the current Space.
  5. In the Space file tree, right-click a matching file and choose Open with → Your Plugin View.

Whenever you edit and save files under src/ in your code editor, Eidos Lite will automatically recompile and hot-reload the view!


File views take over the presentation and editing of any file format (text, media, custom binary files, or .eidos SQLite database packages).

Declare the view in plugin.json:

{
"apiVersion": 1,
"id": "example.file-viewer",
"name": "Custom File Viewer",
"version": "0.1.0",
"views": [
{
"id": "viewer",
"title": "Custom Viewer",
"entry": "./src/main.tsx",
"context": "file",
"access": "write"
}
],
"placements": [
{
"location": "file/open",
"view": "viewer",
"extensions": [".json", ".dat", ".mp4"]
}
]
}

Mount a React interface in src/main.tsx:

import type { ViewContext } from "@eidos.space/plugin-sdk"
import React, { useEffect, useState } from "react"
import { createRoot } from "react-dom/client"
import "./style.css"
function App({ ctx }: { ctx: ViewContext }) {
const [content, setContent] = useState<string>("")
const file = ctx.file!
useEffect(() => {
// Read current file text or binary using ctx.fs
ctx.fs.readText(file.path).then(setContent).catch(console.error)
}, [file.path])
const handleSave = async () => {
await ctx.fs.writeText(file.path, content)
await ctx.ui.notify("File saved successfully!")
}
return (
<div className="viewer-container">
<header className="header">
<h3>{file.name} ({file.size} bytes)</h3>
<button onClick={handleSave}>Save</button>
</header>
<textarea
value={content}
onChange={(e) => setContent(e.target.value)}
/>
</div>
)
}
export default function mount(ctx: ViewContext, root: HTMLElement) {
const reactRoot = createRoot(root)
reactRoot.render(<App ctx={ctx} />)
return {
dispose() {
reactRoot.unmount()
},
}
}

2. Filesystem Operations & Companion Files (ctx.fs)

Section titled “2. Filesystem Operations & Companion Files (ctx.fs)”

ctx.fs provides complete local filesystem operations to plugins. In file views, it supports reading/writing binary data, companion file discovery, and streaming media playback.

ctx.fs.readBinary(path) and ctx.fs.writeBinary(path, data) support binary payloads up to 16 MiB, allowing direct handling of images, audio/video chunks, and custom binary formats:

// Read binary data
const bytes = await ctx.fs.readBinary("assets/logo.png")
// Write binary data
const payload = new Uint8Array([0x89, 0x50, 0x4e, 0x47])
await ctx.fs.writeBinary("data/output.bin", payload)

② Companion Media Detection & Streaming Playback

Section titled “② Companion Media Detection & Streaming Playback”

For media files and subtitles, use ctx.fs.getUrl() and ctx.fs.list():

// 1. Get high-performance streaming URL with range request support (206 Partial Content)
const streamUrl = await ctx.fs.getUrl("movie.mp4")
// 2. Discover companion subtitle files in the same directory
const companions = await ctx.fs.list(undefined, { extensions: [".srt", ".vtt"] })
// 3. Read companion subtitle text
if (companions.length > 0) {
const srtText = await ctx.fs.readText(companions[0].path)
}
const watcher = await ctx.fs.watch("data", () => {
console.log("Directory changed; reloading data")
})
// Automatically unsubscribe when the view unmounts
ctx.subscriptions.add(watcher)

Execute background operations via the Command Palette (Cmd+K) or keyboard shortcuts.

Declare the action in plugin.json:

{
"extension": "./src/extension.ts",
"actions": [
{
"id": "stat-workspace",
"title": "Summarize Space Files",
"context": "workspace"
}
],
"placements": [
{ "location": "command-palette", "action": "stat-workspace" },
{ "location": "keybinding", "action": "stat-workspace", "key": "Mod+Alt+S" }
]
}

Implement the action in src/extension.ts:

import type { ExtensionContext } from "@eidos.space/plugin-sdk"
export default function activate(ctx: ExtensionContext) {
ctx.actions.register("stat-workspace", async ({ fs, ui }) => {
const files = await fs.list()
await ui.notify(`The root directory contains ${files.length} files.`)
})
}

4. Independent Feature Pages (context: "page")

Section titled “4. Independent Feature Pages (context: "page")”

Build dedicated dashboards or tool panels anchored in the Space navigation sidebar.

Declare the page in plugin.json:

{
"workspace": { "files": true },
"views": [
{
"id": "dashboard",
"title": "Journal Dashboard",
"context": "page",
"entry": "./src/dashboard.tsx"
}
],
"placements": [
{ "location": "navigation", "view": "dashboard" }
]
}

Once mounted, the page appears in the Space sidebar navigation. When workspace: { "files": true } is declared, the page can use ctx.fs to index or create files across the entire Space (e.g. automatically creating daily journal entries).


5. Verification and Packaging for Distribution

Section titled “5. Verification and Packaging for Distribution”

Run static type and manifest checks from the project root:

Terminal window
npm run check

Bundle the plugin into an offline .eidos-plugin archive:

Terminal window
npm run pack:plugin

The resulting file is located at dist/<plugin-id>-<version>.eidos-plugin. Users can double-click it or drag and drop it directly into the Eidos Lite Plugin Manager to install.