Build a feature with Claude Code
In Tutorial 3 you built a feature by hand. Here you’ll build the same kind of feature by describing it — the Claude Code plugin does the scaffolding, writes the code and tests, wires it into the SPL and product, migrates, and verifies.
Table of contents
Prerequisites
- The Claude Code plugin installed — see Claude Code → Installation.
- A product to build into (e.g.
my_first_appfrom Tutorial 1) with the SPLENT CLI container running.
Step 1 — Describe what you want
You don’t type CLI commands. In Claude Code, just say what the feature is:
add a notes feature with title and body, owned by the user
Claude recognises this as SPLENT feature work and runs the feature skill. It
infers a name (splent_feature_notes), an archetype (full, because it has a
model), and that “owned by the user” means a foreign key to the auth user
table — so it depends on auth.
Step 2 — What Claude does
The skill drives the CLI end-to-end, writing real code at each step:
# scaffold the package
splent feature:create splent-io/splent_feature_notes --type full
# write idiomatic code (Claude does this, following the conventions):
# models.py Notes(id, title, body, user_id → user.id, created_at)
# repositories.py list_for_user / get_for_user (BaseRepository)
# services.py create_for_user / list_for_user / delete_for_user (BaseService)
# routes.py @login_required /notes (resolved via service_proxy)
# forms.py, templates/notes/index.html, hooks.py (sidebar), seeders.py
# tests/unit, tests/integration, tests/functional
# infer the contract (run with a product selected)
splent feature:contract splent_feature_notes --write
# add to the SPL — dependency constraints are auto-detected
splent spl:add-feature sample_splent_spl splent_feature_notes # → notes => auth
# install into the product
splent product:select my_first_app
splent feature:add splent-io/splent_feature_notes
# migrate
splent db:migrate splent_feature_notes
splent db:upgrade
Claude follows two rules throughout: the CLI owns the mechanics (it never hand-edits pyproject feature lists, the
.uvlmodel, or migration tables), and you own the logic (models, services, routes, templates, tests).
Step 3 — Verify
splent feature:test splent_feature_notes
# unit ... 3 passed integration ... 2 passed functional ... 2 passed
splent feature:xray --validate # hooks/extension wiring OK
splent product:validate # UVL satisfiable, contracts compatible, imports OK
splent product:routes | grep notes
# /notes GET/POST splent_feature_notes notes.index
# /notes/<int:note_id>/delete POST splent_feature_notes notes.delete
Open the app, log in, and you’ll find a Notes link in the sidebar; /notes
lists the current user’s notes and lets them add and delete their own.
When the app won’t boot
If product:derive fails with ValueError: Unrecognized value for
SESSION_TYPE: null, the product has no session backend selected. Ask Claude:
/splent:doctor the app won't start, SESSION_TYPE is null
The doctor skill diagnoses it and adds a session feature
(splent_feature_session_filesystem or _redis) to the SPL and product, then
re-derives.
What you end up with
A complete, tested feature — splent_feature_notes — added to the SPL with a
notes => auth constraint, installed and migrated into your product, and
serving a login-protected /notes page. The same result as
Tutorial 3, reached by describing the feature instead of
writing every file.
Tips
- Prefer describing intent; the right skill (
feature,product,doctor) triggers automatically. See the Skills reference. - Review the diff like any change — Claude writes idiomatic SPLENT code, but it’s your feature.