Ricochet Reference

A working reference for the current Ricochet toolchain: stack words, declaration operators, symbols, OOP, MVC, Active Record, templates, tests, and debugger behavior.

rco new --with-sqlite my_app
rco fmt app.rco
rco routes my_app
rco test my_app
rco run --debug --step app.rco
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

Copy/Paste Smoke Script

Verify your local virtual machine installation works correctly with this bootstrap class and execution sequence.

User Model Subclass
  "email" Accessor
  [ self email.get ] "displayName" Method
end

User new
"ada@example.com" swap email.set
displayName
println

Syntax And Symbols

Key lexer tokens, comment formatting, blocks, OOP declarations, HTML views, and routes.

Comments

(( Any documentation comment or note. ))

Comments are delimited with double parentheses and are ignored by compilation.

Class Declarations

User Model Subclass
  "users" Table
  "email" Accessor
end

Declaration shape stays postfix: declaration name first, declaration operator last.

Collection Declarations

users array
settings map
queue list
tags Set

Name-first collection declarations bind mutable shared collections. Use `Array new`, `Map new`, `List new`, or `Set new` for anonymous values.

Reference Prefix

"users" name var
$name array
$users "Ada" push drop
$users count println

`$name` reads an existing binding for ordinary static variable access. Keep `get` for dynamic by-name reads such as `"name" get` or `fieldName get`. Declaration words still use bare names or strings, so `$name array` reads the variable `name` and declares an array using that runtime string. Function and method locals refresh within the active call frame, while top-level declarations stay shared.

Argument Lists

( ctx -> Response ) [
  $ctx "home/index" swap view
] "index" Method

Parentheses create optional input/output metadata for functions and methods.

Blocks

[ self email.get ]

Square brackets create first-class bytecode blocks. Use `call` to execute a block value.

Conditionals

result dup ok? if
  value
else
  error "message" at
end

`if else end` is postfix: the condition is already on the stack before `if`.

Loops

count get 10 < while
  count get 1 + count set
end

The condition expression before `while` is re-executed before every iteration. `break` exits and `continue` rechecks the condition.

Members

user email.get
"ada@example.com" user email.set

Postfix selectors call methods directly. Generated accessors use `field.get` and `field.set` selectors.

Imports

"lib/math" import
7 triple

"forms/validation" import
"email" "ada@example.com" form_field
"value" at

Static string imports load relative `.rco` files before the importing file. If the relative file is missing, imports shaped like `package/module` resolve through `[dependencies.package]` in `ricochet.toml`. Dynamic imports are supported at runtime using evaluated module strings.

Templates

<strong>{ $user name.get }</strong>
<small>{ 20 22 + }</small>

Each `{ ... }` expression runs Ricochet and must leave exactly one renderable value.

Desktop Webview

state map
state get "count" 1 put drop
"Count: " state get "count" at to_string concat webview_text countText var
"Increment" "increment" webview_button button var
actions array
actions get "Increment" "increment" "increment_counter" webview_action push drop
"Counter" $countText $button concat state get actions get webview_window_state value document var

The webview globals build escaped HTML fragments and state/action document maps for desktop webview hosts.

Terminal UI

tui_enter value drop
"Hello TUI" tui_write value drop
tui_flush value drop
tui_read_key value drop
tui_leave value drop

The TUI globals drive alternate-screen terminal apps with drawing and key input.

Routes

GET "/" HomeController "index" route
POST "/users" UserController "create" route
DELETE "/users/:id" UserController "destroy" route

Route files are line-oriented and accept quoted paths and action names.

Words And Operators

Search, filter, and inspect postfix operators built into the core bytecode engine.

Filter Category:

OOP Examples

How OOP works under the hood in a concatenative environment.

Class-First Model File

Project style is one class per file, with the filename matching the class name.

(( app/Models/User.rco ))
User Model Subclass
  "users" Table
  "id" Accessor
  "email" Accessor
  "name" Accessor

  [
    self name.get nil? if
      self email.get
    else
      self name.get
    end
  ] "displayName" Method
end

Runtime Class And Accessor Names

Strings and variables can drive targeted declaration operators, which is where Ricochet starts to feel different.

"Widget" className var

className get "Object" Subclass
className get "name" Accessor

className get new
"dynamic" swap name.set
name.get

Dynamic Dispatch

Use a postfix selector for direct method calls or `send` when the method name is itself a value.

User new
"ada@example.com" swap email.set
dup displayName println
dup "displayName" send println

MVC Application Example

The default structure of a server-side web application running under Ricochet serve.

1
Route config/routes.rco
2
Controller app/Controllers
3
View app/Views
4
Model app/Models

Manifest

[package]
name = "ricochet_app"

[web]
mode = "mvc"
routes = "config/routes.rco"

[web.views]
escape = "html"

[web.static]
dir = "public"
mount = "/assets"

[web.capabilities]
fs_root = "."
env_allow = ["RICOCHET_SESSION_SECRET"]
http_allow_hosts = ["127.0.0.1"]

[web.session]
signing_secret_env = "RICOCHET_SESSION_SECRET"
encryption_secret_env = "RICOCHET_SESSION_ENCRYPTION_SECRET"

[dependencies.forms]
path = "./packages/ricochet_forms"
package = "@ricochet/forms"
version = "^0.1.0"

Routes

GET "/" HomeController "index" route
GET "/users" UserController "index" route
GET "/users/show" UserController "show" route
POST "/users" UserController "create" route
DELETE "/users/:id" UserController "destroy" route

Controller

(( app/Controllers/HomeController.rco ))
HomeController Controller Subclass
  [
    "Hello Ricochet" title var
    ctx get
    "home/index" swap view
  ] "index" Method
end

Model Used By MVC

(( app/Models/User.rco ))
User Model Subclass
  "email" Accessor
  "name" Accessor

  [
    self name.get nil? if
      self email.get
    else
      self name.get
    end
  ] "displayName" Method
end

Controller With Collection

(( app/Controllers/UserController.rco ))
UserController Controller Subclass
  [
    users array
    User new
    "ada@example.com" swap email.set
    "Ada Lovelace" swap name.set
    users get swap push drop
    users get count userCount var
    "Users" title var
    ctx get
    "users/index" swap view
  ] "index" Method
end

Redirect And Headers

LoginController Controller Subclass
  [
    "/dashboard" redirect
    303 status
    "cache-control" "no-store" header
  ] "create" Method
end

Request Context

For `POST`, `PUT`, `PATCH`, and `DELETE`, MVC parses URL-encoded forms, JSON bodies, and multipart forms. Declared action Args bind route params first, then form fields, JSON object fields, upload fields, query params, and context values. `request` includes `body`, `json`, `uploads`, and `files`; upload maps include `name`, `field`, `stream_id`, `filename`, `content_type`, `size_known`, `size`, `text`, and `data_base64`. Larger files are retained as temporary upload streams for `upload_read`, `upload_stream`, `upload_streams`, and `upload_release`.

ContextController Controller Subclass
  ( request cookies config file ) [
    file var
    config var
    cookies var
    request var
    map
    "method" request get "method" at put
    "theme" cookies get "theme" at put
    "package" config get "package" at "name" at put
    "json_name" request get "json" at "name" at put
    "upload_text" file get "text" at put
    json
  ] "show" Method
end

Session Map

SessionController Controller Subclass
  ( session ) [
    session var
    session get "user" at nil? if
      session get "user" "Ada" put drop
    end
    session get "user" at text
  ] "show" Method
end

Logger

LogController Controller Subclass
  ( logger ) [
    logger var
    "loaded" logger get info drop
    "careful" logger get warn drop
    "ok" text
  ] "index" Method
end

AI Capability

(( ricochet.toml ))
[ai.default]
provider = "openai"
model = "gpt-4.1-mini"
api_key = "${OPENAI_API_KEY}"

(( app/Controllers/AiController.rco ))
AiController Controller Subclass
  ( ai ) [
    ai var
    "Write one sentence about Ricochet" ai get chat result var
    result get ok? if
      result get value "text" at text
    else
      result get error "message" at text
    end
  ] "index" Method
end

View

<main>
  <h1>{ title get }</h1>
  <p>{ 20 22 + }</p>
</main>

Active Record Examples

Interact with Postgres schemas using simple, stack-based ORM words.

Model Mapping

(( app/Models/User.rco ))
User Model Subclass
  "users" Table
  "id" Accessor
  "email" Accessor
  "name" Accessor
end

Model Class Calls

User all
User default_page
42 User find_record
"email" "ada@example.com" User where
10 User limit
10 20 User page
"email" "asc" 10 20 User order_page
"email" "ada@example.com" 10 User where_limit
"email" "ada@example.com" 10 20 User where_page
"email" "ada@example.com" "id" "desc" 10 20 User where_order_page
User count_records
User first_record
1 User exists?
attributes map
attributes get "email" "ada@example.com" put drop
attributes get "name" "Ada" put drop
attributes get User insert

updates map
updates get "email" "grace@example.com" put drop
42 updates get User update

Controller With Stack Result Handling

(( app/Controllers/UserController.rco ))
UserController Controller Subclass
  ( ctx -> Response ) [
    User all
    dup ok? if
      value users var
      ctx get "users/index" swap view
    else
      error "message" at text
    end
  ] "index" Method
end

Result Envelope For App Boundaries

meta map
meta get "capability" "workspace.read" put drop

"payload" ok meta get result_envelope envelope var
envelope get "ok" at println
envelope get "data" at println
envelope get "meta" at "capability" at println

Loops And Computational Completeness

Mutable counters, Peano numerals, and conditional backward jumps.

Counter-Machine Multiplication

Mutable counters, conditional branching, decrement, and backward jumps provide the core WHILE-machine model. This program computes `6 * 7` without a multiplication word.

0 product var
6 multiplicand var
7 multiplier var

multiplier get 0 > while
  product get multiplicand get + product set
  multiplier get 1 - multiplier set
end

product get println

Loop Control

0 count var

count get 10 < while
  count get 1 + count set
  count get 3 = if continue end
  count get 6 = if break end
  count get println
end

Unary Counter Shape

For an abstract unbounded counter, object chains can represent Peano-style natural numbers independently of the fixed-width integer convenience type.

Counter Object Subclass
  "previous" Accessor
end

nil counter var

counter get Counter new previous.set counter set
counter get Counter new previous.set counter set
counter get nil? false = while
  counter get previous.get counter set
end

Debugging And Tests

Interactive execution traces, break-on-fault logs, and unit testing support.

Realtime Trace

Debug mode prints each instruction with stack before and after. Step mode pauses and accepts `step`, `next`, `out`, `continue`, `abort`, `stack`, `locals`, `globals`, `self`, or `tasks`; trace files record JSON debug events for tooling, `rco debug --json` streams the same event contract as JSON Lines, and `rco debug-adapter` serves standard Debug Adapter Protocol requests for IDEs.

rco run --debug app.rco
rco run --debug --step app.rco
rco run --breakpoint 12 app.rco
rco debug --json app.rco
rco debug-adapter
rco run --trace-file trace.json app.rco
rco repl --debug

Fault Shape

Runtime errors preserve the relevant stack when an operation fails loudly.

TRACE app.rco:3 [<main>] CallWord("+")
  before: [Number(20), Number(22)]
  after:  [Number(42)]
FAULT [<main>] unknown word typo
  stack:  [Number(42)]

TestCase

(( tests/UserTest.rco ))
UserTest TestCase Subclass
  [
    "Ada"
    "Ada" assert_equals
  ] "testDisplayName" Method
end

CLI Reference

Comprehensive list of commands available in the Ricochet command-line interface.

CLI Script Words

args count println
"DATABASE_URL" env_get dup ok? if value println else error "message" at eprint end
cwd value println
now println
100 random println

Numeric Conversions

1.5 2 + println
12.0 to_integer value println
12.5 to_integer error "kind" at println
255 to_unsigned_tinyint value println
"1.23456789" to_float32 value println

Date And Time

"2026-06-18T13:14:15.250Z" timestamp_parse value startedAt var
startedAt get timestamp_format value println
startedAt get "%Y-%m-%d %H:%M:%S" timestamp_format_pattern value println
startedAt get timestamp_parts value parts var
parts get "year" at println
startedAt get 2 duration_hours value timestamp_add value later var
startedAt get later get timestamp_diff value println
"2026-02-28" date_parse value date var
date get 1 date_add_days value nextDate var
nextDate get "%Y-%m-%d" date_format value println
date get nextDate get date_diff_days value println

Packages

rco publish ./packages/ricochet_forms --registry ../ricochet-registry
rco publish ./packages/ricochet_forms --registry ../ricochet-registry --provenance-file provenance.json --signature-file forms.sig --signature-kind minisign
rco registry rebuild ../ricochet-registry
rco registry check ../ricochet-registry
rco search forms --registry-url file:///E:/path/to/ricochet-registry/index.toml
rco add registry:@ricochet/forms --registry ../ricochet-registry --as forms --version "^0.1.0"
rco add registry:@ricochet/forms --registry-url file:///E:/path/to/ricochet-registry/index.toml --as forms --version "^0.1.0"
rco add github:BARKx4/ricochet_auth@v0.1.0 --no-fetch
rco install
rco verify
rco audit --json

Tasks

10 base var
[ 100 sleep base get 5 + ] spawn task var
task get task_status
task get running?
task get completed?
tasks count
task get await
task get release_task
task get task_status
handles array
handles get [ 20 2 + ] spawn push drop
handles get [ 30 4 + ] spawn push drop
handles get await_all

Capabilities

"README.md" fs_read_text value count println
"https://example.com" http_get value response var
response get "status" at println
"https://example.com" http_get_task request var
request get await value asyncResponse var
asyncResponse get "body" at println
workspaceOptions map
"README.md" workspaceOptions get workspace_read_text value readme var
"." workspaceOptions get workspace_list value workspaceEntries var
workspaceEntries get count println
settings map
provider map
provider get "api_key" "PROVIDER_API_KEY" secret_env put drop
settings get "provider" provider get put drop
path array
path get "provider" push drop
path get "api_key" push drop
settings get path get config_get value secret_resolve value token var
payload map
payload get "probe" true put drop
providerHosts array
providerHosts get "api.example" push drop
"POST" "https://api.example/v1/models" http_request_new value providerRequest var
providerRequest get token get http_bearer_auth value providerRequest set
providerRequest get payload get http_json_body value providerRequest set
providerRequest get "allowed_hosts" providerHosts get put drop
providerRequest get 30000 http_timeout value providerRequest set
providerRequest get "max_response_bytes" 1048576 put drop
providerRequest get http_request_task await value providerResponse var
providerResponse get "status" at println
processArgs array
processArgs get "status" push drop
processOptions map
processOptions get "GIT_TERMINAL_PROMPT" "0" process_env_put value processOptions set
"git" processArgs get processOptions get process_spawn value processResult var
processResult get "success" at println
processOptions get "stdout_max_bytes" 1048576 put drop
"git" processArgs get processOptions get process_start value processJob var
processReadOptions map
processJob get "id" at processReadOptions get process_read value processOutput var
processOutput get "stdout" at println
processJob get "id" at process_release value drop
runtime_capabilities "process" at "enabled" at println
approvalOperation map
approvalOperation get "capability" "workspace.write" put drop
approvalOptions map
approvalOperation get approvalOptions get approval_create value approval var
approval get "id" at approval get "token" at approval_claim value "claimed" at println
runtime_capabilities "approval" at "records" at println
"Ready" tui_write value drop tui_flush value drop

Acceptance Suite

cargo build -p ricochet_cli --bin rco
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scriptscceptance.ps1

Showcase Apps

Explore reference applications built to test the Ricochet runtime.

Repo-Local Examples

The showcase folder includes a SQLite notes MVC app, a first-party package consumer, an AI provider request probe, a GUI v2 task monitor, and a debugger demo.

rco check examples/showcase/sqlite_notes
rco run examples/showcase/package_auth_forms/main.rco
rco run examples/showcase/ai_provider_probe/main.rco
rco gui examples/showcase/gui_task_monitor.rco
rco debug --step examples/showcase/debugger_demo.rco

Known Current Limits

The bounds of the v0.1.19-rc.3 release candidate specification. Be aware of these rules in your application code.

  • Ricochet v1 is a developer beta target for building and testing usable local MVC web apps. It is not a production deployment promise.
  • `Number` values are signed `i64` integers. Decimal or exponent literals produce finite `Float` values backed by `f64`; mixed numeric math promotes to `Float`. `to_int`, `to_tinyint`, `to_unsigned_int`, `to_float32`, `to_float64`, and related conversion words provide checked range/precision boundaries. Exact decimal and money values remain future work.
  • HTTP, filesystem, environment, process, PTY, and socket access are host capabilities. The v1 beta policy keeps `--capability-profile trusted` as the local-development default and uses `--capability-profile sandboxed` for untrusted examples, package review, bug repros, and third-party code. Sandboxed starts with filesystem and HTTP disabled, then `--fs-root PATH`, `--http-allow-host HOST`, and `--env-allow NAME` can open bounded access. Raw TCP and WebSocket clients/listeners are separately opt-in with `--allow-sockets` or bounded with `--socket-allow-host HOST`, then exposed through retained `tcp_*` and `ws_*` words; accepted listener connections reuse the ordinary retained read/write/send/close/release words. Direct child process execution is always opt-in with `--allow-process`; `--process-root PATH` narrows process and PTY cwd values independently from the filesystem root. `process_spawn` captures a bounded blocking result, while `process_start`, `process_jobs`, `process_job`, `process_read`, `process_cancel`, and `process_release` provide capped retained long-running jobs. PTY sessions are separately opt-in with `--allow-pty` and expose `pty_start`, `pty_write`, `pty_read`, `pty_resize`, `pty_stop`, `pty_release`, `pty_list`, and `pty_detail`. Runtime approval records are available to local apps through `approval_create`, `approval_claim`, `approval_complete`, `approval_reject`, and `approval_detail`; MVC request VMs share the same approval registry so one-time claims work across requests. `rco serve` also keeps process environment access disabled unless `--allow-env` or `--env-allow` is passed for a trusted local MVC app. `--no-fs`, `--fs-readonly`, `--no-http`, and `--no-env` further narrow host powers. Simple HTTP calls use a 10 second timeout and a 1 MiB response body cap; retained HTTP streams are capped and can be released with `http_stream_release`; `http_request` and `http_request_task` can set bounded `timeout_ms`, `max_response_bytes`, `allowed_hosts`, and `allowed_schemes` per request. Header names and values are validated before connecting.
  • MVC request body parsing has configurable `[web.uploads]` bounds for request size, file size, memory threshold, and retained streams. Multipart uploads expose UTF-8 `text` and `data_base64` for small files when possible, plus retained stream metadata for larger files.
  • Web controller execution and template expressions have instruction budgets so runaway server code returns a fault instead of hanging a request.
  • The built-in session map uses a cookie named `ricochet_session`; configure `[web.session] signing_secret_env` to HMAC-sign it, or `[web.session] encryption_secret_env` to emit authenticated encrypted v2 cookies. `rco new --with-sqlite` includes a local beta form/session login loop; `@ricochet/auth` provides beta guard/token helpers, while production credential policy remains app/package work.
  • `rco serve --watch` is a development hot reload path. Active requests keep their runtime snapshot; new requests use the newest successfully reloaded revision, and `--debug --watch` prints reload traces with changed files. Watched MVC runtimes honor the same CLI and manifest-declared filesystem, HTTP, environment, process, and PTY capability setup as ordinary `rco serve`.
  • Static imports remain the preferred compile-time path. Dynamic runtime imports are available through `import_dynamic`, `module_get`, and `module_call`, with lock-file and manifest path checks. GitHub sources can be recorded with `--no-fetch`; fetching uses `git clone` when enabled.
  • Task values support eager `spawn`, explicit `await`/`await_all`, retained completed/failed status, explicit cleanup with `release_task`, and basic inspection with `id`, `info`, `task_status`, `pending?`, `running?`, `completed?`, `failed?`, `tasks`, and `runtime_capabilities "tasks" at`; HTTP globals also expose `http_get_task`, `http_post_json_task`, and `http_request_task` for task-returning requests. Debug pause events include task snapshots; deeper suspended-task stack inspection is supported.
  • The MVC `ai` capability supports OpenAI-compatible chat completions through `[ai.default]`; `@ricochet/ai` provides beta provider HTTP request-map helpers. Streaming and richer structured schema validation are supported.
  • Result values cannot be used directly as conditions. Use `ok?`, then `value` or `error`; use `result_envelope` when an app/API boundary needs a `{ ok, data, error, meta }` map.
  • Top-level method declarations are rejected; methods belong inside classes and use `[ body ] "name" Method`.
  • Active Record targets existing SQLite, PostgreSQL, and MySQL/MariaDB schemas in v1. SQL migrations can be applied from `db/migrations` for those adapters.
  • Template expressions must leave exactly one scalar renderable value: nil, bool, number, float, or string.