Eidos

Build with Eidos File 1.0

Eidos 1.0 has four interoperable layers:

File Format → Runtime → Adapter → UI

Most applications should compose the published Runtime and UI packages rather than reimplement every layer. Implement a layer only when you are building a conforming alternative.

The frozen English specifications are normative:

Choose your layer

If you are building…Start with
A Node service or headless data tool@eidos.space/eidos-file and a Node ConnectionPort
A browser applicationRuntime in a Dedicated Worker, a browser Adapter, and @eidos.space/eidos-file-ui
A visual React viewer or editor@eidos.space/eidos-file-ui on top of a conforming Host and Runtime
A storage or UI implementationThe corresponding 1.0 specification and interoperability tests
An Agent workflow or scriptThe eidos CLI and Eidos Skill

Install the reference packages

pnpm add @eidos.space/eidos-file@1.0.0 \
  @eidos.space/eidos-file-ui@1.0.0 react react-dom

Import @eidos.space/eidos-file-ui/styles.css once.

Building for an Agent or automation rather than embedding the packages? Follow the CLI and Skill setup instead.

Runtime and Adapter

The following code is a composition outline, not a standalone quickstart. Your Adapter or host supplies connection, environment, and cancellation.

Give Runtime.open or Runtime.create an EA-Connection-1.0 ConnectionPort. The reference Browser binding is SQLiteWasmConnectionPort; Desktop uses BetterSqlite3ConnectionPort.

import { Runtime, type ConnectionPort } from "@eidos.space/eidos-file"

const { service, hostBridge } = await Runtime.open(
  connection satisfies ConnectionPort,
  environment,
  "readwrite",
  { cancellation, deadlineMilliseconds: 30_000 }
)

Only service becomes RuntimeClient. hostBridge stays inside trusted Adapter/product composition. In browsers, keep Connection and Runtime in a Dedicated Worker and expose the service through AdapterTransportRuntimeClient; do not send SQLite or raw handles to Window.

Your product implements HostServices for opaque source/destination tokens, permission, save/CAS, conflict, recovery and assets. Host receives the trusted bridge; UI does not.

React viewer

import { useEffect, useMemo, type ReactNode } from "react"
import type { HostServices } from "@eidos.space/eidos-file"
import {
  EidosFileUIProvider,
  type AssetPresenter,
} from "@eidos.space/eidos-file-ui"
import { EidosUIKernel } from "@eidos.space/eidos-file-ui/kernel"
import {
  EidosStandardView,
  EidosUIRuntimeProvider,
} from "@eidos.space/eidos-file-ui/runtime-platform"

function Viewer({
  host,
  sourceToken,
  assetPresenter,
}: {
  host: HostServices
  sourceToken: string
  assetPresenter: AssetPresenter<ReactNode>
}) {
  const kernel = useMemo(() => new EidosUIKernel(host), [host])
  useEffect(() => {
    void kernel.openSource({ sourceToken, access: "read" })
    return () => {
      void kernel.close()
    }
  }, [kernel, sourceToken])
  return (
    <EidosFileUIProvider locale="en">
      <EidosUIRuntimeProvider kernel={kernel} assetPresenter={assetPresenter}>
        <EidosStandardView />
      </EidosUIRuntimeProvider>
    </EidosFileUIProvider>
  )
}

The kernel negotiates Host and Runtime, then loads a snapshot and its revision-bound schema before rendering. Grid, Gallery and Kanban consume columnar Runtime results. They never reproduce File filtering, Formula, Lookup, Relation, aggregate or grouping semantics.

EidosFileUIProvider supports locale="en" and locale="zh", plus host messages or translate overrides. Locale changes UI copy, accessibility labels, input affordances, and formatting only. Canonical option names and user-authored Table, Field, and View names remain File data and are never translated.

EidosStandardView is the reference read-only viewer composition. Full editors use the shared EidosFileEditorShell and editor components so Browser and Desktop keep one interaction hierarchy. See the @eidos.space/eidos-file-ui package guide for the editor composition surface.

File-entry URIs are never presentation URLs. Relative, https:, and canonical inline image Data URLs all go through HostServices.resolveAsset; only an injected AssetPresenter consumes the returned lease token. Hosts without a session-scoped relative root omit that capability. Open/download is an explicit leased action, and ordinary URL fields never auto-fetch.

Required interoperability checks

  • run the same Runtime contract over Browser WASM and Desktop better-sqlite3;
  • verify tagged values, nested transactions, snapshots, cancellation and error mapping at the Connection boundary;
  • verify prepared-commit receipts before COMMIT on transported mutations;
  • verify snapshot/schema/page cursor binding and revision invalidation in UI;
  • treat disabled optional capabilities as absent optional methods, not stubs.
  • verify invalid Base64/media/size, the 1 MiB inline boundary, missing relative root, lease expiry/fallback, and zero direct URI fetch/navigation.