Skip to content
j3w1 edited this page Sep 9, 2026 · 2 revisions

Taking the theme into an editor, terminal, native toolkit or any application with its own theme format. For port authors and for anyone deciding whether a target is supported.

Current state: no native ports are published. The capability explorer publishes an empty catalogue, and an empty catalogue means exactly that — no application support, not "support is implied". The owner's historical gedit scheme, IntelliJ scheme, tmux colours and browser-extension colours are catalogued in references/catalogue.json as evidence of where the palette came from. They are not supported downloads.

Contents: What a port is · Must reproduce · Fallbacks · Mapping vocabulary · Statuses · Anatomy · Starting one · Terminals

What a port is, and is not

A port themes only what the host documents as customisable. Editor colouring, application chrome, terminal colours and plugin surfaces are separate scopes: a file that changes one does not get to claim the others.

A port never patches binaries, injects unsupported hacks, overwrites a user's whole settings file, or touches keybindings, credentials or unrelated preferences. It installs under a unique name beside the host's defaults, and it documents how to roll back.

What every port must reproduce

  1. The surface ladder: canvas, default, raised, overlay, input.
  2. The text ladder: default, bright, prose, muted, subtle, disabled.
  3. Focus as a ring distinct from selection as a fill, with the ring recoloured on fills.
  4. Selection, inactive selection and hover as three distinguishable fills.
  5. The status hues with their glyphs, where the host renders glyphs.
  6. Zero radii and 1px borders where the host allows geometry; otherwise a recorded deviation.
  7. The monospace family by name, honouring the user's size.

Every required role must end up in exactly one of four buckets: mapped, explicitly inherited from the host, marked unsupported with an explanation, or intentionally out of scope. Nothing is left unaccounted for — and a coverage percentage means nothing without its denominator.

Fallbacks by host capability

Answers for the cases that come up first, from spec/portability.md:

The host… Do this
has no dashed outlines (many native toolkits) solid 1px ring in focus.ring; record the deviation
has no separate inactive selection use the selection fill everywhere; record it
has no read-only styling hook treat as default text with a dotted bottom edge if borders are available, otherwise as default
has no pattern fills for charts keep the glyph or label channel; never colour alone
is a sixteen-colour terminal heritage-ansi for fidelity, or the extended slots once approved; document bold-as-bright and whether 256/24-bit colours bypass the slots
has fixed radii document it; do not fight the toolkit
forbids removing its own focus indicator keep the host's indicator; never draw two

Mapping vocabulary

The explorer and exports/port-capabilities.json distinguish five states, and they are not interchangeable:

Label Means
Mapped The role has a named destination in the target
Inherited The target keeps its own value or behaviour, deliberately
Unsupported The target cannot provide this within the recorded scope
Out of scope Deliberately left outside this port
Not implemented Not built

A legacy unmapped role keeps its stated reason rather than being assigned a guessed classification. mapping.json must list every role in the declared profile exactly once, across mappings and unmapped.

Statuses and the verified bar

Status Means
experimental Artifacts exist and checks pass; real-target verification is incomplete
verified Imported into the recorded target, with matching evidence and a current token digest
deprecated Kept, with a reason

verified is expensive on purpose. A parse success is a structural pass, not verification. A list of mappings is not verification. An experimental label is not verification. To mark a record verified, all of this must hold at once: the evidence subject digest still matches, the manifest declares verified, the target and tested versions include the recorded version, the recorded platform is a declared target, and every recorded check actually passed. Changing targets, mappings, capabilities or artifact bytes invalidates the evidence; a stale artifact token digest hides the resolved values it claimed.

If the catalogue has no verified port for your target, that is an honest gap. Treat it as one.

Anatomy of a port

A port is created under ports/<slug>/ only when implementation work begins, from templates/port/:

File Contents
port.json The manifest: target, versions, status, declared surfaces
mapping.json Theme role → native keys, plus every unmapped role with a reason (schema version 1)
capabilities.json Optional detail: integration kind, a full theme revision, surface states and reasons, each role's mapping state and surface, rollback instructions
src/ Generator inputs
dist/ The committed importable files
evidence/ Real captures — application version, OS, date — and the optional import-evidence protocol

Each classification in capabilities.json must agree with mapping.json and belong to a supported surface; inherited, unsupported, out-of-scope and not-implemented roles must stay unmapped. Without that file the older mapping contract still applies, but the explorer will report unclassified unmapped roles and missing pins.

The generator writes exports/port-capabilities.json, which is digest-covered and included in task kits. Consumers fetch it at their own pinned revision. Full rules: ports/README.md.

Starting a port

  1. Read spec/portability.md and ports/README.md.
  2. Copy templates/port/ to ports/<slug>/ and work through CHECKLIST.md.
  3. Inspect the target first. Write down which surfaces it can express before you map anything.
  4. Map roles to native keys using resolved token values only. Never invent an approximation for something the host cannot do — that is an unsupported entry.
  5. Account for every role in the declared profile.
  6. Ship as experimental. Only a real import with matching evidence earns verified.
  7. Document installation, scope and rollback for a user who wants to undo it.

For web frameworks rather than native applications, the equivalent work is in Web integration.

Private or licensed targets

Where a target cannot be redistributed, the bounded private-parity harness runs entirely outside this repository against an operator-supplied config:

npm run parity:private -- --config /private/location/parity.json

Without a target it prints a not run prerequisite record — public validation, builds and browser tests never require a private target. The harness validates installed versions against the target package and lock, copies only explicitly selected inputs into a new private directory, and captures native references and real framework controls with recorded environment, input hashes, property differences and screenshots. It never starts the target's backend or runs its package scripts. Private sources, configuration and results stay out of Git and off the public site — including when verification fails. A completed diagnostic may report differences; it does not certify an application port.

A note on terminals

A sixteen-colour terminal is the one target where the heritage-ansi profile earns its keep: it holds the historical slots exactly, including the assignments that fail the contrast floor. Use it for fidelity to the original workstation, and be explicit that you are doing so. It is not an approved profile for a new interface, and values that fail are flagged $deprecated rather than presented as ordinary passes.

Document bold-as-bright behaviour and whether the application's 256-colour or 24-bit output bypasses the slots entirely — otherwise the port claims a fidelity it does not have.


Next: Verification · Concepts · Contributing

Clone this wiki locally