Skip to content

Plugins

Beyond scaffolding, checking, and indexing, everything the CLI does is a plugin: a named tool behind one contract, with its own folder under .eidos/plugins/<name>/, switched on per project. Twelve ship with Eidos.

Eidos is not another markdown editor. It facilitates one thing: the definition of a product, the project’s blueprints, which are the source of truth for what the product is. Everything else the tooling does serves that truth and is subordinate to it. A canvas draws it; a comment discusses it; a task serves it; a version names a commit of it. None of them becomes a second definition beside it.

Two rules follow:

  • Every plugin lives in its own workspace, .eidos/plugins/<name>/, or in a project folder declared as its own. Switching one off leaves the definition exactly as it was.
  • Every plugin is built for this lifecycle, not for general use. Anyone who wants a whiteboard or a task board for its own sake opens another tool.
Plugin Facilitates On by default Keeps it in
Canvas Drawing the definition: pages of sketches and blueprints, styled by the framework’s properties no (on in a project made before it turned off, which keeps it) .eidos/plugins/canvas/<id>.yaml
Git Reading its history: a blueprint’s commits and a diff viewer, Source control (what changed under the project, a commit of it), the identity that signs a comment, the recorded versions, git mv and git rm behind every rename and delete where the project is a repository the viewer command in its local.yaml
Comments Discussing it: threads on a blueprint, a doc, a canvas page, or a task, anchored to a heading or an item and projected into the file as readable text yes .eidos/plugins/comments/threads/<id>.yaml, a comments:threads region while the file has threads
Backlog The work that serves it: tasks with statuses, columns, types, milestones, and drafts, on a board and in a table, never inside a blueprint no a backlog/ folder the plugin owns, settings in its folder
Records The pieces it is made of: record types such as acceptance criteria or characters, labelled in the blueprints or kept one file each, checked, linked to, and listed in a table per type, with an optional lifecycle and sign-off no the blueprints themselves, a folder per file-based type, settings in its folder
Assets The files that are not markdown: images, PDFs, anything, listed, linked to blueprints and tasks, embedded or linked from the editor yes, in a project made from 0.17.0 on the project’s assets/ folder, an index in its folder
Linter Keeping the markdown in one form: rules the project sets, applied on every save and reported by the check yes .eidos/plugins/linter/settings.yaml
Metrics Keeping it readable: reading time against a budget, the filler, repeated sentences, and copied paragraphs to trim, and counts the project chooses, each a warning yes in a project made from 0.14.0 to 0.16, no from 0.17.0 on .eidos/plugins/metrics/settings.yaml
Authorship Who stands behind it: who wrote each section, a person or an agent, and which of an agent’s sections a person has reviewed no .eidos/plugins/authorship/snapshot.yaml
Terminal Your own shell in the Panel, started in the project no nothing on disk
AI Agent A conversation with the coding agent you already run (Claude Code, Codex, or any command speaking ACP), what the page has open carried as context yes .eidos/plugins/agent/conversations/, local ones under local/
Automations Workflows you build: when something happens (a blueprint or task added, a status changing, a commit), steps that do something, ask you, or check the result, run anywhere or in the app yes .eidos/plugins/automations/automations.yaml when shared, your own and the runs under local/

Each has a page of its own in this section: what it adds to the app, what it keeps on disk, its commands, and what the check reports for it. Using the app → · Plugin commands →

A plugin is on or off per project: plugins.<name>: true | false in the CLI’s settings.yaml, shared with the project, with the same line in the local local.yaml overriding it. A new project writes every switch as it is made, each at the default in the table; a project made earlier names no switch for one it never set and keeps the default it was made under, so Canvas stays on there. eidos plugin lists them, eidos plugin enable|disable <name> writes the switch, eidos plugin set <name> <setting> <value> writes one of its settings to the file its scope names, eidos setup offers them as a menu, and the app’s Plugins page has one switch and one settings form per plugin. Off, a plugin registers nothing: no command, route, finding, view, or region; its folder and files stay where they are for the day it comes back. The AI Agent’s switch is yours rather than the project’s: on or off for you in every project, kept in your preferences.yaml, so no project turns it off for anyone.

eidos instructions <plugin> prints a plugin’s guide while it is on, and a plugin that has something to say to an agent says it in AGENTS.md under the Eidos nudge.

The standard gives a tool one name and four places to use it:

  • Its folder, .eidos/plugins/<name>/, committed with the framework: settings.yaml for what the project decides, local.yaml and local/ for what is local, on one machine and never committed (the project’s .eidos/.gitignore carries both). The CLI’s own folder is eidosmd/: the plugin switches, strictness, users, the tag prefix, the versions, and the shared drafts travel with the project; the theme, the editor, the workbench’s layout, and the local drafts stay on the machine.
  • Its project folders, declared under folders with owned_by: "@<name>/<kind>" (Backlog’s backlog/, Assets’ assets/). What such a folder holds and what is checked inside are the tool’s to say; the standard reads none of it. The project →
  • Its properties, properties.tools.<name> in Framework.yaml, and a key named for itself on any property row (canvas styles a node by a property’s value). Properties →
  • Its regions, <!-- <name>:<region> --> to <!-- /<name>:<region> --> inside a markdown file: a span the tool owns and rewrites wholesale (Comments’ threads at the foot of a blueprint, an image Assets embedded). Regions →

The standard reads none of it, eidos check never faults it, and eidos migrate carries it across untouched.

A plugin may run users of its own, as the AI Agent runs @agent. It registers each through the host, host.user({ name, alias, role, agent, access, accessHint }), and the user is listed as the plugin’s by eidos users and on the Users page while the plugin is on: its name, alias, and role are the plugin’s and read-only there, it has no email and no access select, and it cannot be removed. Whether it may change the framework is the plugin’s answer, editor or none, asked each time it matters, so it follows a setting of the plugin’s; a project that marks no person an editor leaves everyone one, plugin users included. Nothing is written until the plugin keeps the user, the first time it signs something: then it goes into settings.yaml marked plugin: <name>, so what it signed stays readable once the plugin is off.

A plugin someone else wrote is listed on the Registry and installed once per machine, into the folder Eidos keeps what belongs to no project (~/Library/Application Support/eidosmd on a Mac, %APPDATA%\eidosmd on Windows, ~/.config/eidosmd on Linux), under plugins/<name>/<version>/. The CLI and the Eidos MD app share it.

Terminal window
eidos plugin install @acme/hello # the newest version, each file checked against the sha256 the Registry lists
eidos plugin install @acme/[email protected] # one version; in a project, also names it there
eidos plugin install # every plugin the project names that this machine lacks
eidos plugin enable hello # the project's switch: it wants the plugin
eidos plugin allow hello # this machine's trust, in your local.yaml

A project that uses one names it with the version it takes, community_plugins.hello: "@acme/[email protected]" in settings.yaml, so a teammate who clones the project sees the command that installs it. Installing switches nothing on and allows nothing. A plugin from outside runs, in the CLI and in the app, only when all three hold: the project switches it on, this machine allows it, and its min_host is no newer than this CLI. Until then eidos plugin lists it with the reason, and none of its code runs. Restricted mode, on the Community plugins page, keeps every plugin from outside from running on any project of yours until you turn it off.

A configuration is a Registry listing of a project’s plugin settings: eidos install @owner/name into a project you have takes its plugins’ settings and offers to install any plugin from outside it needs, and eidos install <source> --plugin <name> pulls one plugin’s shared settings from any source. Every plugin and configuration is reviewed by a person before the Registry lists it.

To publish one, eidos plugin verify <folder> runs the checks the Registry’s CI runs on a plugin’s release files and prints their hashes, and eidos publish --plugin <folder> writes the listing for a new version. A listed version is never changed.

A plugin is developed against the app you already use, from its build folder, without publishing it. Its source builds with npm on Node 22.6 or later, which the eidos binary does not need for itself. Linking a folder, starting a plugin, and installing from GitHub are also under Develop on the Community plugins page, shown once Enable developer settings is on.

Terminal window
eidos plugin new team-notes # a plugin's source from the template, its dist/ linked in this project
cd team-notes && npm install
npm run dev # builds dist/ and builds it again on every change
  • Link a build folder. eidos plugin link <folder> loads the plugin from the folder its build writes manifest.yaml, cli.js, and optionally app.js, page.js, and instructions.md to, in place of any installed version, on this machine until eidos plugin unlink <name>. In the project it is linked from, it is named, switched on for you, and allowed, so it runs at once. Nothing is copied.
  • Reload as it builds. The app loads a linked plugin again whenever its build rewrites the folder: its commands, its routes, and its views come from the new code without a restart. Reload on its row does the same on demand.
  • Start from the template. eidos plugin new <name> [--folder <dir>] [--title <title>] writes a plugin’s source with a command, a route, a sidebar view, its guide, a build with a watch mode, and a test, and links its dist/.
  • Try it in a sandbox. eidos plugin dev <folder> serves the app on a project and an app data folder of its own, the plugin linked, switched on, and allowed there, so none of your projects, settings, or sign-ins is touched. The sandbox is removed when the server stops; --keep <dir> keeps it.
  • Install from a release. eidos plugin install github:<owner>/<repo>[@<tag>] installs a plugin straight from a GitHub release, the latest when no tag is named, for someone trying it before it is listed. Nothing checks an unlisted plugin’s files, so it is marked Unlisted with its repository, and like any install it runs only once you switch it on and allow it.

eidosmd/plugin-testing runs a plugin’s own suite in a sandbox: a project and an app data folder of the test’s own, with the build folder linked, switched on, and allowed.

import { pluginSandbox } from 'eidosmd/plugin-testing';
const sandbox = await pluginSandbox('dist');
const run = await sandbox.run(['team-notes', 'greet', 'Ada']); // { status, stdout, stderr }
const answer = await sandbox.route('GET', 'greet', { query: { who: 'Ada' } }); // as the page calls it
await sandbox.close();

run runs eidos in the sandbox’s project; route calls the plugin’s app routes as the page does, with no server and no network. While a sandbox is open, the process’s app data folder is the sandbox’s, and close gives it back.