targets: The Deploy-Target Registry#
The seam between the palette model and every artifact.
Each supported application is a Target: a small policy object declaring which palette hues anchor which of the app’s roles and which filenames each mode produces.
The mechanism – iterating modes, writing out/, checking drift, deploying to local config directories – lives once, in irix.cli and irix.deploy (policy/mechanism separation; see Architecture: How Irix Is Put Together).
The render contract is the parity constraint: render() takes an explicit Mode, and the engine always invokes it for both modes – a dark-only target is unrepresentable rather than merely discouraged.
Concrete targets live in sibling modules, each registered here on import: targets.editors: VSCode, kimi, Sublime, and Vim Targets, targets.portable: Portable and Creative Deploy Targets, targets.shell: Shell-Tooling Targets, targets.terminals: Terminal-Emulator Targets.
- irix.targets.Mode = Mode#
Type alias.
Type aliases are created through the type statement:
type Alias = int
In this example, Alias and int will be treated equivalently by static type checkers.
At runtime, Alias is an instance of TypeAliasType. The __name__ attribute holds the name of the type alias. The value of the type alias is stored in the __value__ attribute. It is evaluated lazily, so the value is computed only if the attribute is accessed.
Type aliases can also be generic:
type ListOrSet[T] = list[T] | set[T]
In this case, the type parameters of the alias are stored in the __type_params__ attribute.
See PEP 695 for more information.
Irix deploy-target registry: the seam between the palette model and every artifact.
Each supported application is a Target: a small policy object declaring which palette
hues anchor which of the app’s roles and which filenames each mode produces. The
mechanism — iterating modes, writing out/, checking drift, deploying to local config
directories — lives once, in irix.cli and irix.deploy (policy/mechanism separation).
The render contract is the parity constraint: render() takes an explicit Mode, and the
engine always invokes it for both modes — a dark-only target is unrepresentable rather
than merely discouraged.
- irix.targets.MODES: tuple[Mode, Mode] = ('dark', 'light')#
Every target renders exactly these modes; order is the canonical presentation order.
- class irix.targets.Anchors(*, targets: dict[str, dict[str, str | dict[str, str]]])#
The central app→hue assignment table, loaded from
irix/data/anchors/*.yaml.Historically every artifact hand-picked its own neutral and accent hues (kitty=slate, alacritty=sage, firefox=sage+jade, …). This table records those choices as data so they are made once, centrally — and so regeneration preserves each app’s established look instead of re-deciding it. One file per target family keeps the table reviewable beside the family’s renderers.
- targets#
Mapping of target name to that target’s role→address table, where an address is a
Palette.resolve-compatible'hue-shade'(or bare hue) string, or a per-mode{dark: ..., light: ...}override of the same shapeirix.semantics.Semanticsroles support (see that module for the rationale).- Type:
dict[str, dict[str, str | dict[str, str]]]
- classmethod load() Anchors#
Load and cache the packaged anchor table, merged across family files.
- Returns:
The union of every
anchors/*.yamlfile’stargetstables; target names are globally unique, so files never collide.
- address(target: str, role: str, mode: Mode = 'dark') str#
Return the palette address anchored to
rolefortarget.- Parameters:
target – Registered target name, e.g.
'kitty'.role – Target-local role key, e.g.
'neutral'or'ansi_red'.mode – Which mode’s address to return when the anchor carries a per-mode
{dark: ..., light: ...}override; plain-string anchors ignore this (the same address serves both modes). Defaults to'dark'so every pre-existing call site keeps today’s behavior unchanged.
- Raises:
KeyError – If the target or role has no anchor entry — anchoring is explicit, never defaulted, so a missing entry must fail loudly at render time.
- model_config = {}#
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- irix.targets.palette_for(mode: Mode, *, full: bool = False) Palette#
Return the palette for
mode.- Parameters:
mode – Which scheme to load.
full – Load the full Radix superset (
full/full_light) instead of the curated Irix subset.
- irix.targets.resolve_strict(palette: Palette, address: str) str#
Resolve
addressthroughpalette, raising on any miss.Palette.resolvereturns''on a miss; artifact generation must never embed an empty color, so the engine funnels every lookup through this guard.- Parameters:
palette – The palette to resolve against.
address – A
'#hex','hue-shade', or bare-hue address.
- Returns:
The resolved
'#RRGGBB'value.- Raises:
KeyError – If the address does not resolve to a non-empty value.
- class irix.targets.Target(*, name: str, family: str)#
One deployable application target.
Subclasses implement
renderfor a single, explicit mode and are registered into the module-levelREGISTRYviaregister. Reference implementation:irix.targets.terminals.KittyTarget.- name#
Unique registry key, e.g.
'kitty'.- Type:
str
- family#
The
out/subdirectory family:'terminals','shell','editors','browsers','inkscape','python','web'.- Type:
str
- render(mode: Mode) dict[str, str]#
Render every artifact this target produces for
mode.- Parameters:
mode – The scheme to render; the engine calls this once per member of
MODES.- Returns:
Mapping of artifact path (relative to
out/) to full file content. Must be non-empty for both modes — the parity suite enforces this.
- deploy_dest(relpath: str) Path | None#
Return the local config path where the
relpathartifact installs.- Parameters:
relpath – One key of
render’s result.- Returns:
The absolute destination path, or None when the artifact is generate-only (no local application consumes it directly).
- anchor(role: str, mode: Mode) str#
Resolve this target’s anchored
roleto a hex value undermode.- Parameters:
role – Target-local role key from
anchors.yaml.mode – The scheme to resolve under.
- model_config = {}#
Configuration for the model, should be a dictionary conforming to [
ConfigDict][pydantic.config.ConfigDict].
- irix.targets.REGISTRY: dict[str, Target] = {}#
The live registry; populated by
registerat import of each family module.
- irix.targets.register(target: T) T#
Register
targetunder its name; duplicate names are a programming error.
- irix.targets.all_targets() Iterator[Target]#
Iterate registered targets in name order (import family modules first).
- irix.targets.load_all_targets() None#
Import every family module in this package, registering its targets.
Family modules (
irix.targets.terminals, …) callregisteras an import-time side effect; nothing else triggers that import.clianddeploycall this once before consultingREGISTRY/all_targets, so a new family module is picked up automatically – no per-module import list to maintain here as squads add targets.
- irix.targets.source_out_root() Path#
Return the repo checkout’s
out/directory (the generation destination).Generation writes to the source tree so artifacts are reviewed and shipped as package data; it is a development-time operation and errors in wheel installs.
- Raises:
FileNotFoundError – When no source checkout is present (e.g. wheel install).
- irix.targets.packaged_out_root() Path#
Return the readable root of packaged artifacts (deployment source).
Resolves
irix.out(the built-wheel package-dir alias ofout/) and falls back to the source checkout for editable installs, where the alias never materializes.