CLI
The development tool that copies component source into your app and helps you keep it up to date with the registry.
After init,
run every command through bin/shadwire. The binstub loads the CLI
from the app's bundle, so everyone on the project uses the same version.
bin/shadwire help COMMAND shows the help for a command.
Commands
| Command | What it does |
|---|---|
shadwire init |
Prepares the app: writes shadwire.json, installs the shared base files (ui_component.rb, shadwire.css) and the base gems, adds shadwire to the development group, creates the bin/shadwire binstub, and inserts the Tailwind @import. |
bin/shadwire add NAME... |
Installs one or more components along with their registry dependencies, applies gems and importmap pins, and records all of it in shadwire.json. |
bin/shadwire list |
Lists every component in the registry's catalog. |
bin/shadwire search QUERY |
Searches the catalog by name, title, description and when-to-use text, so you can search for things like form, modal or loading. |
bin/shadwire info NAME |
Shows the component's full API: helpers, variants, sizes, props, files, gems, pins and registry dependencies. |
bin/shadwire diff [NAME...] |
Compares the installed files against the registry and reports unchanged, modified or missing, with a unified diff for the modified ones. Read-only. |
bin/shadwire update [NAME...] |
Reapplies the registry's version of the installed components. Overwrites local edits, so run diff first. |
bin/shadwire remove NAME... |
Uninstalls components. It only deletes their own files, never the shared base files or a file another installed component still uses. |
bin/shadwire status |
Describes the whole app in one call: detected stack, installed components with the helpers they define, and drift. |
bin/shadwire version |
Prints the installed version of the CLI. |
Reference
status
Describes the project in a single call. Run it first. It is also the only command an agent needs to have in its context.
| Field | How to read it |
|---|---|
installed[].helpers |
The ui_* methods defined in this app. Calling the helper of a component that is not installed raises NoMethodError. |
installed[].drift |
unchanged, modified, missing or unknown. |
stack.importmap |
Whether importmap and Stimulus are present. The interactive components need both. |
cli.binstub |
Whether bin/shadwire exists. If it is false, run init. |
helpers.includeAllHelpers |
False means the app turned off Rails' automatic helper inclusion, so each controller needs a helper call for the Ui::*Helper modules. |
helpers.legacyHelperPresent |
An app/helpers/ui_helper.rb left over from before helpers were split per component. It defines helpers for components you have not installed, and you can delete it. |
search
Search looks at the name, title, description and
the when-to-use text, so you can search for what you need:
form, modal, overlay,
loading, right-click.
info
The component's full API. Check it before writing ERB so you are not guessing at
arguments. It returns whenToUse, usage snippets,
requiresStimulus, registryDependencies, the
install files, and api.components[] with each class's helper,
variants, sizes, props and attributes.
helper is null for anything without a
ui_* wrapper: the base superclass, the internal parts a parent
component renders by itself, and blocks. File contents are left out.
add
Without --yes, files that already match the registry are skipped,
and it asks about the ones you changed. In a non-interactive shell without
--yes, everything is skipped and nothing gets installed.
diff
Changes nothing. Marks each file as unchanged,
modified or missing, with a unified diff for the
modified ones.
update
update overwrites local edits
diff first. update does list what it replaced
(overwritten and diffs in the JSON output), but only after the
fact. See how to keep your edits.
remove
It only deletes files that belong to the components you remove. The shared base files, and any file another installed component still uses, stay in place. Importmap pins that nothing uses any more are listed but not removed.
Flags
| Flag | Commands | Effect |
|---|---|---|
--cwd DIR |
all | Runs against another application directory instead of the current one. |
--registry URL |
all | Reads from another registry. Accepts https:// and file:// URLs; use file:// to test a registry you built locally. |
--json |
all but version | Prints JSON instead of human-readable output, for agents and CI. |
--yes, -y |
init, add, update, remove | Applies file and dependency changes without asking. |
--overwrite |
add, update | Overwrites locally modified files without asking. |
--no-deps |
add, update | Skips transitive registry dependencies (on by default). |
--force |
init | Rewrites an existing shadwire.json and recreates the binstub. |
--exit-code |
diff | Exits non-zero when there is drift, so CI can fail on it. |
Errors and exit codes
Exit code 0 means the command worked. If a command could not install a dependency, it says so and exits non-zero, so you can rely on the exit code instead of checking the Gemfile yourself.
Each error is a single line on stderr that tells you what to do. These are the messages
for a malformed shadwire.json, an unreachable registry, a registry
that returns HTML, and a missing argument:
The exception is status, which never fails: it returns
"rails": false, registryError or
configError as fields and exits 0. That makes it safe to run
anywhere, including when an agent loads it.
In CI
Every command accepts --yes (no prompts), --json
(JSON output) and --cwd (run in another directory). This job fails
the build when an installed component no longer matches the registry:
The job needs the development group installed; without it,
bin/shadwire will not run.