
Widgets State Security Distribution
- 36 installs
- 50 repo stars
- Updated June 18, 2026
- josiahsiegel/claude-plugin-marketplace
Helps with security tasks.
About
widgets-state-security-distribution is a Claude Code skill for security. It helps solo builders move faster with AI-assisted development.
- widgets-state-security-distribution
- Security
- AI-coding skill
Widgets State Security Distribution by the numbers
- 36 all-time installs (skills.sh)
- Ranked #1,453 of 2,203 Security skills by installs in the Skillselion catalog
- Data as of Aug 3, 2026 (Skillselion catalog sync)
npx skills add https://github.com/josiahsiegel/claude-plugin-marketplace --skill widgets-state-security-distributionAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 36 |
|---|---|
| repo stars | ★ 50 |
| Last updated | June 18, 2026 |
| Repository | josiahsiegel/claude-plugin-marketplace ↗ |
What it does
Helps with security tasks.
Files
Widgets, State, Configuration, Security, and Distribution
Use this skill when a TUI needs product-level interaction patterns, robust application state, secure terminal handling, user customization, or shipping guidance.
Widget design principles
- Every widget has state, focus rules, keyboard behavior, mouse behavior if supported, validation, accessibility fallback, and snapshot tests.
- Keep interactions predictable: lists navigate, tables sort/filter/page, forms validate near fields, dialogs trap focus, command palettes search commands, and scrollbars indicate position without being required.
- Virtualize large lists/tables/trees and keep viewport offset, selection, and expanded nodes in state.
- For charts, progress bars, spinners, and dashboards, provide textual summaries and reduced-motion/no-animation modes.
State and event architecture
Prefer an explicit model-update-view or reducer architecture:
1. Model stores domain state and UI state. 2. Events/messages represent keys, mouse, paste, resize, timers, worker results, and errors. 3. Update transforms state and schedules side effects. 4. View renders from state and dimensions. 5. Effects run asynchronously and return messages.
This keeps rendering deterministic, makes tests cheap, and prevents background tasks from writing directly to the terminal.
Configuration and customization
- Use XDG base directories on Unix-like systems where appropriate; use platform-native config/cache/state locations on Windows and macOS.
- Allow keybinding remapping for advanced users and conflict-heavy environments such as tmux/Zellij.
- Store themes as semantic roles, not raw widget-specific colors.
- Validate config files strictly and show actionable errors in plain output if the TUI cannot start.
Terminal security
Terminal output is an interpreter. Sanitize untrusted text before writing it to a terminal or logs that may later be viewed in a terminal. Escape-sequence injection can change titles, write clipboard data, spoof prompts, hide text, or corrupt display state.
- Strip or visibly escape control characters from untrusted data unless intentionally rendering them.
- Treat pasted text as data, not commands.
- Bound paste length and validate after paste completes.
- Avoid automatic OSC 52 clipboard writes from untrusted content.
- Make hyperlinks visible and avoid misleading link text.
Distribution rules
- Document supported terminals and fallbacks.
- Ship a
--no-tuipath for automation, accessibility, and incident recovery. - Package with platform conventions: static binaries where feasible, Homebrew/Scoop/Winget/MSI/packages as appropriate, shell completions, manpages, and checksums.
- In containers, detect missing TTY and provide line-oriented behavior.
- Ensure crash cleanup works in release builds, not just development.
Reference files
references/widget-patterns.md- Common terminal widgets, behavior contracts, and anti-patterns.references/state-config-distribution-security.md- MVU state, async effects, config, packaging, and terminal security.
State, Configuration, Distribution, and Security Reference
MVU and reducer patterns
A robust TUI can usually be expressed as:
Model: domain data plus UI state such as focus, viewport, theme, terminal size, selected IDs, modal stack, pending edits, and async status.Message/Event: decoded keyboard, mouse, paste, resize, timers, worker replies, process output, and errors.Update: pure or mostly pure state transition that returns next state and effects.View: deterministic rendering from model and terminal dimensions.Effect/Command: async work that reports completion as messages.
Do not let effects write to the screen. Effects should send messages; the renderer owns terminal output.
Async and concurrency
- Use queues/channels/tasks to merge input, timers, worker results, and resize events.
- Make long work cancellable.
- Debounce search/filter and coalesce repeated progress updates.
- Preserve ordering for user-visible messages where it matters.
- Avoid data races between background work and rendering state.
Configuration
- Prefer explicit CLI flags for temporary behavior and config files for persistent preferences.
- Unix-like paths: follow XDG config, state, cache, and data conventions when practical.
- Windows/macOS: use platform-appropriate app config locations rather than hard-coded dotfiles only.
- Make keybindings user-remappable; detect duplicates and conflicts.
- Store themes as semantic roles with color-level fallbacks: no-color, 16-color, 256-color, truecolor.
- Include an ASCII/Unicode preference and a reduced-motion preference.
Config path examples:
| Purpose | Unix-like | macOS | Windows |
|---|---|---|---|
| Config | $XDG_CONFIG_HOME/app/config.toml or ~/.config/app/config.toml | ~/Library/Application Support/App/config.toml | %APPDATA%\App\config.toml |
| State | $XDG_STATE_HOME/app/state.json or ~/.local/state/app/state.json | ~/Library/Application Support/App/state.json | %LOCALAPPDATA%\App\state.json |
| Cache | $XDG_CACHE_HOME/app/ or ~/.cache/app/ | ~/Library/Caches/App/ | %LOCALAPPDATA%\App\Cache\ |
| Data | $XDG_DATA_HOME/app/ or ~/.local/share/app/ | ~/Library/Application Support/App/ | %LOCALAPPDATA%\App\Data\ |
Document the exact paths in app config paths or --help output. Provide --config, --no-config, and environment overrides only when they are useful and testable.
Packaging and distribution
- Static or mostly static binaries simplify Rust, Go, Zig, and some C/C++ deployments, but verify terminfo, TLS, and native dependencies.
- Cross-compile only if you also test on the target platform.
- Common channels include Homebrew, Scoop, Winget, MSI, distro packages, AppImage, language package managers, archives with checksums, and containers.
- Containers rarely have a rich TTY by default. Detect non-TTY and document
-itusage if interactive mode is intended. - Ship shell completions, examples,
--help, manpage/docs, release notes, and an uninstall/config cleanup story.
Distribution checklist:
| Channel | Include | TUI-specific checks |
|---|---|---|
| Homebrew | formula, checksum, completions | macOS Terminal/iTerm smoke test; bottle architecture coverage. |
| Scoop | manifest, autoupdate, hash | Windows Terminal and PowerShell launch; path quoting. |
| Winget | installer manifest, version metadata | Silent install/uninstall; PATH and code-signing expectations. |
| Archives | .tar.gz/.zip, checksums, signatures | Executable bit on Unix archives; README with --no-tui. |
| Containers | image tags, entrypoint docs | docker run -it; TERM/locale; non-root config/cache path. |
| Language packages | npm/pip/cargo/nuget metadata | Native dependency availability and postinstall behavior. |
Release/upgrade checklist:
- Version is updated by the repository's version tooling, not by hand.
- Changelog includes terminal compatibility, keybinding, config, and accessibility changes.
- Config migrations are idempotent, backed up if destructive, and have
--dry-runwhere appropriate. - Exit codes remain documented:
0success/normal quit,1generic failure,2usage/config error,130interrupted, plus domain-specific codes if needed. - Upgrades do not silently enable mouse, clipboard, telemetry, or destructive keybindings.
- Old config paths either migrate or produce a clear message.
- Release artifacts are smoke-tested in non-TTY mode and at least one full-screen TUI mode.
Terminal security
Untrusted strings can contain control bytes. If rendered raw, they may inject CSI/OSC/DCS sequences, change terminal title, create misleading hyperlinks, write clipboard data, hide output, or spoof prompts.
Malicious examples:
"build failed\x1b[2J\x1b[HAll tests passed" # clears screen and spoofs success
"name\x1b]0;prod shell\x07" # changes terminal title
"url\x1b]8;;https://evil.invalid\x1b\\click\x1b]8;;\x1b\\" # misleading OSC 8 link
"copy\x1b]52;c;VE9LRU4=\x1b\\" # attempts clipboard write
"hide\x1b[?25l" # hides cursor if not reset
"\x1b[31mERROR\x1b[0m" # forges styled severitySafe rendering policy:
1. Treat all domain data, filenames, log lines, process output, network data, and pasted text as untrusted. 2. Style through structured spans owned by the renderer, not embedded escape sequences in data. 3. Strip or escape C0/C1 controls except explicitly allowed whitespace (\n, \t, optionally \r in progress parsing). 4. Replace ESC with visible ^[ or \x1b in debug/raw views. 5. Validate URLs before OSC 8; display the target URI in text or offer a reveal action. 6. Disable OSC 52 by default for untrusted content; require explicit copy action and a user setting. 7. Bound OSC/DCS parser payload length to avoid memory abuse.
Sanitization strategy:
sanitize_for_terminal(input, mode):
normalize line endings if needed
for each grapheme or byte sequence:
if printable Unicode scalar and not bidi-control-forbidden: keep
else if char is allowed whitespace: keep
else if mode == debug: append visible escape such as "\\x1b" or "^["
else: append replacement marker or drop
return safe text plus separate style metadataFor logs that may later be viewed in terminals, sanitize before writing or provide a safe viewer mode. Do not rely on downstream pagers to neutralize control sequences.
OSC 8 and OSC 52 cautions
- OSC 8 hyperlinks should never hide a surprising destination. For package names, issue IDs, or hosts, show a visible URL in a detail panel or status line.
- OSC 52 clipboard writes can exfiltrate or overwrite clipboard data. Gate behind
--clipboard=always|ask|never, default conservatively, and never trigger from untrusted text. - Terminals, tmux, SSH policies, and security tools may block OSC 52. Treat failure as normal.
- When recording or sharing terminal logs, strip OSC 8/52 sequences so links and clipboard payloads are not executed by viewers.
Error handling and restoration
- Use RAII/defer/finally/dispose guards for raw mode, alternate screen, cursor visibility, mouse, paste, focus, terminal title, palette, and keyboard modes.
- Cleanup must be idempotent and safe after partial initialization.
- Provide recovery instructions in help and docs: quit keys,
reset,stty sane, reopen terminal,--no-tui. - Preserve meaningful exit codes for normal quit, validation failure, interrupted operation, and unexpected crash.
TUI Widget Pattern Reference
MVU event/message taxonomy
A useful message set separates user input, system events, and effect replies:
InputMsg:
Key(key, modifiers)
Mouse(kind, row, col, button)
Paste(text)
SystemMsg:
Resize(width, height)
Tick(now)
FocusIn | FocusOut
DomainMsg:
SearchChanged(text)
RowActivated(id)
FormSubmitted(values)
EffectMsg:
LoadStarted(request_id)
LoadSucceeded(request_id, data)
LoadFailed(request_id, error)
CommandProgress(request_id, percent, line)Async command pattern:
update(model, SearchChanged(q)):
model.query = q
model.loading = true
request_id = new_id()
model.active_search = request_id
return model, debounce(150ms, Search(request_id, q))
update(model, LoadSucceeded(id, data)):
if id != model.active_search: return model, none # stale result
model.loading = false
model.rows = data
model.table.selected = clamp(model.table.selected, data.len)
return model, noneEffects should report messages. They should not mutate widget state directly and should not write to the terminal.
Text input and text area
State shape:
TextInputState:
value: grapheme buffer
cursor_grapheme: int
selection: optional range
horizontal_offset_cells: int
placeholder: text
validation: ok | warning | error(message)
is_secret: bool
composing: optional IME/preedit text if supported- Cursor movement, deletion, selection, and word navigation must respect grapheme clusters and cell widths.
- Support paste as literal text, length limits, validation, masking for secrets, and clear error messages.
- Multiline text areas need scroll offset, line wrapping, Home/End semantics, and visible cursor positioning.
Tables
State shape:
TableState:
rows: [RowId]
selected: int
scroll_y: int
scroll_x: int
sort: [{column, direction}]
filter: text
columns: [{id, min, preferred, max, priority, align, truncate}]
loading: bool
error: optional textPatterns:
- Selection and scroll are UI state; row data belongs to the domain model or cache.
- Column sizing should be deterministic: reserve fixed columns, distribute remaining width, hide low-priority columns below thresholds.
- Render only visible rows plus optional overscan.
- Include no-color indicators for selection (
>), sort (sort: name asc), and errors (ERROR:text). - Preserve selected row by stable ID across refreshes when possible.
Trees
State shape:
TreeState:
root_ids: [NodeId]
expanded: Set<NodeId>
selected: NodeId
visible_flattened: [NodeId] # derived/cache
scroll_y: int
filter: optional textPatterns:
- Flatten the visible tree after expansion/filter changes; render the flattened slice.
- Keep expansion by stable node ID, not row index.
- ASCII fallback:
+,-,|, `-- `` instead of box drawing. - Search should reveal path context or provide a separate results mode.
Command palettes
State shape:
CommandPaletteState:
open: bool
query: text
selected: int
results: [{id, title, aliases, description, disabled_reason, dangerous}]
mode: commands | files | symbolsPatterns:
- Search titles, aliases, descriptions, and keybindings.
- Disabled commands remain visible with a reason when discoverability matters.
- Destructive commands require confirmation outside the palette.
- Keep palette actions keyboard-first: Up/Down, Ctrl-N/Ctrl-P, Enter, Esc, Ctrl-U clear.
- Do not hide commands only because the mouse is unavailable.
Forms
State shape:
FormState:
fields: [{id, label, value, touched, dirty, validation, help, secret}]
focus_index: int
submit_state: idle | submitting | failed(message) | succeeded
original_values: mapPatterns:
- Validate on blur and submit; show field-local messages as soon as useful.
- Keep labels stable and inputs aligned.
- Mask secrets but support explicit reveal/copy rules where appropriate.
- Preserve dirty/touched state so async validation does not erase user edits.
- Provide
--config, flags, stdin, or environment alternatives for automation.
Lists, tables, and trees
- Keep selection, scroll offset, filter, sort, and expanded nodes in state.
- Virtualize large data sets and render only visible rows.
- Provide keyboard navigation: arrows, PageUp/PageDown, Home/End, search/filter, and activation.
- Tables need stable column sizing, truncation rules, horizontal scrolling or responsive column hiding, and no-color indicators for sort/selection.
- Trees need expand/collapse keys, depth indentation, and ASCII fallback for branch glyphs.
Charts, progress, and spinners
- Charts in terminals are approximate; include textual values and units.
- Braille, block, and sparkline charts need ASCII fallback.
- Progress bars need percentage, counts, rate, ETA when meaningful, and a log-friendly non-animated mode.
- Spinners must be suppressible for reduced motion, CI, and logs.
Dialogs, modals, and notifications
- Modal dialogs should trap focus, expose clear accept/cancel keys, and restore prior focus on close.
- Destructive dialogs should name the object and action, not rely on red text.
- Toasts/notifications should not hide persistent errors; provide a stable status area or log panel.
Tabs, split panes, and viewports
- Tabs need keyboard switching and visible active state without color dependency.
- Split panes need minimum sizes and predictable collapse behavior on narrow terminals.
- Viewports need scroll offset, total size, visible range, and clear behavior after resize.
- Scrollbars are indicators, not the only navigation mechanism.
Menus, command palettes, and file pickers
- Menus should support arrows, mnemonics where appropriate, search/filter for long lists, and Esc/cancel behavior.
- Command palettes should search labels, aliases, and descriptions; show disabled reasons; and keep destructive commands confirmable.
- File pickers need permission error handling, symlink clarity, hidden file toggles, and path input fallback.
Anti-patterns
- Hidden actions only available by mouse.
- Meaning encoded only through color or icons.
- Overusing modal popups for routine status.
- Rendering every row of a huge table.
- Widgets that own global terminal state independently.
- Forms that report validation only after final submit when inline feedback is possible.