Guides

Explore: backlinks, related Blocks and the trail

What is connected to a Block: the Blocks that point at it, the Blocks related to it, and the chain of Derivations behind it. The explore Feature, the panel, the related route and derivationTrailOf.

The Explore panel answers three questions about one Block, all from the Block index, and a fourth from the host's knowledge graph when it has one:

TabQuestionSource
backlinksWhich Blocks point at this one?EditorBackend.index.edges(address, 'in') without the tag Edges (see Edges)
relatedWhich Blocks are about the same thing?EditorBackend.index.related(address), the related route below
trailHow was this Block made?derivationTrailOf(address, index), the chain of Derivations, the original first
knowledgeWhat does the knowledge graph know about it?EditorBackend.knowledge.search(title), then neighbours(id) of the node you choose; see below

A tab shows only when the backend can fill it: backlinks needs index.edges, related needs index.related, trail needs only index, knowledge needs the knowledge capability. A backend without the index capability has no Explore panel.

Enable it

The explore Feature is in no level list of the presets. A host that composes with composeEditor opts in by id: interaction: [...INTERACTION.full, 'explore'], with explore: { open, show } in the options. The Feature requires the composites Feature and the backend capability index; over a backend without it, composeEditor reports the Feature in omitted.

import { INTERACTION } from '@skaile/forge-editor/presets/compose'
import { composeEditor } from '@skaile/forge-editor/vue/advanced'

const composed = composeEditor({
  content: 'rich',
  interaction: [...INTERACTION.full, 'explore'],
  ai: false,
  backend,
  explore: {
    // What choosing a Block does: open its Document and reveal the Block.
    open: address => workspace.openBlock(address),
  },
})
EntryContent
@skaile/forge-editor/exploreframework-free: exploreFeature, exploreFeatureCore, createExploreModel, exploreTabsOf, exploreCountOf, exploreTabLabel, exploreKindLabel, exploreKnowledgeLinksOf and the types
@skaile/forge-editor/explore/vue, @skaile/forge-editor/explore/reactexploreFeature with the inspector section, plus ExplorePanel, ExploreSection and useExploreModel

The Feature adds the section Verknüpfungen to the inspector and the details card of a Typed block: the count of each tab and a button to the panel. show(address) in the options is where the host places its panel (a sidebar tab, a drawer); without it, the section shows the panel inline under the counts.

The panel

ExplorePanel takes the Block to show (address, null for none) and open, the host's way to a Block. It renders the ExploreModel of createExploreModel({ backend, address, open }); the Vue and React components render the same model.

The model keeps one state: the selected tab and, per tab, { status: 'idle' | 'loading' | 'done' | 'failed', items }. It loads the three lists when the address changes, cancels what a newer Block replaced, and never loads the same Block twice (refresh() loads again). A failing list is failed and the others stay usable. open(address) calls the host and resolves whether it happened; a throwing host is logged, never rethrown.

GET /api/editor/blocks/:documentId/:blockId/related answers the Blocks most related to one Block as BlockSearchHit[] (documentId, blockId, title, type), best first, at most ten, the Block itself never. The score of a candidate Block is:

EvidencePoints
each tag it shares with the Block2
each reference target both point at with a chip3
it holds every word of the Block's title1

A candidate with score 0 is left out, and equal scores keep the order of the Documents. relatedBlocks(row, candidates) and relatedScore in @skaile/forge-editor/core are the ranking; the route and the in-memory backend both use them.

The route reads only Documents the user may read (the scope of the Workspace search). It answers [] for an unknown Block, 403 when the user may not read the Document of the Block, 400 without a Document or Block ID, 401 without a user and 501 without the index port. An adapter with vectors can rank better behind the same route.

RouteAPI.blockRelated (port index)
ClientEditorBackend.index.related(address, signal?), optional: a backend without it leaves the related tab out

The trail

derivationTrailOf(address, source, signal?) (@skaile/forge-editor/core) follows derivedFrom of the Derivation through source.blockGet (the Document's current content, so EditorBackend.index is a TrailSource). It answers TrailStep[], the original first and the Block itself last:

const trail = await derivationTrailOf({ documentId: 'doc', blockId: 'rendition-of-rendition' }, backend.index!)
// [{ address: …'original', method: null, state: null },
//  { address: …'summary',  method: 'ai:summary', state: 'fresh' },
//  { address: …'short',    method: 'ai:rewrite', state: 'stale' }]
  • It goes at most TRAIL_MAX_HOPS (8) Derivations back and never visits a Block twice.
  • A Block without a Derivation is a trail of one step with method: null and state: null.
  • A Block made from an uploaded asset ends the trail there; its method says how it was made.
  • Each step's state is the one the row badge shows (fresh, stale, edited, missing, foreign). An original that is gone gives missing; one the user may not read gives foreign.
  • It answers [] for a Block that does not exist and rejects when the Block itself cannot be read.

The knowledge tab

The knowledge tab („Wissensgraph“) is offered only when the backend has the knowledge capability (EditorBackend.knowledge, served by the KnowledgeGraph port; see Knowledge graph). It sits after the trail.

  • List. Per Block the model reads the title through index.blockGet and searches the graph for it. state.query is that text ('' for a Block without a title, which searches nothing), state.knowledge the hits ({ id, label, kind, score }, best first).
  • Neighbours. model.focusNode(hit) loads knowledge.neighbours(hit.id) into state.focus ({ node, status, nodes, edges }); exploreKnowledgeLinksOf(state.focus) lists the nodes joined to it with the edge type and its direction. focusNode(node) on one of them moves on, focusNode(null) returns to the hits. Another Block resets the focus.
  • No Block. A knowledge node is no Block, so choosing one never calls the host's open.
Copyright © 2026