Web And Data

Serve Ricochet MVC projects, use hot reload, configure databases, parse requests, and work with Active Record.

docs/reference/guides/web-and-data.html
docs/wiki/web-and-data.html
Ricochet stack and MVC flow Value::String Value::Map Value::Class Value::Block bytecode VM Controller View Postgres $name "home/index" swap view [ ... ] "methodName" Method

Serve an MVC app from its project directory:

rco serve --host 127.0.0.1 --port 3000
rco serve --allow-env --http-allow-host 127.0.0.1
rco serve --env-allow OPENAI_API_KEY --http-allow-host api.openai.com
rco serve --allow-process --fs-root .
rco serve --allow-process --process-root .\scripts
rco serve --allow-pty --fs-root .
rco serve --watch
rco serve --debug
rco serve --watch --fs-root . --http-allow-host 127.0.0.1

--watch reloads Ricochet MVC routes, controllers, models, views, and the manifest between requests. If a reload fails, the request returns a clear MVC error and the next request retries after you fix the source. Combine --watch with --debug to print reload trace lines with the new revision and changed files. The same filesystem, HTTP, environment, process, and PTY capability flags used by ordinary rco serve are also honored by watched MVC runtimes and by each hot-reloaded revision.

rco serve --debug also records MVC request fault pauses. Before a controller action, view render, or response metadata failure becomes an HTTP 500 response, the server prints a FAULT request ... line with the method, path, controller/action, revision, stage, and error text.

Use rco doctor [path] for a read-only health check of a source file, source tree, package project, or MVC app. Add --capabilities to print the MVC manifest capability surface that will matter for trusted local beta apps. Package projects can also run rco verify [path] to check dependency manifest/lock consistency, local path containment, git package cache commit matches, and locked package-content integrity without fetching or rewriting anything.

rco serve keeps MVC process environment access disabled unless you pass --allow-env or one or more --env-allow NAME entries. Prefer --env-allow for trusted local beta apps that store secret references as environment variable names. --no-env keeps the default disabled behavior explicit, and conflicts with both env-opening flags.

Templates

MVC views use ordinary HTML files with Ricochet template markers. { ... } runs an expression and renders exactly one scalar value: nil, bool, number, float, or string. Values are HTML-escaped by default.

Use {% ... do %} for non-rendering setup code. Script blocks share template locals with later expressions and blocks, and they must leave no values on the stack. Use postfix {% condition if %}, {% else %}, and {% end %} for conditionals. Use {% collection "item" each %} and {% end %} to loop arrays, lists, sets, or maps; map items expose key and value.

{% "Featured users" "heading" var do %}
<h1>{ heading get }</h1>
{% show get if %}
  <ul>
    {% users get "user" each %}
      <li>{ user get "name" at }</li>
    {% end %}
  </ul>
{% else %}
  <p>No users</p>
{% end %}

Template directives are compiled only by the template renderer; do, if, else, each, and end in {% ... %} are not new global VM words. Template markers are rejected inside HTML attributes, <script>, and <style> so untrusted view data stays in text context.

SQLite Scaffold

For a zero-service local beta app, rco new --with-sqlite my_beta_app creates db/development.sqlite3, seeds users, configures Active Record, and adds /login, /me, and /logout routes that exercise form params and the session cookie. The manifest shape is:

[database.default]
adapter = "sqlite"
url = "db/development.sqlite3"

For production credential flows, import @ricochet/auth and validate credentials before storing password hashes. The core password_hash and password_verify words use Argon2id PHC-format hashes; the auth package wraps them with credential normalization, length/common-password checks, and a generic auth_credentials_verify result map for login paths.

"auth/session" import

"Ada@Example.COM" "Long unique passphrase 2026" auth_password_hash value hash var
" ada@example.com " "Long unique passphrase 2026" "ada@example.com" $hash auth_credentials_verify

PostgreSQL

For a Postgres-backed app, use the same manifest shape with a Postgres URL:

[database.default]
adapter = "postgres"
url = "${DATABASE_URL}" # use sslmode=require for remote databases

Ricochet requires TLS for remote Postgres connections. sslmode=disable is accepted only for localhost or loopback development databases.

MySQL And MariaDB

For a MySQL or MariaDB-backed app, use the MySQL adapter with a mysql:// URL:

[database.default]
adapter = "mysql"
url = "${MYSQL_URL}"

Active Record maps model declarations to existing tables, and rco migrate applies ordered SQL or Ricochet DSL migrations from db/migrations while recording applied versions in schema_migrations.

Migrations And Seeds

Use rco migrate new NAME [path] to create an apply-only SQL migration, or rco migrate new NAME --dsl [path] to create paired Ricochet migration DSL files. Use rco migrate status [path] to list ordered migration files and rco migrate apply [path] to apply pending SQL or DSL. Existing VERSION_name.sql files remain compatible. For reversible migrations, use paired SQL or DSL files such as VERSION_name.up.sql, VERSION_name.down.sql, VERSION_name.up.rco, and VERSION_name.down.rco.

rco migrate status
rco migrate new create_notes --dsl
rco migrate apply
rco migrate rollback --steps 1
rco migrate dump --output db/schema.sql
rco seed

Migration DSL files are compiled only by the migration command; the DSL words are not global runtime words. The DSL stays postfix and covers safe table, column, index, and string-literal default operations:

"notes" table_create
"id" "integer" column primary_key
"body" "text" column not_null
"status" "text" column not_null "writer's draft" default

"notes" "archived_at" "text" column_add
"notes" "archived_at" "archived_on" column_rename
"idx_notes_status" "notes" "status" index_create
"uq_notes_body" "notes" "body" unique_index_create

Rollback DSL uses the same postfix shape:

"idx_notes_status" "notes" index_drop
"uq_notes_body" "notes" index_drop
"notes" "archived_on" column_drop
"notes" table_drop

rco migrate rollback [path] --steps N rolls back applied SQLite, PostgreSQL, and MySQL/MariaDB migrations newest-first and fails loudly when a migration has no matching down SQL or DSL file. MySQL and MariaDB DDL can auto-commit depending on the statement; Ricochet records the migration as rolled back only after the down migration succeeds.

rco migrate dump [path] --output db/schema.sql writes a deterministic beta DDL snapshot for SQLite, PostgreSQL, and MySQL/MariaDB user objects. The dump excludes schema_migrations and adapter-internal objects where applicable. It is not a byte-for-byte replacement for pg_dump or mysqldump.

rco seed [path] runs db/seeds/*.sql and db/seeds/*.rco in filename order for SQLite, PostgreSQL, and MySQL/MariaDB projects. Ricochet seed files load project models and receive the db capability. Seeds are not tracked, so non-idempotent seed files run again on every invocation. Raw MySQL migration batches do not support DELIMITER routine-body syntax in this beta path.

Request Data

MVC actions parse application/x-www-form-urlencoded, application/json, and multipart/form-data request bodies for POST, PUT, PATCH, and DELETE. Declared action Args bind route params first, then form fields, JSON object fields, upload fields, query params, and finally context values. The same data is available through $ctx "request" at: form holds text fields, json and body hold parsed JSON values, uploads is keyed by multipart file field name, and files contains every uploaded file. Upload values include name, field, stream_id, filename, content_type, size_known, size, text for small UTF-8 bytes, and data_base64 for small arbitrary file bytes. Larger files are retained as temporary upload streams and can be consumed with upload_read, inspected with upload_stream, listed with upload_streams, and released with upload_release. Configure [web.uploads] bounds with max_request_bytes, max_file_bytes, memory_threshold_bytes, and max_retained_streams.