Plugins Are Semantic Contracts
Most plugin systems start with loading code.
That is useful, but it is not the interesting part.
The interesting part is the boundary.
A plugin wants to enter a host. The host has state, UI surfaces, permissions, policies, data shapes, effects, users, runtime quirks, and failure modes. If the plugin boundary is just a package import or a JavaScript bundle, the host has to trust too much too early.
The better shape is a semantic contract.
A plugin should say what it provides, what it requires, where it mounts, what it can read, what it can write, which effects it may run, which runtime it needs, and what evidence would prove that it fits.
- Host exposes
- mounts, state views, actions, effects, gatesThe host publishes the surfaces a plugin can safely depend on.
- Plugin provides
- views, commands, workers, rules, projectionsThe plugin contributes capabilities, not just files.
- Plugin requires
- capabilities, data shape, policy, runtimeRequirements are visible before the host admits the plugin.
- Admission proof
- type, policy, preview, runtime, rollbackInstallation becomes a decision with evidence, not a blind load.
Loading Code Is Not Enough
A traditional plugin system often has a shape like this:
host app -> plugin API -> plugin bundleThat shape answers one question:
can the host call the plugin?But the harder questions are different:
what does the plugin believe the host contains?
which state can it read?
which state can it mutate?
which effects can it run?
which UI surface can it occupy?
which runtime does it assume?
which version of the contract was it built against?
what proof says it still works?
what happens when the host changes?Those are semantic questions.
If they are hidden inside code, every plugin install becomes a trust exercise. If they are represented as a contract, the host can route the plugin: admit it, sandbox it, adapt it, ask a human, or block it.
The Host Exposes A World
A host application should not expose itself as a bag of callbacks.
It should expose a world.
That world contains typed mount points, readable state views, callable actions, effect capabilities, event streams, policy rules, and gates.
For example:
host Dashboard @id("host_dashboard") {
mount sidebar @surface("navigation.sidebar")
mount panel @surface("dashboard.panel")
state CurrentUser @readonly
state WorkspaceSummary @readonly
capability host.fetch {
effect network.fetch
policy same_origin
}
action openPanel {
input PanelRoute
writes ui.route
}
gate previewProbe {
checks layout, focus, accessibility
}
}This is not a widget API.
It is the host saying: these are the places an extension can appear, these are the resources it can ask for, and these are the proofs required before it becomes real.
The Plugin Declares Its Shape
The plugin should be equally explicit.
plugin WeatherWidget @id("plugin_weather") {
mounts host.dashboard.panel
provides view WeatherPanel {
reads WorkspaceSummary.location
uses host.fetch
emits openPanel
}
requires capability host.fetch
requires gate previewProbe
fallback view WeatherUnavailable
}The important thing is not the exact syntax.
The important thing is that the plugin can be reasoned about before the host executes it.
It has a mount. It has a provided view. It has declared reads. It has a capability requirement. It has a gate. It has a fallback.
That gives the host a review object.
Projection Is The ABI
An ABI is usually thought of as a low-level calling convention.
For this kind of system, the useful ABI is semantic.
The host and plugin do not need to share one implementation language. They need to share stable meaning: mounts, capabilities, state shapes, actions, effects, identities, and proof obligations.
1plugin WeatherWidget @id("plugin_weather") {2 mounts host.dashboard.panel3 4 provides view WeatherPanel {5 reads WorkspaceSummary.location6 uses host.fetch7 emits openPanel8 }9 10 requires gate previewProbe11 fallback view WeatherUnavailable12}This is where Frontier-style representation matters.
The plugin can be written once as a contract, projected into a host-specific implementation, and still carry the proof that says what survived.
Admission Is The Install Step
Installing a plugin should not mean copying code into the host.
It should mean admitting a capability through a boundary.
The useful result is not just safer extension.
It is more malleable software.
Plugins stop being vendor-specific bundles. They become bounded capabilities that can move between hosts when the semantic boundary matches.
The Host Can Route The Plugin
A semantic contract gives the host choices.
The host does not need to say only yes or no.
That routing is the difference between a plugin ecosystem and a controlled extension surface.
Plugins Become Composable Capabilities
Once plugins are semantic contracts, composition gets more interesting.
A plugin can provide a view to one host, a command to another host, and a worker to a third host. A host can expose only the mounts and capabilities it is willing to admit. A translator can lower the same plugin contract into React, SwiftUI, HTML, a CLI command, or an agent tool manifest.
The plugin boundary becomes less like:
download this package and hope it behavesAnd more like:
this capability can mount here
this state view is readable
this effect is allowed
this target projection is proved
this fallback exists
this install can be rolled backThat is a much stronger foundation for user extension, internal tools, agent-built software, and cross-language projection.
The larger idea is that a plugin is not an escape hatch from the system.
It is a request to join the system.
And if software is represented semantically, that request can be inspected, translated, tested, routed, and admitted without pretending that loading code is the same thing as trusting it.