6.3 KiB
| name | description |
|---|---|
| bliss | Drive a remote Bliss instance from the command line the way a human uses the /workshop UI — create/edit structures, routes, templates, databases, run the db REPL, read logs. Use when asked to build, inspect, or modify Bliss Structures against a running instance. |
bliss CLI
bliss talks to a running Bliss instance exactly as a human does through the
workshop UI. Reads come back as JSON from the /plumbing API (pipe into
jq). Writes go through the same /workshop/* endpoints the UI posts to.
Setup
The CLI is at bliss-cli/bliss in the repo. Configure via env vars:
export BLISS_URL=https://your-instance.example.com # default http://localhost:3000
export BLISS_USER=you
export BLISS_PASS=secret
It logs in once and caches the session cookie under ~/.bliss/, re-logging-in
automatically when it expires. Run it as node bliss-cli/bliss <command> (or
./bliss-cli/bliss if on PATH).
Instead of re-exporting BLISS_URL every time, set a sticky target once —
it persists to ~/.bliss/target and is used until you change it (a BLISS_URL
env var still overrides it when set):
bliss use https://your-instance.example.com # set the target instance
bliss use # print the current target
The model (what you're editing)
A Structure is a mini web app. It has routes (a VERB + path + a JS
handler string run in a sandbox), templates (Eta, with a test_object
used for preview), and databases (each with a library JS module and its
own SQLite file). Ids are integers. Build a structure by: create it → add a db →
write its library → add routes whose handlers call the library → add templates
the handlers render.
Templates are hypermedia, not escaped-string templates. Default to <%~ %>
(raw) over <%= %> (escaped) in Eta content — only use <%= %> inside an HTML
attribute value, where an unescaped " would break the tag. Reach for htmx
attributes (hx-trigger="every 10s", hx-swap-oob, etc.) instead of JS
setTimeout/fetch polling loops. See CLAUDE.md's "hypermedia homestead"
section for the full rationale.
Reads (JSON)
bliss structures # list all structures
bliss structure <sid> # structure + its routes, templates, dbs, files
bliss route <sid> <rid> # one route incl. its handler source
bliss template <sid> <tid> # one template incl. content + test_object
bliss db <sid> <dbid> # one db incl. its library source
bliss files <sid> # files attached to a structure
bliss logs <sid> <rid> [--since <id>] # route logs (console.log output + errors)
bliss versions <route|template|db> <sid> <id> # save history (newest first)
bliss version <versionId> # one version incl. full snapshot
All emit JSON, so: bliss structure 3 | jq '.routes[].path'.
Version history (undo trail)
Every content-changing save of a route handler, template, or db library records
an append-only snapshot. The live row is always the current version; old ones
are kept so nothing edited is ever lost. versions lists the summaries (id,
created_at, bytes) newest-first; version <id> returns the full snapshot
(the versioned fields). No-op re-saves are deduped, so identical content doesn't
pile up. There's no revert command yet — to roll back, fetch an old snapshot and
re-update-* its content:
bliss versions route 3 12 # what saves exist
bliss version 24 | jq -r .snapshot.handler > /tmp/old.js
bliss update-route 3 12 --handler-file /tmp/old.js # restore it as a new save
Writes
bliss create-structure "<name>" # -> {location, id}
bliss update-settings <sid> [--route-prefix <p>] [--head-injection <s>|--head-injection-file <f>]
bliss clone <sid> --name "<n>" --prefix /p [--clone-dbs]
bliss create-route <sid> <VERB> <path> # VERB: GET|POST|PUT|DELETE|WS ; -> {id}
bliss update-route <sid> <rid> --handler-file <f|-> # replace handler code
[--scaffold-file <f>] [--path <p>] [--verb <v>]
bliss create-template <sid> "<name>" # -> {id}
bliss update-template <sid> <tid> --content-file <f|-> [--test-object-file <f>]
bliss create-db <sid> "<name>" # -> {id}
bliss attach-db <sid> <dbid> <alias> # share an existing db under an alias
bliss update-library <sid> <dbid> --file <f|-> # returns eval output/errors
bliss repl <sid> <dbid> '<code>' # run JS/SQL against the db; --file <f|-> also works
bliss upload <sid> <path> # upload a static file
Previews
bliss preview-route <sid> <rid> # rendered HTML of a GET route
bliss preview-template <sid> <tid> # rendered HTML using the template's test_object
Links
Jump straight into the workshop editor for something instead of constructing the URL by hand:
bliss link structure <sid>
bliss link route <sid> <rid>
bliss link template <sid> <tid>
bliss link db <sid> <dbId> # by numeric db id
bliss link db <sid> <alias> # or by the alias used in require('db')(alias)
bliss link db resolves an alias (e.g. chat, as in require('db')('chat'))
by looking at the structure's attached dbs — handy since the same alias name
often points to a different db per structure (aliased/cloned dbs).
Editing code (handlers, templates, library)
Handlers/templates/library are multiline code. Write the code to a temp file and
pass --*-file, or pipe via - (stdin):
cat > /tmp/handler.js <<'EOF'
function handler(req, res) {
const { library } = require('db')('main');
res.render('home', { items: library.all() });
}
EOF
bliss update-route 3 12 --handler-file /tmp/handler.js
echo "function handler(req,res){ res.send('hi') }" | bliss update-route 3 12 --handler-file -
The db library runs with sql (the better-sqlite3 instance) in scope and sets
module.exports. Test it fast with bliss repl <sid> <dbid> 'library.someFn()'.
Typical loop
bliss structures/bliss structure <sid>to orient.- Edit a handler/template/library into a temp file, push with the matching
update-*command. bliss preview-route/bliss replto see the result;bliss logsto debug.