feature:install
Install a feature into the active product in one interactive step — clone, register, configure, and start.
Table of contents
Usage
splent feature:install <namespace>/<feature_name> [options]
Options
| Option | Description |
|---|---|
--editable |
Clone as editable at workspace root |
--pinned |
Pin a released version from cache |
--version <tag> |
Version to pin (e.g. v1.2.3). Pinned mode only — skips version selection |
--dev |
Add to features_dev (development only) |
--prod |
Add to features_prod (production only) |
If neither --editable nor --pinned is given, the command detects whether the feature already exists at the workspace root (→ editable) or prompts you to choose.
Examples
# Interactive — asks mode + version
splent feature:install splent-io/splent_feature_nginx
# Pin a specific version, no prompts
splent feature:install splent-io/splent_feature_redis --pinned --version v1.5.6
# Editable, dev-only
splent feature:install splent-io/splent_feature_admin --editable --dev
What it does
feature:install orchestrates several existing commands into a single flow:
Pinned mode
installing redis (pinned)
version fetching available versions...
1) v1.5.6 (latest)
2) v1.5.5
3) v1.5.4
Select version [1]: 1
version selected v1.5.6
cache redis@v1.5.6 already cached
attach redis@v1.5.6
env generate + merge
docker starting redis services
redis installed.
| Step | What happens | Delegated to |
|---|---|---|
| Version selection | Fetches available tags from GitHub and presents a numbered list. Default is latest. Skipped if --version is passed. |
_get_available_versions() |
| Clone | Downloads to .splent_cache/ if not already cached. Skipped if version is already in cache. |
feature:clone |
| Dependency check | Reads [tool.splent.contract.requires].features from the feature’s pyproject.toml. If any are missing from the product, prompts to install them first (recursive). |
See Dependency resolution |
| Attach | Adds ns/feature@version to pyproject.toml, creates versioned symlink, runs pip install -e in the web container, triggers Flask reload. |
feature:attach |
| Env merge | Generates and merges .env files so new variables (ports, upstream hosts) are available. |
product:env --generate + --merge |
| Docker | Starts the feature’s own Docker services (if it has a compose file). Only the feature’s containers — the product is not restarted. | docker compose up -d |
Editable mode
installing nginx (editable)
clone nginx (editable)
add nginx
env generate + merge
docker starting nginx services
nginx installed.
| Step | What happens | Delegated to |
|---|---|---|
| Clone | git clone to workspace root (latest tag or main). Skipped if directory already exists. |
git clone |
| Dependency check | Same as pinned — reads contract, prompts for missing dependencies. | See Dependency resolution |
| Add | Adds ns/feature (no version) to pyproject.toml, creates symlink, runs pip install -e, triggers Flask reload. |
feature:add |
| Env merge | Same as pinned. | product:env |
| Docker | Same as pinned. | docker compose up -d |
Dependency resolution
After cloning a feature (but before registering it in the product), feature:install reads its contract to check for required features:
# splent_feature_notes_tags/pyproject.toml
[tool.splent.contract.requires]
features = ["notes"]
If any required features are missing from the product, the command lists them and asks whether to install them first:
notes_tags requires features not installed in my_first_app:
- notes
Install them first? [Y/n]: y
Accepting triggers a recursive feature:install for each missing dependency. If notes itself requires auth, that will be detected and resolved too — all the way down the chain.
Why the contract and not the UVL?
The UVL defines the variability model of the SPL — which features can coexist and under what constraints. But a feature being installed might not be in the UVL yet (e.g. a third-party feature, or a new feature you just created). The contract’s requires.features is declared by the feature author and is always available in its pyproject.toml, regardless of whether the feature appears in any UVL model.
What it checks
- Source:
[tool.splent.contract.requires].featuresin the feature’spyproject.toml - Compared against: all features declared in the product’s
pyproject.toml(acrossfeatures,features_dev, andfeatures_prod) - Matching: by short name (e.g.
"auth"matchessplent-io/splent_feature_authorsplent-io/splent_feature_auth@v1.5.7)
How it relates to other commands
feature:install does not replace the lower-level commands — it composes them:
| Command | Scope | When to use directly |
|---|---|---|
feature:clone |
Download to cache | When you only want to cache a version without installing |
feature:add |
Register editable | When the feature is already at workspace root and you don’t need env merge or Docker |
feature:attach |
Register pinned | When the feature is already cached and you don’t need env merge or Docker |
feature:install |
All of the above + env + Docker | Default for most installations |
Requirements
- A product must be selected (
splent product:select). SPLENT_APPandSPLENT_ENVmust be set.- For pinned mode: GitHub must be reachable (to fetch tags and clone).
- For editable mode: the repository must be accessible via SSH or HTTPS.
See also
feature:clone— clone a feature into the local cachefeature:add— register an editable feature (low-level)feature:attach— register a pinned feature (low-level)feature:remove— uninstall a feature from the product- Env placeholders —
__PRODUCT__and__FEATURE_HOST_DIR__resolved during env merge