Imported from jichong-tay/stitchyard (
AGENTS.md). Install upstream withnpx skills add jichong-tay/stitchyard. Copyright stays with the author.
Repository guidance for coding agents
Scope and intent
These instructions apply to the entire repository. Stitchyard is the
installable FastHTML and Tailwind component library under src/stitchyard/.
Switchyard is the API gateway and server-monitoring showcase under
examples/switchyard/. The showcase may depend on Stitchyard; Stitchyard must
never depend on the showcase.
Preserve direct Tailwind utilities, Python FT component functions, and explicit HTMX contracts unless the user authorizes an architectural migration.
Start with the correct catalog
The installed Stitchyard catalog is canonical for the reusable public surface, including signatures, variants, requirements, accessibility, responsiveness, patterns, and HTMX ownership. Before changing reusable UI code, follow this lookup order exactly:
- Query by intent, for example
uv run stitchyard --intent "status badge" --json. - Narrow ambiguous results with
--category, then retrieve the chosen record with--name. Use--allonly for catalog audits or when targeted queries return nothing. - Import the selected symbol from the stable
stitchyard.uipublic surface. - Inspect only the selected function or class and its direct helpers. Do not
scan every file under
src/stitchyard/ui/orpatterns.py. - Read one or two call sites and the focused
tests/test_stitchyard_*.pyassertions that cover its contract. - Inspect assets, routes, or application state only when those contracts change.
- Create a component only after the catalog confirms no existing primitive, composition, or compatible extension expresses the requirement.
Use the showcase catalog only for Switchyard-specific work such as gateway tables, monitoring widgets, drawers, or pages:
uv run python -m examples.switchyard.catalog --intent "filter routes" --json
Showcase portable records may already re-export Stitchyard components. Treat
adapt entries as integration examples and reference entries as product
examples, not installable library APIs. Never import examples.switchyard from
src/stitchyard.
Use docs/using-from-another-repo.md for downstream integration,
docs/component-patterns.md for pattern semantics, and
docs/offline-assets.md before changing packaged runtime assets. Use
docs/browser-behaviors.md before changing the showcase's data-* actions,
global events, overlay state, focus behavior, or static/js/ files.
Use before create
Prefer these choices in order:
- Reuse an existing Stitchyard component unchanged.
- Compose existing primitives with
Stack,Cluster, or a feature-owned function. - Extend an existing component with an optional keyword-only argument whose default preserves current output.
- Create a narrowly named shared component when at least two consumers need the same semantic structure or one complex interaction needs an isolated contract.
Do not add a second button, badge, field, panel, switch, status, empty-state, or layout pattern beside an existing one. Do not extract a generic wrapper for one short call site. Keep pages thin and application concerns outside the library.
Library ownership and component patterns
- Keep app-neutral components in
src/stitchyard/ui/and reusable structural patterns insrc/stitchyard/patterns.py. - Keep routes, repositories, prepared product models, the dashboard shell,
gateway widgets, and monitoring compositions in
examples/switchyard/. PanelDecoratorwraps an unchanged FT tree with presentation; it is a structural decorator, not Python@decoratorsyntax.StackandClusterown generic composition layout only.Whenselects already-prepared, side-effect-free render values.StatefulToggleis immutable and render-local/in-memory only. It does not persist between requests, workers, or restarts. Durable state belongs to the consumer's domain layer and is passed back into a new render.CardTemplatedefines uniform slots, whileComponentFactorycentralizes named creation in an instance-local registry. Do not introduce a mutable process-global component registry.
Styling and generated files
- Use direct Tailwind utilities, existing semantic tokens,
cx(), and complete, statically visible class strings. Never construct utilities through interpolation such asf"bg-{tone}-500". - Put shared token changes in
assets/theme.css, installable authored rules inassets/library.css, and library imports/source discovery inassets/stitchyard.css. src/stitchyard/_static/stitchyard.cssis generated package output. Never edit it directly. Runnpm run watch:library-csswhile developing andnpm run build:library-cssbefore testing a wheel.assets/components.cssandassets/tailwind.cssbelong to the Switchyard showcase.static/styles.cssis its generated output and must not be edited. Usenpm run watch:cssornpm run build:css.- Run
npm run buildwhen both library and showcase outputs must be refreshed. - Keep the graphite hierarchy: black canvas, charcoal surfaces, zinc borders, and off-white primary controls. Green, amber, and coral communicate healthy, warning, and error states rather than decoration.
- Adding daisyUI, Flowbite, another component library, or a styling runtime is an architecture change and requires explicit user authorization.
Stable FastHTML component contracts
- UI functions accept prepared display data and return deterministic FastHTML FT trees. They do not query repositories, inspect requests, or mutate shared state.
- Preserve public names, defaults, IDs, accessible names, URL overrides, and serialized markup. Prefer optional keyword-only parameters for compatible extensions.
- Pass behavior through explicit URLs and attributes instead of embedding application route knowledge in portable primitives.
- Every component must render correctly alone, inside a full page, and as an HTMX response when it declares an HTMX contract.
- Export public library symbols through
stitchyard.uiand add or update the matching record insrc/stitchyard/catalog.pyin the same change. - Add product-specific records only to
examples/switchyard/ui/catalog.py.
HTMX fragment ownership
- Every fragment has one stable root that owns its swap boundary.
- An
outerHTMLresponse returns the same owning root and ID. AninnerHTMLresponse returns only content valid inside the target host. - Full-page and fragment routes reuse the same component functions; never maintain duplicate markup.
- Mutations return the smallest owner of changed state. Shell-level effects use
a documented named
HX-Triggerevent. - Preserve focusable controls and their accessible names across replacement.
- Portable components receive endpoints, targets, and IDs from callers; routes remain in the consumer application.
Query the selected catalog record with uv run stitchyard --name NAME --json
before changing an ID, target, swap mode, or response shape.
Offline asset contracts
src/stitchyard/assets.pyis the only owner of packaged browser asset URLs and route registration. UseStitchyardAssets,offline_headers,offline_footers, andregister_offline_assets; do not add parallel helpers.- Runtime routes expose a fixed allow-list. Do not accept user-provided package paths or turn the mount into a general static-file server.
- Keep vendor version constants, filenames, bytes, license notices,
vendor-manifest.jsonhashes, and asset tests synchronized. - Do not hand-edit
src/stitchyard/_static/vendor/as an ordinary application change. Vendor refreshes require provenance, license, integrity, and offline response verification. - An offline FastHTML consumer disables CDN defaults with
default_hdrs=False,htmx=False,pico=False, andsurreal=False, then installs the asset nodes and registers the mount. - Stitchyard does not bundle consumer-specific scripts or fonts. Applications own those resources and must self-host them when network independence matters.
Switchyard browser module contracts
These rules apply only to the showcase under static/ and
examples/switchyard/:
static/app.jsis the only browser entry. Imported modules must not install global listeners at import time.- Keep explicit
.jssuffixes on relative imports and make every authored module reachable from the entry. - Keep overlay/focus ownership in
overlays.js, delegated actions inactions.js, and HTMX/application events inhtmx.js; do not create a second owner for the same state. - Delegate listeners when targets can arrive in an HTMX swap. Query replaceable nodes when an action runs rather than retaining module-scope references.
- Access third-party globals through
window, includingwindow.htmxandwindow.lucide. - Preserve the actions, events, IDs, focus, Escape, Tab, and
inertcontracts indocs/browser-behaviors.md. - Mark routine polling roots with
data-background-request="true". Give interactive controls inside them stabledata-focus-keyvalues.
Responsive and accessibility rules
- The operator workflow is desktop-first, but Tailwind implementation remains
mobile-first: base behavior first, then
sm:,md:,lg:, andxl:. - Keep mobile controls at least 44px tall or wide. Reveal collection fields by priority instead of making viewport-level horizontal scrolling the primary mobile experience.
- Every icon-only action needs an accessible name and visible focus state.
- Prefer native semantics and keep custom ARIA state synchronized with visible state.
- Focus containment, restoration, Escape behavior, and
inertmanagement are interaction contracts, not optional polish. - Pair status color with text or an icon. Charts require a useful accessible name or textual summary.
- Respect reduced-motion preferences and do not announce routine polling through
aria-live.
Verification
Run the smallest relevant tests first, then the full suite. Common checks are:
uv run pytest tests/test_stitchyard_catalog.py -q
uv run pytest tests/test_stitchyard_patterns.py -q
uv run pytest tests/test_stitchyard_assets.py -q
uv run pytest -q
Run npm run build:library-css after library class or asset changes and
npm run build:css after showcase class or asset changes. For browser module
changes, run uv run pytest tests/test_browser_assets.py -q before the full
suite. Before a release, run npm run build, uv build, install the wheel into
a clean environment, and verify its public imports, catalog command, stylesheet,
and offline asset responses.