Skip to content

Commands

eidos <command> --help prints the same with examples. Every root-bound command takes --root <path>; without it the root is found by its .eidos/ marker from the working directory. Commands that read take --json for stable, snake_case output.

Exit codes: 0 done, 1 the check found errors (or an index is stale under --check), 2 the command could not run.

Create a root, or pull pieces of a framework into one that exists. The plan is always shown before anything is written.

Terminal window
eidos install # asks each answer in a terminal
eidos install @BuildableWorks/software --group identity --product "Care Connect" --yes
eidos install @BuildableWorks/book docs/book --naming "Title Case" --yes
eidos install @BuildableWorks/research --collection investigations --yes # into the root you are in
eidos install acme/[email protected] --path docs/blueprints --role reviewer --yes
eidos install ../other-root --all --plan # print the plan, touch nothing
eidos install ../acme/Blueprints --setup-only --yes # another root's setup, none of what is written in it
eidos install --blank Blueprints --yes # a root from nothing: the Eidos core alone, no collections

A source is one of:

  • A Registry package, @owner/name or @owner/name@<version>, fetched with git. Buildable’s three starting frameworks (@BuildableWorks/software, book, and research) are packages like any other: the CLI carries no copy of them. The Registry →
  • A GitHub owner/repo@<tag> or git URL, with --path <folder> naming the root inside it.
  • A repository on this machine, <path>@<tag>, with --path.
  • A folder, read as it is. Whatever the source, one person’s local.yaml and local/ under .eidos/plugins/ are never copied.

With no source, in a terminal, the walkthrough lists the Registry’s packages, each with its description; the Browser’s Registry page lists the same and includes from them into the root you are in.

Option Meaning
--collection <name> Pull one collection: its entry, variants, templates, grouping, scoped properties, and folder. Repeatable
--variant <collection.variant> Pull one variant and its template into a collection the root has. Repeatable
--role <name> Pull one role file. Repeatable
--top-level <title> Pull one top-level document and its file. Repeatable
--all Take everything the root lacks
--plan / --dry-run Print the plan and stop
--yes Confirm without asking
--on-conflict current|incoming Resolve every conflict the same way. A conflict is a name both sides define differently
--force Treat every skip (a name both sides define the same) as a conflict
--offline Folders, repositories on this machine, and what is already cached only; fetch nothing, send nothing. A Registry package needs the Registry, so it is refused
--naming <convention> New root: kebab-case (default), TitleCase, or "Title Case"
--group <name> New root: a starting group under the grouped collection. Repeatable
--product <name> New root: fills the README’s placeholder
--no-framing New root: leave out the framing collection
--strict / --no-strict New root: whether a warning fails eidos check, kept with the root
--no-agents New root: write no AGENTS.md pointer
--setup-only New root from a root in use: copy its setup (the Framework, templates, roles, and each plugin’s shared settings, less the product name and the install record, and of its users only its agents and the person copying, each with their role), none of its blueprints, tasks, drafts, decisions, comments, canvases, assets, saved views, versions, or top-level documents, and none of anyone’s local files. Its naming convention is kept unless --naming says otherwise
--blank New root from nothing: the Eidos core alone, a Framework with no collections, templates, or roles, shaped afterwards with eidos configure:collection add, the framework editor, or the AI Agent. It takes no source, so its one argument is the root; nothing is read from the Registry, fetched, or sent, so it works offline. Never a default: eidos install with no source still asks for one
--json The source, the plan, every write, skip, and conflict, and the check

On a root that exists, every name is converted into the root’s naming convention, the framework document is edited with its comments kept, then the index is rewritten and eidos check runs. A second run with the same arguments writes nothing.

Scaffold one blueprint: frontmatter from the properties that apply to the collection, body from the variant’s template with its guidance, filename in the naming convention, a permanent id.

Terminal window
eidos new specs "Session Management" --group identity --summary "Keeps a signed-in user signed in."
eidos new specs Passkeys --variant micro --set status=Intake --set tags=auth,security
eidos new frames Market --dry-run
Option Meaning
--variant <name> One of the collection’s variants; default is the group’s default, else the collection’s. With neither, new refuses and names the variants
--group <name> The sub-folder
--id <id> The permanent id, one token in any form; default is a new B- and four characters, such as B-1AC3, unique in the root
--summary <line> The one-line summary, so the index lists it at once
--set key=value A property value at creation; repeatable; lists are comma-separated
--dry-run Print the file instead of writing it

Required properties are generated blank; an optional one is written only when --set or --summary gives it a value. It refuses a taken id or an existing file.

A blueprint started before it belongs to a collection: the file new would write, kept with the CLI until it is published, in no index, listing, or check.

Terminal window
eidos draft new specs "Session Management" --group identity # .eidos/plugins/eidosmd/drafts/, shared with the root
eidos draft new specs "A rough idea" --local # local/drafts/, local, never committed
eidos drafts # every draft, with the collection each is meant for
eidos drafts --search passkeys # the drafts holding every word
eidos draft move a-rough-idea shared
eidos draft set a-rough-idea --for frames --group ""
eidos draft publish session-management # into its collection under new's rules, then the index
eidos draft discard a-rough-idea

publish needs the id free, converts the name to the root’s convention, and notes a group the collection does not declare. The browser offers the same from the New blueprint form and the reader’s head.

Validate the whole root, or the named blueprints, against the root’s own framework.

Terminal window
eidos check
eidos check specs/identity/login.md
eidos check --strict # this run: warnings fail too
eidos check --json
eidos check --format github # a GitHub annotation per finding
eidos check --format codequality # a GitLab Code Quality report on stdout

Errors are wrong on any reading: frontmatter that does not parse, a missing id or title, a duplicate id, a variant the collection does not declare, a link to a file that does not exist, a template the framework names but lacks, a region with no closer.

Warnings are gaps to surface, never refuse: a required property missing or empty, a value off a property’s options, a property no block declares, a work-tracking field, a section the template declares but the body lacks, an unknown section (only when the root asks, below), sections out of order (a heading the template does not declare is skipped), a grouping value that does not match its folder, a frame nobody has written, a stale index, a version gap, and anything at the root the framework document does not declare (or declares and is not there).

Whether a warning fails the check is the root’s setting (eidos setup --strict on|off, kept in git so CI and every machine agree). --strict and --no-strict override one run.

The section rules are the root’s too, each a switch in the same file. A heading the variant’s template does not declare (section-unknown) is not reported unless the root turns it on (eidos setup --warn-unknown-sections on): a template is the starting point and the guide to a complete blueprint, not a fence, so extra headings are the owner’s to add. A required section the body lacks (section-missing; every declared section, where the template marks none required) and declared headings out of order (section-order) are reported unless turned off (--warn-missing-sections off, --warn-section-order off). A section the template offers but does not require (section-optional-missing) and a property the framework does not declare for the collection (property-unknown, property-scope) are reported only when turned on (--warn-missing-optional-sections on, --warn-unknown-properties on): a property of your own is yours, and the page offers to promote it to the framework instead.

Run eidos check on every merge request, so an id two branches drew apart (id-duplicate, alias-taken) fails before the merge rather than after it; eidos ids fix-duplicates redraws it on the branch. Under the sequential scheme, the check also notes each draft id still on the default branch (id-draft) until eidos ids finalize gives it its number.

The job that runs eidos check on every merge request, printed or written into the repository.

Terminal window
eidos ci # print the job for both hosts
eidos ci --write github # .github/workflows/eidos-check.yml
eidos ci --write gitlab # an eidos-check job in .gitlab-ci.yml, the rest of the file kept

The job installs this CLI’s version with npx and runs eidos check --format github or --format codequality at the root, named from the top of the Git repository, where the file is written. An error fails it; a warning shows against its file and fails it only when the root is strict. A second run refreshes the job rather than adding another; in .gitlab-ci.yml it sits between # eidos:ci:start and # eidos:ci:end.

--format keeps the check’s exit code. github prints a workflow command per finding (::error file=…,line=…::<code>: <message>); codequality prints a Code Quality report (an error major, a warning minor) on stdout and the findings on stderr. Paths are relative to the Git top level.

Checking in CI →

Rebuild the index key inside Framework.yaml, one list per collection, touching nothing else in the document.

Terminal window
eidos index
eidos index --check # write nothing; exit 1 if stale

A blueprint without a summary is listed with a null summary and named on stderr. It is never invented.

Terminal window
eidos framework # version, naming, folders, properties, vocabulary
eidos framework --as yaml # the document, normalized, with guidance as comments
eidos list specs --group identity --where status=Draft
eidos list --search B-5KFM # by its id; every word of a search, in any case
eidos show login # by id, filename, or path
eidos show login --json # properties and sections parsed out

--where key=value matches a property case-insensitively; a list property matches any item. --search <words> keeps the blueprints holding every word, in any case and any order, in the id, the title, the summary, or a property’s value, what the page’s search box over a table finds; it never reads the body. Find a blueprint this way rather than by searching the files.

One blueprint’s frontmatter from the shell, so nobody opens a file to flip a value.

Terminal window
eidos property get @login
eidos property set @login status Done
eidos property set @login tags auth,security
eidos property unset @login depends_on

The blueprint is @<id>, a path, or a filename. A value is coerced to the property’s declared type. A property the table does not declare for the collection, a tool’s own, or a value off the options is refused unless --force. --dry-run prints the frontmatter as it would be.

New generated ids for blueprints, the one way an id changes.

Terminal window
eidos reid @login # one blueprint, or several
eidos reid --all # every blueprint whose id is not already B- and letters or digits

Each blueprint gets an id drawn under the root’s id scheme (B-1AC3 by default, B-F36 under adaptive), unique in the root, and every reference a plugin keeps to the old one follows: a comment thread’s target, a canvas node, a task’s blueprints, an asset’s links. The files keep their names, and links between blueprints are paths, so they are untouched. The plan is printed first, as for configure:, with --dry-run, --yes, and --json. A plugin that is off and keeps files is named in the plan, since it cannot follow.

What the root’s id scheme does to ids already given.

Terminal window
eidos ids finalize --dry-run # sequential: the numbers each draft id would get
eidos ids finalize # on the default branch only
eidos ids fix-duplicates --dry-run # an id a merge left held twice, and what it would become
eidos ids fix-duplicates

finalize gives every task’s and decision’s draft id its kind’s next number, the oldest first, the draft kept as an alias and every reference following. It refuses off the default branch (ids.default_branch, else the CI’s default branch, else origin’s HEAD, else main or master), so a number is written once, where every branch meets, and never changes after. Run it as a CI job after a merge and commit what it writes:

.gitlab-ci.yml
finalize-ids:
image: node:22
rules:
- if: $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH
script:
- npx eidosmd ids finalize --root Blueprints
- git diff --quiet || (git commit -am "Finalize ids [skip ci]" && git push "https://ci:${PUSH_TOKEN}@${CI_SERVER_HOST}/${CI_PROJECT_PATH}.git" HEAD:$CI_COMMIT_BRANCH)

A random draw cannot see an id made on another branch that is not merged yet, so two branches can draw the same one; the clash shows when they meet. Run eidos check on every merge request so it fails there:

.gitlab-ci.yml
check-blueprints:
image: node:22
rules:
- if: $CI_PIPELINE_SOURCE == "merge_request_event"
script:
- npx eidosmd check --root Blueprints
.github/workflows/blueprints.yml
on: pull_request
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npx eidosmd check --root Blueprints

fix-duplicates mends one on the branch, after merging the default branch in: the item whose file the default branch has with the id keeps it, and the other is drawn a fresh id under the root’s scheme, keeping no alias (the old id is the other item’s). A file the default branch also has that names the id is left naming the item that keeps it; every other reference in the root follows the redrawn item. Where neither item is on the default branch, the one made first keeps the id.

A blueprint moved as mv moves a file: to another group of its collection, to a new title, or both. eidos mv is the same command.

Terminal window
eidos move @login billing # to a group its collection declares
eidos move @login --title "Sign in" # renamed where it is
eidos mv @login billing --title "Sign in" # both at once

The file goes into the group’s folder with its name and its id kept, the grouping’s property is set to the group where the collection declares one, and every link in the root that pointed at the old path follows. The plan is printed first, as for configure:, with --dry-run, --yes, and --json. A new title is set with the body’s heading where it read the old title (a heading in other words is left as written), and the file is renamed to the name the title takes in the root’s naming convention, so property set is for the title alone and move --title for the title with its file. Move blueprint to… in a reader’s ⋮ runs the same plan.

The framework, edited from the shell. Every change prints a plan (each entry, key, file, and link it touches, and every value that will be gone) and asks.

A command that writes needs a framework editor: it refuses, and says why, unless the user it acts for (EIDOS_USER, else the user you act as, else your git identity matched to a listed user) has editor access. A root that marks no person an editor leaves everyone one, a plugin’s user included; otherwise a plugin’s user, the AI Agent’s @agent, changes the framework only while its plugin lets it. show and --dry-run always run, and a plugin’s configure: commands (eidos backlog configure:property) follow the same rule. eidos users →

Noun Operations
property add, show, rename, set, remap, remove
collection add, show, rename, set, remove
folder add, show, rename, set, remove
group add, rename, set, remove
variant add, rename, set, set-default, clear-default, remove
term add, set, remove
doc add, rename, set, remove
role add, show, rename, remove
Terminal window
eidos configure:property add team --type Text --applies-to all --required --meaning "Owning team."
eidos configure:property add tier --type Text --options Core,Extended --meaning "How central the unit is."
eidos configure:property rename status maturity --dry-run
eidos configure:property remap maturity Draft=Nascent Done=Mature --yes
eidos configure:collection rename specs units --unit unit
eidos configure:folder add assets --description "Images the blueprints link to."
eidos configure:folder add exports --owned-by @acme/exports --description "What the exporter writes."
eidos configure:group rename specs cli cli-core
eidos configure:group set specs sketches --default-variant micro
eidos configure:variant add specs api --from micro
eidos configure:variant clear-default specs
eidos configure:doc rename "Design Principles" Principles
eidos configure:role rename developer engineer
Switch Meaning
--dry-run Print the plan and stop
--yes Proceed without asking
--force Proceed where values or files will be gone, or through a conflict the plan names
--preserve On a remove: leave the files or keys on disk for check to report as undeclared

A rename reaches everywhere the name appears: every blueprint’s frontmatter, every link in the root, me.md, the users, and this CLI’s settings. A move is a git mv where git is on. Narrowing a property’s options names every blueprint with a value off the new list and needs --force. After any change the index is rewritten and check runs. Without a terminal and without a switch, a command exits 2 naming the switch, so an agent learns it from the error.

Move a root to the standard this CLI carries, mechanically.

Terminal window
eidos migrate --dry-run
eidos migrate

It renames what moved between versions, rewrites the standard’s properties.core block, sets eidos_version, and reports what only the owner can decide (a folder or file at the root nothing declares). A root already current is left alone. Versioning →

The CLI’s own settings for a root, none of them the standard’s: the product the root defines, which plugins are on, whether a warning fails check, the people who work in the root, and who this machine acts as.

Terminal window
eidos setup # a menu of the plugins, then the questions, in a terminal
eidos setup --product "Care Connect" # what the Home and the desktop app call the root; "" goes back to the repository's name
eidos setup --enable backlog --disable terminal --strict on --add-user "Ada Lovelace" --alias ada --role developer --email [email protected] --as ada
eidos setup --warn-unknown-sections on --warn-section-order off # which section rules warn
eidos setup --id-scheme adaptive # how new blueprints, tasks, and decisions draw their ids
eidos setup --id-scheme sequential --id-padding 3 # T-001; --default-branch names the branch finalize runs on

Writes .eidos/plugins/eidosmd/settings.yaml (shared with the root) and local.yaml (yours, gitignored).

The id scheme is how every new blueprint, task, and decision draws its id, one choice for the root (ids.scheme in settings.yaml, also on the browser’s Framework Settings → Root):

  • adaptive, the one to choose: a run of letters then a run of digits, three characters to start (T-F36), a character longer once 80% of a length is in use (FT36, FT362, FT3621), counted across the whole kind. Letters are Crockford’s 22 (no I, L, O, U), so an id read aloud has one spelling.
  • random: four characters of Crockford’s base32 (T-1AC3). A root without the setting draws these, so its ids never change shape until it chooses; a root made with eidos install and set up there starts on adaptive.
  • sequential: a new item gets an adaptive draft id on any branch, and eidos ids finalize, run on the default branch, gives each task and decision its next number (T-412, or T-001 with --id-padding 3), keeping the draft as an alias so it still resolves. A blueprint keeps the id it was drawn, since a blueprint keeps no former id.

Ids already given stay as they are when the scheme changes. A draw that lands on an id or alias already held is drawn again.

Terminal window
eidos plugin # every plugin: title, version, on or off, where its switch is written
eidos plugin enable backlog # plugins.backlog: true in settings.yaml; a plugin that keeps a root folder declares it
eidos plugin disable terminal --me # local, in local.yaml
eidos plugin set agent agent codex # one declared setting, to the file its scope names (a me setting in local.yaml); --unset for the default
eidos instructions backlog # a plugin's own guide, while it is on

Off, a plugin registers nothing; its folder, settings, and regions stay for the day it comes back. Plugins →

Each plugin that is on mounts its command under a Plugins heading in eidos --help; eidos <plugin> --help prints it with examples.

Terminal window
eidos canvas new "Product Map" # .eidos/plugins/canvas/product-map.yaml (--local for local/); list, show <id> [--page], move <id> shared|local, schema
eidos comments @login # the threads on a blueprint; add <target> <text> [--section] [--item] [--reply] [--as], close, reopen, delete, project
eidos backlog --status "In Progress" # the tasks; add <title> --for @login [--type], show, set, check <task> <n>, link <task> <type> <other>, unlink, promote, types, sections, export, draft:*
eidos decisions --unconfirmed # the inbox; add <decision> --for @login [--type] [--task] --as <alias>, show, set, confirm, types, statuses, project, remove
eidos assets --for login # the files; show, add <file>, link <path> --to @login, set --title|--name, remove
eidos linter --fix # the markdown files that drifted from the root's rules, settled

A target for Comments is a blueprint (@<id>, a path, a filename), a doc, or <host>:<id> (backlog:<task>, canvas:<page>, decisions:<id>). Plugins →, one page per plugin

Terminal window
eidos version # the root's versions, newest first
eidos version record 1.0.0 # a row naming HEAD
eidos version record 1.0.0 --commit a1b2c3d --tag # names that commit and tags it blueprints/1.0.0
eidos version set 1.0.0 --name 1.0.1 # renames it; its tag becomes blueprints/1.0.1
eidos version set 1.0.0 --commit a1b2c3d # points it at another commit; its tag moves with it
eidos version remove 1.0.0 --tag # takes it out and deletes its tag here (never pushed)

A version is a fixed point: a name for a commit, so a team can later read the root exactly as it was (the scope a client signed off, what a release was built against). Git already holds every file; the row gives the commit a name. It is this CLI’s record, in .eidos/plugins/eidosmd/versions.yaml, written only when asked. The tag prefix is versions.tag_prefix in settings.yaml, blueprints/ by default.

set and remove print their plan, then ask in a terminal; --dry-run prints it and stops, --yes proceeds, and without a terminal and without --yes the command exits 2. set --tag tags a version on its commit (or moves its tag back onto it) and set --no-tag deletes its tag; remove without --tag keeps the tag and says so. A tag is made, moved, or deleted in this repository alone: nothing is pushed, so a tag already on a remote stays there until you push the change yourself (git push <remote> --delete <tag>). record --tag takes a tag already on that very commit as the version’s own, and refuses one on another commit.

eidos version lists each version with its commit’s date and its tag, then says where the record and the repository’s tags disagree: a tag a version names that git does not hold or holds on another commit, and a tag under the prefix that no version names, each with the commands that settle it. eidos check reports the same as git/version-tag-missing, git/version-tag-moved, and git/version-tag-stray, except on a shallow clone.

Terminal window
eidos views # every saved view: its id, its name, the address that opens it, shared or local
eidos views --json # { views[{ id, name, page, query, scope }] }
eidos views move V-7K2M local # move a view to your local.yaml, or back with shared; its id, filters, and sort kept

The views saved in the browser from a filtered board or table (Save as view): the shared ones first, from .eidos/plugins/eidosmd/views.yaml, committed with the root, then yours, from views in local.yaml, never committed. A view is made, renamed, and deleted in the browser, and moved between shared and local there or with eidos views move; the command lists them, so an agent can hand a person the address of one under eidos browser. The Backlog’s My work, By status, and By type are the views every root starts with and are kept in neither file. Saved views →

Terminal window
eidos browser
eidos browser --port 7000 --no-open

The root in a local web page on 127.0.0.1. The browser →

Terminal window
eidos roles
eidos whoami --role developer --experience "new to this product" --capacity fluent
eidos whoami --clear
eidos whoami --global --name "Ada Lovelace" --email [email protected] --note "Short answers; ask before writing."

whoami writes the local, gitignored .eidos/me.md. --global sets who you are on every root (your name, email, technical capacity, and a note on how you like to be helped), kept in preferences.yaml outside every root and copied into each root’s me.md as whoami, the browser page, or the desktop app opens it; without values it prints them. A field you change in one root’s me.md stays that root’s, and whoami says which fields came from the global one. Roles →

Terminal window
eidos users # every user: name, @alias, role, email, and whether one is an agent
eidos users add "AI Agent" --alias agent --agent # add one on the fly; only the name is needed
eidos users set ada --access editor # a framework editor; none takes it back
eidos users set ada --access owner # a framework owner, and so an editor (--editor and --owner still work)
eidos comments add @login "…" --as agent # a comment signed by that user, not by you

The people and agents who work in the root, the same list as the Users settings page (users in .eidos/plugins/eidosmd/settings.yaml). add takes a name and nothing else by default: the alias comes from the name, a role is optional, and a user already there is reported rather than added twice. An agent adds itself once with --agent, then signs every comment as itself with --as <alias> (or EIDOS_USER), never as the person it works for. Comments →

set gives a person framework access, none, editor, or owner, as the Users page’s Access select does (--editor, --no-editor, --owner, and --no-owner set one toggle at a time). An editor may change the framework and every plugin’s shared settings; with nobody marked an editor, everyone is one. An owner holds the intent, the scope, and the final call, is always an editor, and is the only one who grants or removes owner (while the root has no owner, an editor names the first). Anyone may make themselves an editor; a user who is not one changes nobody else’s access. Neither is a role: a user’s role is still the contract an agent responds by. A plugin’s user is listed as the plugin’s and set by its plugin, never here.

Terminal window
eidos feedback --kind bug --message "The board drops a card dragged twice"
pbpaste | eidos feedback --kind feature # the description from stdin

Sends a Bug Report, Feature Request, or Other (--kind bug|feature|other) to the maintainer: the description, the eidosmd version, and the OS, to eidosmd.com, which mails it and keeps nothing. Nothing from your root is sent. There is no reply channel, so put your email in the description if you want an answer. It is sent only when you run it, so EIDOS_NO_TELEMETRY does not hold it back. A send that fails, or finds feedback closed for now, prints your description back and exits 2. In the browser and the desktop app it is Send Feedback in the command palette, and under Help in the desktop app’s menu, a form that shows what goes with the description before you send it.

Terminal window
eidos instructions # list the guides
eidos instructions overview # required first read for an agent
eidos agents --write # a pointer in AGENTS.md (or --file CLAUDE.md)
eidos standard # the text of EIDOS.md this CLI carries; --version for the number

Agents →