feature:xray
Shows the integration surface of the active product, read from the feature contracts. You see which layout slots each feature fills, what every feature exposes, and what refiners override or extend. --validate checks the features for collisions.
Example
splent feature:xray # every feature, every section
splent feature:xray splent_feature_auth # one feature
splent feature:xray --hooks # hooks only
splent feature:xray splent_feature_auth --services # one feature, services only
splent feature:xray --validate # the collision checks
Feature X-Ray — my_first_app
my_first_app (product layout)
template: base_template.html
hook: layout.anonymous_sidebar ← splent_feature_auth
hook: layout.authenticated_sidebar ← splent_feature_auth, splent_feature_profile
3 unused: layout.head, layout.scripts, layout.modals
splent_feature_notes (refined by splent_feature_notes_tags)
service: NotesService ← overridden by splent_feature_notes_tags
model: Notes ← extended by splent_feature_notes_tags
splent_feature_notes_tags (refines splent_feature_notes)
service: NotesService → NotesServiceWithTags
model: Notes + NotesTagsMixin
splent_feature_auth, splent_feature_profile, splent_feature_public — no active refinements
2 refinement(s) across 1 feature(s).
Options
| Argument / Option | Description |
|---|---|
FEATURE |
Optional. Inspect only this feature. Without it, every feature of the product. |
--services |
Service classes and their overrides. |
--templates |
Template files and their overrides. |
--models |
Model classes and their extensions. |
--routes |
Registered routes. |
--hooks |
Template hook registrations and the slots they fill. |
--commands |
CLI commands the feature contributes. |
--signals |
Signals the feature emits. |
--validate |
Run the collision checks. |
--full |
Every extension point and every unused layout slot, not only the active ones. |
Without a filter every category is shown. The filters share one setting, so only the last one given applies.
What it does
- Checks the editable contracts. For features declared without a version, read from the workspace root, it looks for stale contracts, written before the source last changed. When it finds any, it lists them and asks
Update stale contracts now?, and yes refreshes them asfeature:contract --writedoes. With no answer to read (/dev/null, an empty pipe, CI), or when the input ends first, it printsRun: splent feature:contract <feature> --writeand reads the contracts as they are. Pinned features are not checked. - Reads the features,
[tool.splent].featuresplus the list forSPLENT_ENV(devby default). A pinned entry is read from itsfeatures/<namespace>/<name>@<version>link or that exact cache snapshot, an unversioned one from the workspace root. - Prints the product layout, one section per feature, and a summary.
Product layout
The slots come from the product’s [tool.splent.layout] (base_template and hooks). Each filled slot lists the features that fill it, in load order, and the others are counted as unused (listed one by one with --full). The section shows with no filter or with --hooks.
Feature sections
| Feature | What its section lists |
|---|---|
Declares [tool.splent.contract.extensible] |
The points in use, overridden or extended by a refiner, or for hooks filled by another feature. --full adds the idle ones, marked (extensible) |
| Declares no extension points | What its contract provides |
| A refiner | What it overrides (→) or extends and adds (+) |
| Nothing to show | Collected on one line |
This is the static view of what the RefinementRegistry applies at runtime, built from each feature’s [tool.splent.refinement].
Validation
--validate checks every feature of the product and exits 1 when it finds an issue.
| # | Check | Result |
|---|---|---|
| 1 | Services | A service class in two contracts is an error, unless a refinement overrides it |
| 2 | Models | The same model class in two features is an error |
| 3 | Routes | The same route in two features is an error |
| 4 | Blueprints | The same blueprint name in two features is an error |
| 5 | Commands | A command listed twice within one feature is an error. Feature commands are namespaced (feature:<name> <cmd>), so two features never collide |
| 6 | Signals | The same signal provided by two features is an error |
| 7 | Hooks | Shared slots are counted as information, since hooks add up |
| 8 | Layout hooks | Unused layout slots are counted as information |
| 9 | Refinement targets | Every override or extension targets a point the base declares extensible, and added routes need routes = true. One check per refinement entry |
── Validation ──
✅ All 10 checks passed. (1 shared hook(s), 3 unused layout hook(s))
Each failure is one line, such as ` ❌ Model ‘User’ — collision: splent_feature_auth, splent_feature_admin, followed by
See also
feature:hooks. The hook registrations of one featurefeature:contract. Infer and update the contract- Template system. How hooks work at runtime
- Feature loading. The integration pipeline and the
RefinementRegistry - Extensibility. Extension points and refinements