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 for help.
/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.