Skip to main content

The Plugin-First Rule

The most important Morph rule is simple:

Feature work belongs in packages, not in compiler core files.

That rule exists because packages govern the compile pipeline: they register sema, lowering, backend routes, and tooling through MorphABI. Core grows only when a new kind of hook is needed, not when a new feature is needed—see Plugin-governed pipeline.


What This Means

When you want to add behavior such as:

  • a ternary expression
  • a new operator
  • a new type
  • a runtime family
  • a build or platform target

your first question is not "which core file should I patch?"

Your first question is:

Which package should own this?


Decision Tree

Use this order:

  1. Can an existing package own the feature?
  2. If not, should a new package own it?
  3. If packages cannot express it today, which framework or SDK capability must be widened?

Only the third case justifies core framework work.


Good Decisions

GoalCorrect Direction
Add a new shared operatorextend Ops or another owning package
Add a tensor-specific featureextend Tensor
Add a new test assertionextend Test
Add a new execution commandextend Vcon or another tooling-owning package
Add a new platform targetextend Build plus a platform package

Bad Decisions

These are the mistakes Morph is designed to stop:

  • adding feature semantics directly to src/parser/...
  • adding domain runtime behavior directly to runtime/src/...
  • hardcoding a new command in core CLI dispatch
  • adding platform-specific build branches directly in core build files

Core is for framework capability, not feature ownership.


Ternary As An Example

Suppose you want condition ? when_true : when_false.

The wrong instinct is:

  • edit core parser code
  • patch core semantic logic
  • add a one-off lowering branch

The right instinct is:

  • identify the package that should own expression syntax of that kind
  • add or extend package features for syntax, sema, and lowering
  • widen framework syntax hooks only if packages cannot express the form today

The Real Role Of Core

Core does not know \u2014 and must never know \u2014 any of the following:

  • What keywords or tokens exist (is, method, gpu, +, .. \u2014 all declared in package [tokens])
  • What a variable declaration looks like (declared in blocks/*/block.toml [forms.*], not in src/parser/)
  • What any type is (Int, Float, Tensor, String \u2014 owned by Types and concrete packages)
  • How any construct is lowered, optimized, or emitted (owned by package feature+route components)
  • Which runtime symbols exist (declared in [runtime.family.*] in package morph.toml files)

Core is a generic, domain-agnostic orchestration host. Its job is to:

  • run pipeline stages (lex, parse, sema, NIR, MIR, backend dispatch)
  • load and compose registered package plugins via the MorphABI
  • enforce ABI contracts between pipeline stages
  • provide stable hook shapes so packages can plug in without touching src/

Core's ignorance is its superpower. Because Core knows nothing, any language feature, any type, any target, any execution model can be added by extending packages \u2014 without rebuilding Core's understanding of the world.

Core is allowed to change only when package authors need a new kind of hook that the framework cannot currently express:

  • a new parser hook shape
  • a new manifest descriptor kind
  • a new runtime host interface
  • a new build or execution host API

That is framework work. It is rare. It is not the same as adding a feature.

A Core file that mentions a token name, a type name, or a specific AST construct by concept is a leak. Treat it as a bug.


Next Steps