Command palette and picker UI for the Bitty terminal, presented through the overlay slot with declarative list and text primitives only.
- Plugin id:
bitty-terminal.palette - Lua module:
lua/palette/ - Capabilities:
ui.overlay.focus - Lazy commands:
bitty-terminal.palette:toggle - Lazy events:
focus.changed,overlay.released
This repository is the independent first-party package created by the bundled
plugin split decision (OQ-053, bitty-plugins-docs product/bundled-plugin-split-decision.md),
owned by bitty CTX-0397. It was scaffolded from
bitty-plugin-template.
Pre-implementation ecosystem: the plugin package, manifest, and policy are
implemented and tested headlessly; the Bitty host is still landing the Plugin
API v1 overlay bridge. Nothing here is a compatibility promise beyond the
manifest [compat] ranges.
| Path | Purpose |
|---|---|
bitty-plugin.toml |
Static manifest: identity, compatibility, capability requests, and lazy triggers. |
lua/palette/init.lua |
Entry point evaluated once per activation; registers the toggle command and the capture session. |
lua/palette/filter.lua |
Bounded, host-free input scanning, filtering, and text-truncation policy. |
lua/palette/scene.lua |
Declarative List/Text overlay composition, including the non-empty default scene. |
tests/ |
Lua 5.4 behavior suite and LuaLS conformance. |
package.json |
Pinned dev dependencies: the authoritative bitty-plugin-lint by commit, plus tooling. |
bun.lock |
Locked dependency graph installed by just install. |
justfile |
Quality gates with pinned tool versions. |
The plugin keeps the behavior and bounds of the former bundled palette; this package now defines them:
- case-insensitive substring filtering over a bounded entry list, at most
128displayed entries (PALETTE_MAX_ENTRIES); - candidate input bounded to
1024examined entries per filter pass (MAX_INPUT); oversizedentriessettings are cut at the bound and the cut is reported through the filter stats (filter.filterreturns{ scanned, truncated }as its second value); - non-table
entriessettings fail closed to an empty list; - query truncated to
128characters, display text truncated to the host overlay text bound128(MAX_OVERLAY_TEXT_LEN) at a UTF-8 code-point boundary; - overlay content composed as a single declarative
ListofTextrows (Text,Row,Column,Listare the only Plugin API v1 node kinds); - every open acquires the focusable overlay plus transient input capture in
one Core-owned switch
(
bitty.ui.overlay.acquire({ title = "Palette", placeholder = "Filter commands" })); the Core surfaces only the capture owner's block, so the acquire is what makes the overlay visible; - the open scene is never empty: the title row plus the filtered items, or the
title plus a
No entriesplaceholder row when the list is empty — a real UI, not a bare pill; - closing ends the session (
bitty.ui.overlay.release(handle, "cancelled")), which destroys the surface; an involuntary session end (focus switch, idle timeout, unload) observed throughoverlay.releasedresets the toggle state so the next toggle re-opens; - host capture calls are
pcall-guarded: a denied focus grant, a live foreign session, or a host without the capture table degrades to command-only mode (counts still returned), and a rejected session update keeps the last successfully presented scene instead of throwing at the command caller or the event dispatchers; togglereturns the number of displayed entries (0when closing) and declares a closed empty-objectargs_schemaplus an integerresult_schemamatching the returned count;- refresh on
focus.changedwhile a session is held.
This package is now the only realization of the palette envelope and
behavior. The historical bundled Rust realization in bitty is gone: its
manifest left the bundled catalog (crates/bitty-plugin-host/src/bundled.rs)
when the palette migrated to this package (CTX-0397), and its runtime module
(crates/bitty-runtime/src/palette.rs) was removed by bitty PR #1611
(commit 67cdcc14). That realization declared only ui.overlay because it
used the lower-level Panel Runtime overlay path.
This package requests neither v1 presentation grant. The accepted W-01
overlay-input-capture contract couples the focusable surface and its capture
session under the single ui.overlay.focus grant, and the spec-acquire path
mounts the surface without passing the v1 ui.overlay slot gate — so the
former ui.rich + ui.overlay pair is unrequested. The v1 ui.overlay slot
stays presentation-only and non-focusable by design.
This is a recorded, intentional difference for bitty-terminal/bitty#1971.
Dropping the v1 grants is a narrowing (one grant instead of two) with no new
authority: no filesystem, process, network, clipboard, or Terminal Truth
access, and release stays ungated so cleanup can never wedge input.
- Entry source. The accepted v1 surface exposes no command-registry
enumeration and no
PickerProvider(the Plugin Reuse and Provider Ecology RFC is draft/post-1.0). The palette reads its bounded entry list and query from its own settings namespace (entries,query) as a v1 adapter. - Interactive query input. v1 has no text-input surface for overlays, and
this package does not yet drain the capture queue (
bitty.ui.overlay.poll), so the query is read from settings rather than typed live.
Install the pinned dependencies once, then run the same gate CI runs:
just install # bun install --frozen-lockfile; the only network step
just checkjust install materializes bitty-plugin-lint (bitty-plugin-sdk, pinned by
commit in package.json and bun.lock) and luaparse; every gate then runs
offline and fails closed when the dependency is absent. just manifest
validates bitty-plugin.toml with the authoritative SDK linter against the
accepted contract in bitty-docs
docs/specifications/plugin-platform-rfc.md (file name, identity,
compatibility, capability closed set, lazy triggers, hard limits). just lua
parses the Lua modules with the pinned luaparse 0.3.1 grammar. lua5.4 is
required for the behavior suite; lua-language-server is optional and
just test-luals skips with exit 0 when absent.
An external package is installed from a local checkout with the Bitty CLI:
bitty plugin install /path/to/paletteThe registry entry in
bitty-plugins points at this
repository; this plugin previously shipped as a bundled (staged, disabled by
default) bitty-terminal.palette.
Only ui.overlay.focus is requested: one focusable overlay plus the bounded
transient input-capture session for one interaction. The plugin has no
filesystem, process, network, clipboard, terminal-input, or persistent-state
authority. It performs no I/O and spawns nothing. Report vulnerabilities through the process
in the umbrella project's security policy rather than a public issue.