eidos is the agent-first Rust interface to the open Eidos File format. It
reads and modifies .eidos files directly, prints readable terminal output by
default, and does not require a running Eidos application.
- Create and inspect Eidos Files.
- Read logical tables, fields, relations, views, and file metadata.
- Query rows through the Eidos query model rather than raw SQL.
- Apply atomic row, saved View, and schema mutations with optimistic revision checks.
- Upsert rows by stored business keys and apply mixed row batches atomically.
- Import, attach, detach, and verify File-field attachments without hand-building metadata.
- Create and update standard Views from user-facing Table and Field names.
- Create, rename, and delete Tables and Fields, and create forward Relations from user-facing intent.
- Preview and manage Formula and Lookup Fields through the canonical Runtime.
- Query Formula and Lookup values, including filters and sorts, through Runtime evaluation.
- Validate file identity, structure, content, and supported semantics.
- Serve a local web editor for one file over HTTP on macOS, Linux, and Windows.
- Publish immutable Eidos File or Markdown Versions, including attachments, to a stable read-only URL.
- Upgrade its own installation from a verified standalone release.
- Initialize the bundled Agent Skill for a Space/project or the current user.
The CLI does not manage Space lifecycle, ordinary documents, application RPC,
version history, or Sync. Use ordinary file tools for standalone text,
eidos attachment for Eidos File attachments, and Graft for history or Sync.
macOS and Linux:
curl -fsSL https://download.eidos.space/cli/install.sh | shWindows PowerShell:
irm https://download.eidos.space/cli/install.ps1 | iexThe installers resolve the stable version from LATEST, download
the exact cli-v<version> GitHub Release asset, and verify it against the
release SHA256SUMS before replacing an existing binary. Unix installs to
~/.local/bin by default; Windows also adds that directory to the user PATH.
The short URLs are served by the apps/download Worker.
Pin a version or installation directory with environment variables:
EIDOS_VERSION=0.37.1 EIDOS_INSTALL_DIR=/usr/local/bin sh install.shStandalone assets currently cover macOS arm64/x64, Linux x64, and Windows x64.
Upgrade an existing standalone installation to the latest stable version:
eidos upgradeThe command uses the same release pointer, platform archive, and
SHA256SUMS contract as the installers. It verifies the downloaded binary's
reported version before replacing the currently running executable. A current
version is a no-op; use --version <semver> to select an exact release and
--force only when intentionally reinstalling or downgrading. The containing
directory must be writable by the current user. On Windows, the verified
replacement is finalized by a one-time helper immediately after the running
CLI process exits.
The CLI is the typed transaction boundary. It also bundles the matching Eidos
Skill, so initialization does not require Node.js, npm, or npx:
# Install in the current Space/project.
eidos skills init
# Install for the current user and all projects.
eidos skills init --globalUse eidos skills init --space <DIR> to initialize another Space. The command
writes the standard .agents/skills/eidos layout. It is safe to repeat; if a
file has local edits, pass --force explicitly to update it from the bundled
CLI Skill. Start a new Agent task after initialization, then try:
Use the Eidos skill to inspect ./tracker.eidos.
Show context first and do not mutate yet.
cargo build
target/debug/eidos create tracker.eidos \
--table Tasks \
--label-field Title \
--fields '[{"name":"Title","type":"text"},{"name":"Status","type":"select"}]'
target/debug/eidos tracker.eidos context Tasks \
--fields Title,Status \
--limit 50Pass the global --json flag when a script or Agent needs the stable machine
contract:
target/debug/eidos --json context tracker.eidos Tasks \
--fields Title,Status \
--limit 50For ordinary row updates, apply combines exact matching, revision checking,
returning rows, and validation before commit:
target/debug/eidos tracker.eidos apply - <<'JSON'
{
"revision": "1",
"table": "Tasks",
"match": {"_id": "019..."},
"expect": 1,
"set": {"Status": "doing"},
"returning": ["Title", "Status"]
}
JSONFor synchronization without pre-known Row IDs, use a stored business key:
target/debug/eidos --json rows upsert tracker.eidos \
--table Tasks \
--key "External ID" \
--values '[{"External ID":"task-1","Title":"Ship CLI"}]' \
--expected-revision 1 \
--dry-runUse rows mutate for a mixed create/update/delete batch that must commit as
one revision. Both commands support JSON from inline input, @path, or stdin.
Lower-level mutation commands remain available for creation, deletion, and automation that already owns stable row IDs. They require the current revision:
target/debug/eidos tracker.eidos rows add Tasks \
--expected-revision 1 \
--values '{"Title":"Ship CLI","Status":"doing"}'
target/debug/eidos tracker.eidos validate --level fullUse the attachment intent commands for File Fields. They own file staging, portable collision names, metadata, revision checks, and rollback:
target/debug/eidos --json attachment import tracker.eidos \
--table Tasks --row 019... --field Files \
--source /absolute/path/report.pdf \
--expected-revision 2
target/debug/eidos --json attachment verify tracker.eidosattachment attach references a verified file that is already below the
.eidos file's directory. attachment detach removes exact File-entry IDs
but deliberately retains physical files.
Create standard Views directly from user-facing names. The command resolves
stable IDs, applies type-specific defaults, and can show the exact plan with
--dry-run:
target/debug/eidos --json view create tracker.eidos \
--table Tasks \
--name "By status" \
--type kanban \
--group-by Status \
--dry-run
target/debug/eidos --json view create tracker.eidos \
--table Tasks \
--name "Delivery calendar" \
--type calendar \
--date-by DueUse view list, view inspect, view update, and view delete for the
remaining lifecycle operations. view-apply remains available when an Agent
needs to submit an exact Runtime mutation document.
Schema intent commands cover the common Agent path and resolve names to stable IDs before applying one revision-checked transaction:
target/debug/eidos --json field add tracker.eidos \
--table Tasks --name Due --type date --dry-run
target/debug/eidos --json table create tracker.eidos \
--name People --label-field Name \
--fields '[{"name":"Name","type":"text"}]'
target/debug/eidos --json relation add tracker.eidos \
--table Tasks --name Owners --target-table People --on-delete detach
target/debug/eidos --json table update tracker.eidos Tasks \
--record-label Title --content-field Notes --position 1 --dry-run
target/debug/eidos --json field update tracker.eidos Estimate \
--table Tasks --type integer --dry-run
target/debug/eidos --json relation update tracker.eidos Owners \
--table Tasks --cardinality one --dry-runtable update covers settings, record label, Markdown content Field,
position, name, and default-Table changes. field update covers settings,
position, name, record-label selection, stored-type conversion, and atomic
Select/Multi-select option renames. relation update changes forward Relation
definitions. Conversion uses recommended policies by default and requires
--confirm-lossy when Runtime preflight reports explicit-lossy; File Fields
must use attachment commands instead. Field nullability is intentionally not
exposed.
Use table rename/delete and field rename/delete for simple lifecycle
changes. schema-apply remains available for atomic batches and supported
schema payloads that need lower-level control. Formula and Lookup Fields use
the embedded TypeScript Runtime for preflight, dependency checks, cycle
detection, and commit:
target/debug/eidos --json formula preview tracker.eidos \
--table Tasks --name Total \
--formula '"Estimate" * 2' --type integer
target/debug/eidos --json formula add tracker.eidos \
--table Tasks --name Total \
--formula '"Estimate" * 2' --type integer --expected-revision 3 --dry-run
target/debug/eidos --json lookup add tracker.eidos \
--table Tasks --name OwnerScore \
--relation-field Owners --target-field Score \
--aggregate sum --expected-revision 4query and context automatically evaluate Formula, Lookup, and inverse
Relation Fields when present. Inverse Relation creation remains outside the
high-level CLI intent surface. Deleting Formula or Lookup Fields is explicitly
lossy and requires --confirm-lossy after a dry run. A table create field
array may include Formula fields; Relation and Lookup fields are added after
their referenced schema exists.
For advanced automation, the equivalent low-level Calendar mutation uses the
stable Table and date Field IDs returned by schema:
target/debug/eidos tracker.eidos view-apply - <<'JSON'
{
"expectedRevision": "2",
"changes": [{
"kind": "create-view",
"clientKey": "calendar",
"tableId": "019...",
"name": "Calendar",
"type": "calendar",
"query": {},
"layout": {"dateField": "019..."},
"position": "1"
}]
}
JSONThe same command supports update-view and delete-view; explicit position
patches reorder Views. View queries and Calendar layout references use stable
Field IDs so renames do not change their meaning.
Both eidos tracker.eidos inspect and eidos inspect tracker.eidos are
supported. Commands print readable key-value sections and tables by default.
With --json, successful commands write one JSON document to stdout and
failures write one JSON error document to stderr. Failures return a nonzero
exit code in either mode.
eidos serve hosts a dedicated Eidos File web editor over HTTP with the UI
embedded in the binary. The editor lives in
packages/eidos-file-serve on top of
@eidos.space/eidos-file-ui, and the TypeScript runtime runs inside an
embedded QuickJS engine on a rusqlite bridge, so every committed mutation
writes straight to the file — there is no separate save step.
target/debug/eidos serve tracker.eidos --port 8420 --openRelative File entries and uploads remain disabled until an existing assets folder is explicitly mounted. With a mount, the embedded UI can preview, open, download, choose, drop, paste, and upload files in File fields:
target/debug/eidos serve tracker.eidos --assets-dir ./assets --openThe mount resolves only assets/<name> references and never falls back to a
guessed sibling or working-directory path.
The server binds 127.0.0.1 by default. Use --lan to bind one detected
private interface and print a paired access link for other devices on that
trusted network:
target/debug/eidos serve tracker.eidos --lan
target/debug/eidos serve tracker.eidos --lan --host 192.168.1.20LAN API access requires the printed link to establish a browser session, and Host/Origin checks remain restricted to the exact bound address. Multiple paired browsers can edit through the same serialized Runtime writer and receive committed revisions live. LAN mode uses HTTP, so do not use it on an untrusted network.
When private-network access is unavailable, sign in with an eidos.space account and publish the same loopback server through Eidos Relay:
target/debug/eidos login
target/debug/eidos whoami
target/debug/eidos serve tracker.eidos --relay --openRelay assigns the account a stable opaque r-….eidos.ink hostname and uses an
outbound WebSocket, so the CLI does not bind a public interface. eidos login
stores a renewable session in an owner-only user configuration file; later
Relay commands silently reuse or refresh it without an operating-system
credential prompt. eidos logout removes that local credential.
By default, opening the Relay URL asks the browser to sign in with the same eidos.space account that claimed the hostname. Relay verifies account ownership and creates a host-only browser session; the URL contains no access key. OAuth tokens never enter the browser URL or the local Serve process.
Create an explicit guest link only when you want to share the running file with a browser that does not have the owner's account:
target/debug/eidos serve tracker.eidos --relay --share--share prints a fragment-key link that pairs the guest browser with this
Serve process. Starting another Relay serve for the same account takes over
the hostname and invalidates earlier browser sessions. Local and LAN modes
remain account-free.
--ui-dir <dir> serves a different static UI build instead of the embedded
one. The embedded editor is available in the published macOS, Linux, and
Windows builds.
Run eidos --help and the repository Skill at ../../skills/eidos/SKILL.md for the complete command and safe-agent workflow.
Sign in to the
Publish account page, create a
Publish CLI key, and store it as EIDOS_PUBLISH_TOKEN. The CLI uses
https://publish.eidos.space by default; set EIDOS_PUBLISH_ORIGIN only when
targeting another environment.
The key is shown only once and grants write access only to the Publish control
plane. Keep it in the current shell or a secret manager; never commit it.
Confirm the installed build has eidos publish --help before following the
workflow.
Publish a public resource with a tenant-local slug:
eidos publish tracker.eidos --slug trackerMarkdown uses the same command. Relative links and images are discovered from the document directory and uploaded as immutable attachments:
eidos publish docs/guide.md --slug guideMarkdown must be UTF-8 and no larger than 16 MiB. It is rendered once as a
script-free static page; raw HTML is not executed. Standard Publish accepts an
.eidos entrypoint up to 256 MiB; Custom accounts can receive a higher
account-specific limit. Source attachments remain limited to 1 GiB, and equal
SHA-256 content is stored once per account.
Publish a local Form View, then collect completed responses into its original Table with the Publication ID from the publish result:
eidos publish feedback.eidos --slug feedback --form-view "Public feedback"
eidos collect feedback.eidos \
--publication 7300a083-df92-49d8-945d-1e0bae0eac18The Collector imports each Row and its retry receipt atomically. Submitted attachments are verified and deduplicated in a local content-addressed asset directory. Republish after changing the Form View or target schema; collection fails closed when the local schema no longer matches the published revision.
The CLI displays hashing, upload, preparation, and activation progress. The slug becomes the URL path, contains 1–64 lowercase letters, digits, or hyphens, and identifies one long-lived resource. Publishing new bytes to the same slug creates an immutable Version while preserving the URL and current access policy. The complete canonical Source Bundle fingerprint includes attachment digests; an identical active fingerprint reuses the current Version instead of creating redundant history. A different slug creates another resource. Resource and Version counts are not quotas; deduplicated account storage and inactive history age are.
Publish can protect a resource with a password. The CLI prompts twice without echo and never places the password in the URL or command arguments:
eidos publish tracker.eidos --slug tracker --passwordFor non-interactive automation, set EIDOS_PUBLISH_PASSWORD and still pass
--password. Remove password protection explicitly with --remove-password.
Republishing without either option preserves the resource's existing access
policy. Password sessions last up to 12 hours, and rotating or removing the
password invalidates existing sessions immediately.
Owner-only account access remains available through:
eidos publish tracker.eidos --slug tracker --visibility privateUse the global --json flag for one stable result document in automation;
interactive progress is intentionally omitted in JSON mode. The result includes
publishFingerprint and versionCreated for deterministic change detection. The complete
plan limits, access behavior, setup, and troubleshooting guide is
in Publish a file.
- The CLI owns physical SQLite mapping; callers use logical table and field names or stable IDs.
- Every mutation is atomic.
--expected-revisionprevents writes based on stale reads.contextcombines compact schema discovery with a bounded logical query.applyvalidates the proposed final state before committing matched updates.rows upsertresolves stored business keys and plans create/update actions in one transaction.rows mutateapplies mixed RowChange batches atomically, with--dry-runrollback support.attachment import/attach/detachperforms revision-checked File-field changes;attachment verifychecks external local assets.schema-apply --dry-runexecutes and rolls back the exact schema transaction.- Runtime-backed lossy Formula/Lookup deletes require
--confirm-lossyon the real commit. view create/update/delete --dry-runresolves intent and rolls back the exact View transaction.view-applyuses the Runtime View mutation document and one revision-checked transaction.validate --level fullshould follow a completed write workflow.- Raw SQLite writes are unsupported.
The CLI supports stored scalar/list fields, forward Relations, saved View lifecycle operations, and Runtime-backed Formula/Lookup evaluation. Formula and Lookup fields are read-only in row mutations. The CLI preserves existing inverse Relation metadata but does not create inverse Relations through the high-level intent surface.
cargo fmt --all --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --releaseThe embedded artifacts are generated but committed, so a clean checkout builds with cargo alone. Refresh them after changing the runtime or the serve UI:
# QuickJS runtime bundle (packages/eidos-file) -> qjs-host/bundle/
pnpm --filter @eidos.space/eidos-file build:quickjs
# Serve UI (packages/eidos-file-serve) -> qjs-host/ui/
pnpm --filter @eidos.space/eidos-file-serve buildThe CLI owns the version in Cargo.toml; Eidos Lite version bumps do not
change it. To prepare a CLI release:
- Update
apps/cli/Cargo.tomlto the exact semantic version. - Run
cargo check --workspaceinapps/cliand commit the resultingCargo.lockchange. - For a stable release, update
apps/cli/LATESTto the same version. - Rewrite
apps/cli/RELEASE_NOTES.mdfor that exact CLI version. Keep it scoped to standalone CLI behavior; do not use monorepo-generated notes. - Run the formatter, Clippy, tests, and installer test.
- Tag the validated commit as
cli-v<version>and push the branch and tag.
The tag triggers
build-and-release-cli.yml,
which rebuilds and verifies four platform archives, generates SHA256SUMS,
and creates a dedicated GitHub Release from the checked-in CLI release notes
without changing the repository's Eidos Lite “Latest Release” pointer.
The workspace contains:
apps/cli/
├── core/ # Eidos File format, query, mutation, and validation library
├── qjs-host/ # Embedded QuickJS host bridging the TypeScript runtime to rusqlite
├── src/ # CLI output, commands, and agent-facing normalization
└── tests/ # End-to-end external-agent contract tests
AGPL-3.0