Feather architecture¶
Feather is organized around release boundaries: everything a user installs lives under apps/, while packages/ contains contracts and implementation shared by those applications. This document is the permanent reference for that boundary, its release trains, and the invariants every commit must preserve.
Layout¶
feather/
├── apps/ Everything that ships to a user
│ ├── inspector/ [platform] Tauri desktop. Session-bound debugging surfaces.
│ ├── studio/ [satellite] Shader graph · texture lab · particle lab.
│ │ Its own binary, identifier, version and release feed.
│ ├── showcase/ [satellite] Thin shell: Studio for the web. No page code.
│ ├── cli/ [platform] @kyonru/feather.
│ ├── vscode-extension/ [satellite] Vendors a pinned platform snapshot.
│ └── docs/ [satellite] Zensical site.
├── packages/ Reusable contracts and runtime consumed by applications
│ ├── protocol/ ◆ Wire message registry and envelope.
│ ├── host/ ◆ Environment capabilities. tauri/ and web/ impls.
│ ├── session-bridge/ ◆ Versioned Inspector↔Studio contract.
│ ├── ui/ Shared interface primitives and the theme registry.
│ └── runtime-lua/ The Lua runtime and built-in plugins. To LuaRocks.
└── catalog/
└── packages/ Love2D package registry.
◆ = the three contracts that make the split hold.
Kept together deliberately: the 13 Inspector surfaces (one session, sidebar and socket); the
three creative tools (they cross-import, and all live in Studio); the built-in plugins (ride the
platform train with the runtime); feather-server with Inspector.
packages/protocol — the cohesion anchor¶
A TypeScript registry is the source of truth for all 78 wire message names (44 Inspector→game, 34
game→Inspector) and the common envelope. TypeScript consumers use derived unions and guards; a
generator emits the Lua message table; check:protocol verifies both live dispatch tables and the
generated output. Payload data stays unknown until a handler has a load-bearing reason to own a
schema (D14); Rust stays a transparent relay (D15). A standalone integer protocolVersion rides
feather:hello, with a named Inspector error on mismatch (D9, D18).
Runtime and session reliability¶
The implemented runtime and session safeguards below are permanent behavioral invariants, not roadmap items:
- An incompatible game remains visible for historical inspection, but Inspector rejects live refreshes and mutating commands locally until that session reports a compatible protocol.
- Session lifecycle events affect only their named session. A background game connecting or disconnecting cannot replace the active game or mutate another session's connection state.
- A runtime log batch is applied as one state update, and in-memory log and performance histories have explicit bounds.
The remaining hardening work and its acceptance checks live in the repository's
ROADMAP.md.
packages/host — what the environment can do¶
Open a file, save a file, pick a directory, workspace storage, theme, open external. Two implementations: Tauri (Studio desktop) and web (showcase). Studio owns its workspace state in both; the host only supplies capabilities (D20).
packages/session-bridge — a versioned process boundary¶
- Inspector is the only owner of the authenticated game session and WebSocket server.
- Studio runs fully standalone with
bridge: null; the showcase always does. - Explicit local pairing lets Studio send the contract's high-level commands to Inspector. Studio never probes loopback by itself — a deliberate security property.
- Loopback-only, authenticated with a short-lived Inspector-issued capability, negotiating a bridge protocol range. Never log, persist, or put the capability in a URL.
- Disconnect, incompatible-version, revoked-capability and Inspector-not-running states are visible and recoverable; a rejected bridge never falls back to an unauthenticated channel.
- Neither application imports the other's source or loads its JavaScript.
32 tests in packages/session-bridge/test/bridge.test.mts, most of them negative. Read them before
changing the connection.
One MCP server, two backends (D32)¶
feather mcp is the one server an agent configures. It routes /creative/* to Studio's backend
(:4007) and everything else to Inspector's (:4005). Each app mints its own loopback token per launch
on its own port; neither reads the other's credentials. When the app behind a route is not running,
the error names it (Feather Studio is not running. Start it and try again.).
- Inspector's backend: sessions, logs, performance, assets, observers, plugin state, runtime control, debugger, Console (under its gates), time travel, Session Replay, plugin catalog.
- Studio's backend: Shader Graph, Particle Playground and Texture Lab authoring plus local
creative snapshots, previews and exports. Particle tools mutate Studio's active local workspace
by default without Inspector; callers pass an explicit
sessionIdonly for live-game operations such as emission and runtime preview.
--studio-url / --studio-token (or FEATHER_STUDIO_MCP_URL / FEATHER_STUDIO_MCP_TOKEN) point
at Studio's side. There is no --target flag.
Release trains and versioning¶
One compatibility family with independently releasable trains. The platform family is the set of artifacts that speak the game wire protocol; it is a compatibility concept, not one lock-step train.
| Train | Members | Tag | Publishes |
|---|---|---|---|
| Coordinated platform | CLI + runtime + Inspector/server | v4.1.0 |
All three at one version, plus feather-platform.json (D25) |
| CLI | cli |
cli-v* |
npm package and the standalone binaries (D27) |
| Runtime | runtime-lua |
runtime-v* |
LuaRocks package and runtime GitHub release |
| Inspector | inspector, feather-server, MCP session backend (:4005) |
desktop-v* |
Signed/notarized Inspector binaries |
| Studio | studio, its Tauri shell, MCP creative backend (:4007) |
studio-v* |
Signed/notarized Studio binaries, own feed |
| Extension | vscode-extension |
ext-v* |
GitHub VSIX, Visual Studio Marketplace and Open VSX, vendoring a declared featherPlatform |
| Continuous web | showcase, docs |
— | Deployments from main |
| Catalog | catalog/packages |
— | Registry push to the packages branch |
Worked examples: a CLI patch tags cli-v4.0.1 and nothing else publishes. A shader graph feature
tags studio-v1.3.0; Inspector is untouched. A game protocol change tags v4.1.0 and moves runtime,
CLI and Inspector together; Studio stays independent unless the bridge contract also changes.
Studio is a separate installed application — own identity (com.kyonru.love.feather.studio),
version source, permissions, signing and feed. Inspector never embeds, downloads or executes Studio
code. scripts/set-version.sh <train> <version> writes only that train's files;
scripts/release-tag-version.sh maps a tag to its train. scripts/release-train.mjs validates the
committed version files and tag namespace for any train, defaults to a dry run, and creates and pushes
only the selected tag when --push is explicit.
The honest trade: "one number, always correct" became "a few declared ranges, verified in CI". That only works while CI enforces them — a declared-but-unchecked range is worse than lock-step.
Invariants¶
These hold for every commit.
mainis always shippable; no change leaves a train un-releasable. Prove release-workflow changes with a dry-run or pre-release tag before merging.- Protocol changes update the generated Lua table and pass the TypeScript/dispatch-table checks. Do not generate Rust types for messages the relay does not deserialize (D15).
- Cross-package imports go through package entry points, never another package's
src/. Inspector and Studio never import each other (no-restricted-imports); shared code goes inpackages/. - Generated files stay in sync:
check:registryandcheck:plugin-catalogpass, and the pre-commit hook enforces it. - Docs move with the code; symlink targets move in the same commit.
- Commit scopes must exist in
.husky/commit-msgbefore use. .husky/pre-pushrunspnpm run test; do not weaken it without replacing it.- Release builds stay Feather-free by default; Console, hot reload, filesystem and network stay opt-in.
Phase record¶
What each phase delivered, for code comments that cite a phase.
| Phase | Delivered |
|---|---|
| 01 | Per-train tags and train-scoped set-version.sh; pre-commit enforces only the desktop trio |
| 02a | protocolVersion negotiation over feather:hello, named mismatch error (D9, D10, D18) |
| 02b | packages/protocol registry for names and envelope; generated Lua table; payload schemas declined (D13, D14, D41) |
| 03 | pnpm + Turborepo at the existing layout (D3, D16, D17) |
| 04 | packages/ui and packages/host extracted; the showcase import inversion removed (D19–D22) |
| 05a | Studio-owned state extracted in place, with an eager persisted-state migration (D28, D37) |
| 05b | Studio application scaffolded; packages/session-bridge contract and transport (D38) |
| 05c | The three creative tools moved out of Inspector (D38, D39, D43) |
| 05d | Separate builds, release workflow, showcase as a thin shell, check:artifact-boundary (D35) |
| 06 | runtime-lua as a package, catalog moved to catalog/, CI path filters retired (D23, D24, D40) |
Glossary¶
| Term | Meaning |
|---|---|
| Train | A set of artifacts that version and release together. |
| Platform family | Runtime, CLI, Inspector, and server: independently releasable artifacts connected by the game protocol and optionally coordinated by a v* tag. |
| Satellite | An artifact that releases on its own cadence and declares a compatibility range. |
| Contract | A typed, versioned seam between independently released code: protocol, host, or session bridge. |
| Host | The environment a UI runs in—Tauri desktop or browser—and the capabilities it provides. |
| Bridge | The authenticated, optional local process connection from Studio to an Inspector-owned live game session. |
| MCP session/debug backend | Inspector-owned automation for live sessions, runtime state, plugins, debugger, Console, time travel, and replay. Served on port 4005 and reached through feather mcp. |
| MCP creative backend | Studio-owned automation for shader, particle, texture, and other creative workflows. Served on port 4007 and reached through feather mcp at /creative/*. |
| Inspector | The session-bound Feather desktop application: debugging, logs, performance, assets, plugins, and related surfaces. |
| Studio | The separate desktop/web application containing Shader Graph, Texture Lab, and Particle Playground. |