Skip to content

The Dispatch ABI ​

The Ship of Tools extension model is its defining idea: multiple dispatch is the plugin system. ConceptExplorerCore defines a small set of abstract types, and methods on those types are the ABI. A package extends Ship of Tools simply by being using-ed — the dispatch tables grow, with no registration call, no plugin manifest, and no central list to edit.

This page is the conceptual contract. For the symbol-by-symbol reference see API — ConceptExplorerCore; for step-by-step tutorials see Writing a FileType Plugin; for a complete external package see the HDF5 worked example.

The pluggable types ​

Core declares three abstract types:

TypeWhat it pluralizesA plugin adds …Status
FileTypefile kinds the explorer can preview / parsestruct PngFile <: FileType endbuilt
ConceptEntityconceptual units a file declaresa function / type / derivation entitydeclared, NOT BUILT (no implementation)
AnnotationKindcategories of concept annotationa TypeMeaning kinddeclared, NOT BUILT (no implementation)

Only FileType is wired end to end. ConceptEntity and AnnotationKind are declared design targets with no concrete subtypes. The window's navigation modes are native Rust views.

The contract ​

Each pluggable type has a small set of methods a plugin implements. Defined in core today:

julia
# FileType
matches(::Type{<:FileType}, path)        -> Bool              # claim a path
preview(::Type{<:FileType}, path)        -> PreviewPayload    # render it
parse_entities(::Type{<:FileType}, path) -> Vector{ConceptEntity}   # declared, NOT BUILT: no caller

# ConceptEntity
ast_hash(::ConceptEntity)                -> String            # declared, NOT BUILT: no method, no caller
applicable_annotations(::ConceptEntity)  -> Vector{Type{<:AnnotationKind}}   # declared, NOT BUILT: no method, no caller

matches and preview are built. parse_entities has methods (the standard plugins return an empty vector) but nothing calls it; ast_hash and applicable_annotations have no method at all. They are declared design targets. The staleness hash that is built today is not ast_hash: see The Concept Layer.

Planned mods ​

Mode, Tool and Capture have been removed from core. ADR 0051 specifies what replaces them in a 0.7.Z after the 0.7.0 tag: Mod with tree_children and the three-argument preview for views, :repl events for structured output, and MCP servers if a mod needs to offer tools to agents. The mod system is not built.

A minimal FileType plugin ​

julia
module PngPreview

using ConceptExplorerCore

struct PngFile <: FileType end

ConceptExplorerCore.matches(::Type{PngFile}, path) =
    endswith(lowercase(path), ".png")

ConceptExplorerCore.preview(::Type{PngFile}, path) =
    PreviewPayload("image/png", read(path))

end

Once the package is loaded in the kernel (see Discovery), PNGs are previewed through it: no registration step and no Rust code.

The serialization seam ​

The Rust↔Julia boundary is crossed by exactly two generic structs, both with opaque payloads so Rust never has to learn about new entity kinds:

  • TreeNode — one node of a mode's column tree: id, label, kind, has_children, badges, and a kind-defined payload dictionary. Declared in core but not built: no Julia code constructs one today; the window's trees travel as the Rust wire type of the same shape.

  • PreviewPayload — a rendered preview: mime, data bytes, and an extras dictionary. The frontend dispatches on mime to pick a renderer.

Because both carry opaque, kernel-defined payloads, adding a new FileType needs no Rust change unless its output must be bounded, in which case the daemon's preview gates also name its extensions. The frontend renders file previews by MIME. Navigation modes are native Rust views; future view extensions follow the planned mod design above.

Core is a plugin to itself ​

The standard file types are implemented as methods on FileType, the same abstract type a third-party plugin extends — they receive no privileged access. Built-in navigation modes are native Rust views. If core ever needs something the ABI cannot express, the rule is to fix the ABI, not to special-case core. This keeps the extension surface honest: third-party plugins travel exactly the path core travels.

Discovery ​

Loaded FileType subtypes are found automatically with file_types (a subtypes(FileType) scan), and the best match for a path is chosen by file_type_for. Which extension packages a project loads is declared explicitly — see Discovery & Configuration.

Next steps ​

An agentic development environment for Julia. Released under the AGPL-3.0-or-later, with a commercial license on request.