@openeditor/workspace
v0.0.43
Published
Provider-neutral virtual workspaces for agents that edit OpenEditor projects. The package does not run a model, own a chat interface, or persist application data. It projects a trusted project snapshot into ordinary JSON files, then validates the complete
Readme
@openeditor/workspace
Provider-neutral virtual workspaces for agents that edit OpenEditor projects. The package does not run a model, own a chat interface, or persist application data. It projects a trusted project snapshot into ordinary JSON files, then validates the complete filesystem result and returns one atomic changeset.
Workspace format
OPENEDITOR.md protected agent instructions
site.json editable project metadata and page graph
pages/<stable-page-id>.json editable canonical OpenEditor documents
.openeditor/workspace.json protected format, policy, revision, and limits
.openeditor/pages.json protected page baseline fingerprints
.openeditor/schema.json protected host-provided schema contextThe host-side WorkspaceBaseline is the trust root. It is deeply frozen and is
never written into the workspace. Files under .openeditor/ help the agent
understand the projection, but imports trust the host baseline instead of those
files and reject any protected-file change.
Export, run, import
import {
InMemoryWorkspaceFileStore,
importProjectWorkspace,
materializeProjectWorkspace,
} from "@openeditor/workspace";
const store = new InMemoryWorkspaceFileStore();
const baseline = await materializeProjectWorkspace(project, store, {
documentValidation: { contract },
});
// A sandbox adapter now exposes `store` as real files to its agent.
const result = await importProjectWorkspace(baseline, store, {
documentValidation: { contract },
validateCrossDocumentReferences(nextProject) {
return validateConsumerReferences(nextProject);
},
});
if (!result.ok) {
console.error(result.diagnostics);
} else {
// This adapter must compare and commit in one real storage transaction.
await applyProjectChangeset(transactionalProjectStore, result.changeset);
}Sandbox-backed stores should implement readSnapshot() so imports observe one
filesystem state. They should implement replaceFiles() when materialization
must be atomic. The generic fallback detects file-list races but cannot prove
that a same-path write did not race a read.
Stable IDs
Every non-text node must have a unique stable openeditor-id before export.
Workspace creation is a strict trust boundary and never repairs source data.
New pages use IDs matching page_[a-z0-9]{20,32}; existing page IDs must use
the broader workspace-safe convention.
Commit boundary
ProjectChangeset is a proposal, not a database mutation. Consumers must apply
it transactionally and reject it if the current project revision or any
expected page fingerprint differs. fingerprintProjectPage,
fingerprintProjectSnapshot, and fingerprintSiteManifest are exported so a
consumer can reproduce the same preconditions against current application
state.
The function-free validation contract manifest is fingerprinted into the host
baseline. Import fails if the consumer omits or changes the contract used at
export. Custom validator functions are represented by their presence, so a
consumer must bump schemaVersion whenever validator behavior changes.
Portable contracts encode explicit child types and root constraints, but they
do not attempt to execute every ProseMirror content-expression feature. A host
whose configured Tiptap schema is authoritative should also provide
validateDocument using validateOpenEditorTiptapDocument (or its configured
engine wrapper). Custom blocks intended inside built-in containers must be
included explicitly in the composed portable container rules.
PolicyEnforcedWorkspaceFileStore is the least-privilege facade intended for
agent tools. It allows protected files to be read but limits writes to
site.json and pages/*.json, validates paths, and enforces file budgets.
