Comments
(( Any documentation comment or note. ))
Comments are delimited with double parentheses and are ignored by compilation.
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_apprco fmt app.rcorco routes my_apprco test my_apprco run --debug --step app.rcoVerify 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
Key lexer tokens, comment formatting, blocks, OOP declarations, HTML views, and routes.
(( Any documentation comment or note. ))
Comments are delimited with double parentheses and are ignored by compilation.
User Model Subclass
"users" Table
"email" Accessor
end
Declaration shape stays postfix: declaration name first, declaration operator last.
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.
"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.
( ctx -> Response ) [
$ctx "home/index" swap view
] "index" Method
Parentheses create optional input/output metadata for functions and methods.
[ self email.get ]
Square brackets create first-class bytecode blocks. Use `call` to execute a block value.
result dup ok? if
value
else
error "message" at
end
`if else end` is postfix: the condition is already on the stack before `if`.
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.
user email.get
"ada@example.com" user email.set
Postfix selectors call methods directly. Generated accessors use `field.get` and `field.set` selectors.
"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.
<strong>{ $user name.get }</strong>
<small>{ 20 22 + }</small>
Each `{ ... }` expression runs Ricochet and must leave exactly one renderable value.
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.
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.
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.
Search, filter, and inspect postfix operators built into the core bytecode engine.
How OOP works under the hood in a concatenative environment.
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
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
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
The default structure of a server-side web application running under Ricochet serve.
[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"
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
(( app/Controllers/HomeController.rco ))
HomeController Controller Subclass
[
"Hello Ricochet" title var
ctx get
"home/index" swap view
] "index" Method
end
(( 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
(( 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
LoginController Controller Subclass
[
"/dashboard" redirect
303 status
"cache-control" "no-store" header
] "create" Method
end
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
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
LogController Controller Subclass
( logger ) [
logger var
"loaded" logger get info drop
"careful" logger get warn drop
"ok" text
] "index" Method
end
(( 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
<main>
<h1>{ title get }</h1>
<p>{ 20 22 + }</p>
</main>
Interact with Postgres schemas using simple, stack-based ORM words.
(( app/Models/User.rco ))
User Model Subclass
"users" Table
"id" Accessor
"email" Accessor
"name" Accessor
end
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
(( 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
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
Mutable counters, Peano numerals, and conditional backward jumps.
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
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
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
Interactive execution traces, break-on-fault logs, and unit testing support.
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
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)]
(( tests/UserTest.rco ))
UserTest TestCase Subclass
[
"Ada"
"Ada" assert_equals
] "testDisplayName" Method
end
Comprehensive list of commands available in the Ricochet command-line interface.
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
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
"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
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
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
"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
cargo build -p ricochet_cli --bin rco
powershell.exe -NoProfile -ExecutionPolicy Bypass -File scriptscceptance.ps1
Explore reference applications built to test the Ricochet runtime.
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
The bounds of the v0.1.19-rc.3 release candidate specification. Be aware of these rules in your application code.