Reference

Derive method contract

DeriveMethod, DeriveContext, the derive registry, the Derivation record and the derivation index functions.

The types come from packages/editor/src/core/derive.ts and core/derivation.ts and are exported from @skaile/forge-editor/core. For how to write a derive method, see Derive methods and the Derivation index.

DeriveMethod

One way to make a new block or text from a block. A Feature contributes methods in EditorFeature.deriveMethods; defineEditor merges them in feature order into preset.deriveMethods (DeriveRegistry).

FieldTypeMeaning
idstringUnique across the preset. Also the id of the block action generated from the method.
label(ctx: FeatureContext) => stringMenu label, in the language of the surface (ctx.t).
iconstringIconify name.
abilityAbility?Shown only on blocks that have this ability (BlockAction.ability).
ordernumber?Position among the block actions (BlockAction.order).
placementBlockAction['placement']?Where the action shows.
requiresreadonly string[]Capability ids the original must all have. Every id must be declared by a Feature (or built in) when the preset is defined.
available(ctx: DeriveContext) => boolean?Backend flags and per-block conditions (ctx.ctx.backend.ai, a readable source). Absent: always available where requires holds.
run(ctx: DeriveContext) => voidDoes the work and writes the result, and for a Derived block its Derivation.
menu(ctx: DeriveContext) => MenuItem[]For a method with sub-choices (derive into one of several Block types).

Exactly one of run and menu is set; defineEditor throws for neither or both, for a duplicate id and for a requires entry no Feature declares.

DeriveContext

FieldMeaning
editorthe editor
nodethe original block
posthe position right before node
ctxthe FeatureContext of the surface (backend, public AI flags, settings, notices, translations)

Registry and functions

ExportDoes
DeriveRegistrymethods (feature order) and get(id)
createDeriveRegistry(methods)builds a registry
deriveMethodsAt(editor, ctx, pos)the methods that can run on the block at pos: the block has every capability the method requires, and available holds. Empty without a block there or without a preset.
deriveActionsOf(preset, ctx)one BlockAction per method, in the shape the block UI renders; requires, ability and available gate it. blockActionsOf includes them.

Derivation

The record in meta.derivation of a Derived block. The original keeps nothing.

FieldTypeMeaning
from{ asset: string } | { block: string, document?: string }The original: an uploaded asset by asset name, or a block by block ID. document is the Document the block lives in; absent = this Document.
methodDerivationMethodHow it was made: 'transcription', 'pdf-text', 'ocr', 'description', 'bibliography', ai:<typeId> for a block derived by the model, or any string.
modelstring?The model that made it.
createdAtstringISO timestamp.
inputHashstringSHA-256 hex of the asset bytes or of the source block's Markdown; '' when unknown.
outputHashstringSHA-256 hex of the produced body's Markdown; '' when unknown.
outputstring?Asset name of the stored raw output (text/markdown).
inputsRecord<string, { from: DerivationSource, hash: string }>?The named inputs of an N-to-1 Derivation (mixdown, a summary of several Blocks). from and inputHash then name the primary input, and inputHash is derivationFingerprint.
activity{ id: string, agent?: string, at?: string }?The run that produced the Block (an AI request, a job); agent is a model or tool id.

DERIVATION_KEY is the meta key ('derivation'). derivationOf(node) reads a Derivation (null without one). derivedChildrenOf(parent) lists the direct children of parent that are Derived blocks, with their child index. isForeignSource(derivation, documentId) tells whether it points at a block of another Document.

Derivation index

derivationIndexOf(doc) builds the reverse index once per document version (memoised per doc node):

Member of DerivationIndexMeaning
derivedevery Derived block with its position, in document order
blockById(id){ node, pos } of the block with block ID id (any depth), or null
assetBlocks(name)the AssetBlock[] ({ node, pos, holder }) that hold the stored asset name, in document order; holder is the position and size of the block around the asset block
derivedFromBlock(id)the Derived blocks whose Derivation points at block id, in this or any Document (isForeignSource tells them apart)
derivedFromAsset(name)the Derived blocks whose Derivation points at the stored asset name

Functions on top of it:

FunctionReturns
derivedOf(doc, originalPos, documentId?)the DerivedEntry[] ({ node, pos, derivation }) made from the original at originalPos, in document order. They point at its block ID or at an asset the original holds as a direct child (its Source media). A Derived block moved out of the original still counts; Derivations from another Document are not listed.
derivationOriginOf(doc, derivedPos, documentId?)DerivationOrigin: { status: 'found', node, pos }, { status: 'missing' } (the original was deleted) or { status: 'foreign' } (another Document, not looked up); null when the node is no Derived block
derivationState(doc, derivedPos, bodyHash, documentId?, foreignHash?, inputHashOf?)DerivationState: source (the origin status), stale (an original changed since: an asset's stored hash against inputHash, a Block of another Document through foreignHash, each named input through inputHashOf(from); null for a block original in this Document, when unknown, and for inputs without inputHashOf) and edited (bodyHash() differs from outputHash; null when outputHash is unknown); null when the node is no Derived block
derivedStateOf(state)DerivedStateId ('fresh' | 'stale' | 'edited' | 'missing' | 'foreign'): the first that applies of missing, stale, edited, foreign (original in another Document, nothing known of it), else fresh
derivationFingerprint({ method, inputs })SHA-256 hex of the method and the hash of every input by input name; independent of the order of the keys in inputs
Copyright © 2026