Repository navigation
Releases: caramelizedev/caramel
Releases · caramelizedev/caramel
Release list
Caramel 0.10.0
Caramel 0.10.0
0.10.0 - 2026-10-08
Upgrade notes
- The inspector's request page shows each query as a card instead of a table row: the statement with one clause per line and coloured, and each bind listed beside its
$n. Pointing at a placeholder or a bind lights up both. Copy SQL and Copy with values write the statement as it ran, as before.
Features
Caramel 0.9.1
Caramel 0.9.1
0.9.1 - 2026-10-08
Fixes
- latte: let the latte-daemon check run the collector on a free port (b76b1f7)
- core: report a missing or unreachable database in one line (f0552b2)
- frappe: resolve an error outside a trace in frappe trace (ae30d7d)
- latte: start PostgreSQL after a crash left a stale postmaster.pid (96a0a7d)
- core: reserve the catalog key finalize (b706350)
- latte: replace DNS and proxy processes an earlier toolchain started (c2d9844)
Caramel 0.9.0
Caramel 0.9.0
0.9.0 - 2026-10-07
Upgrade notes
- The development toolbar
frappe devadds to each page is redesigned: the route, status, time and query count read as separate parts and link to their place on the request's page in the inspector, flags (error,slow,repeated queries) are words, the recent-requests list opens above the bar and closes on Esc or a click outside, a count shows new requests, and it can be minimised to a dot.`opens the list,jandkmove through it, and Copy for an agent puts the request, its queries with their binds and its backtrace on the clipboard as Markdown. - The inspector and the toolbar follow the system's light or dark appearance and share a Theme: auto / light / dark button's choice, which is kept in
localStoragefor the site. The production ops console follows the system appearance too, with its own button and its own stored choice, because it is served from another origin. - The inspector's request page shows spans in recorded order, with those inside a view indented and coloured by kind, a time scale, and links from each query to its row. Each query has Copy SQL and Copy with values, which writes the bind values into the statement as PostgreSQL literals, ready for psql; a query keeps its first 20 binds, and a literal over 2,000 bytes (the value with its quotes) is not kept for copying; those placeholders stay as
$nand the copy starts with a comment saying so. The Binds column shows values as the copy writes them (42,'acme',NULL), and anilbind is no longer recorded as"". The toolbar's links always land on a section: an empty one says nothing was recorded. Repeated queries are highlighted with their source, and a repeatedSELECTsuggests a preload; an error lists your backtrace frames with editor links.
Features
- frappe: redesign the development toolbar (4645853)
- frappe: add light and dark themes to the development toolbar and inspector (c63943b)
- frappe: copy a query with its values, link the toolbar to the trace, theme the console (5f6ae00)
Fixes
- frappe: style the development toolbar's link so it reads on the dark badge (a2a6c71)
- crema: refuse ops flags that were silently ignored (7765a13)
- frappe: copy queries with typed literals, harden the toolbar's keys and copy, guard trace.md (1012d4d)
- crema: show a nil bind as NULL on the error page (5f918f2)
- crema: copy E-strings correctly, keep every toolbar link on a section, show binds as copied, share one palette (5d56216)
- crema: leave a placeholder inside an identifier alone (fb38c3c)
- crema: act on the review of the copy follow-ups (30d1368)
Caramel 0.8.0
Caramel 0.8.0
0.8.0 - 2026-10-06
Upgrade notes
- Crema, Caramel's observability (ADR 0027), traces every routed request. Each response carries
X-Request-ID, and a valid inboundtraceparentcontinues the caller's trace. The application logs one canonical line per request through thecremalog source, andserveandworkset up logging themselves: JSON in production, text in development and test (CARAMEL_LOG_FORMAT,LOG_LEVEL). The oldrequest_id=… error_type=…error line is gone; theerrorline carrieserror_classandfingerprintinstead.Caramel::DevelopmentError.responsenow takes aCaramel::Crema::ErrorReport. - Crema times every SQL statement, job, schedule run, outbound call, view render and cache read inside a trace. Statements start with a comment such as
/*action='App%3A%3ABooks%3A%3AShow'*/; a job continues the trace of the request that enqueued it through the newcaramel_jobs.contextcolumn (a framework migration, so runfrappe migrate); and each database pool names itself inapplication_name. Cold Brew's worker, maintenance, scheduler and hook error lines are nowerrorentries from thecremasource.Caramel::Database::Confighas anapplication_name.SugarORM::Repohas two private hooks,observeandobserve_checkout, thatcaramel/crema/sqlredefines.dump valueis a development aid. frappe devgets an inspector at/__caramel/dev/inspector, a toolbar on each page, richer error pages (editor links, the source, the request, queries and Copy as Markdown; setCARAMEL_EDITOR) and compile errors that link to the editor.frappe traces,frappe trace REFandfrappe errorsread what the session kept (frappe errorslists only what happened after the newest successful build, so a rebuild clears errors it fixed); MRDP gains the codesRUNTIMEandREPEATED_QUERY.frappe lintand new applications'.ameba.ymlenableCaramel/Dump, which reports a leftoverdump; add it to an existing application's.ameba.ymlto adopt it. The development gateway's status answerslatest, andLatte.apphas an Open inspector item.- A running application opens an owner-only ops socket (ADR 0028):
servenext to its application socket,workonly whenCARAMEL_OPS_SOCKETnames a path,offto disable. The binary is its own client:ops status|requests|fibers|metrics|tail|errors|error|traces|trace|debug-token|console. It serves Prometheus text, a read-only console, in-memory rings of errors (with redacted messages) and of failed, slow and debug traces, and signed debug tokens that record one person's requests.APP jobs(stats, failed, show, retry) andAPP db diagnose(alsofrappe db diagnose) need only the database.Caramel::CommandLine.with_databaseis public for registered commands, andCrema.commandadds application commands. require "caramel/crema/recorder"makes an application keep per-minute counts and latency histograms incaramel_metrics, read byAPP insightsand the ops console. New applications require it inconfig/application.cr; add the line afterrequire "caramel"to adopt it, and runfrappe migrate(a new framework migration creates the table). It stores aggregates only: route templates and parameterized SQL, never paths, bind values or messages.require "caramel/crema/otlp"exports traces as OTLP/HTTP JSON to the endpointOTEL_EXPORTER_OTLP_ENDPOINTnames, with the usualOTEL_*headers, service name and sampler variables (ADR 0028). It does nothing without an endpoint.Caramel::Outboundcalls carry the sampling decision in theirtraceparent.- Latte's managed PostgreSQL preloads
pg_stat_statementsandauto_explain(ADR 0029); the next start of an existing cluster restarts it once. Each site's development database getspg_stat_statementsin acaramel_statsschema, whichfrappe db diagnosereads andfrappe db dumpleaves out. No role is grantedpg_read_all_stats, so a site's role sees statement text only for its own statements, and utility statements (such asALTER ROLE … PASSWORD) are not tracked.auto_explainlogs the text and plan of statements that take 250 ms or more topostgres.log; application statements carry placeholders, and no bind values are logged. The spec database is unchanged. - Latte's control API gains version 2 (ADR 0029): a site lists its development session's
errorsandlast_error. Version 1 is still served and unchanged; Frappé, Corretto and Latte.app now ask for version 2, so runlatte stoponce after upgrading so the next command starts the new Latte. Latte.app shows error counts, counts new alerts beside its icon and posts macOS notifications for build failures and new errors; it opens the inspector from a site's menu. - Latte's proxy writes a per-site access log to the site's log directory, and
frappe logs access [--follow]prints it (ADR 0029). Each line carries the application'sX-Request-Id.proxy.logno longer carries access lines. The daemon restarts the proxy's configuration on its next reconcile, so no action is needed. - Latte runs a local trace collector on
127.0.0.1:4318(ADR 0029). Point any service at it withOTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318andOTEL_EXPORTER_OTLP_PROTOCOL=http/json;frappe devsends its application's traces there, and the inspector andfrappe trace REF --mdshow what other services did in the same trace under "Across services". If another program holds port 4318, Latte keeps running andfrappe servicesshows the collector unavailable. frappe newwrites anAGENTS.mdthat maps the application for coding agents, aCLAUDE.mdthat imports it, and a shorterREADME.md. Existing applications keep their files; copyAGENTS.mdandCLAUDE.mdfromtemplates/applicationin the release source to adopt them.- The
Caramel/ServiceNounlint message and description no longer cite the design RFC. The rule is unchanged. - The release source no longer ships the design RFC, the research notes or the separate testing, views and editor-tools guides. The notes are in caramel-notes, and the guides are on the website.
- An application can be multi-tenant (ADR 0025). Nothing changes until it runs
frappe make tenancy MODEL, such asfrappe make tenancy Account. That command adds the tenant's schema, migration, sign-up page and home page,require "caramel/tenancy"inconfig/application.cr, and atenant App::Account, by: :slug do … endblock inconfig/routes.cr. Resources generated after it belong to the tenant and live under/SLUG;frappe make resource … --centralmakes one every tenant shares. To make an existing populated table tenanted, follow the ADR's "Plugging in on existing data". SugarORM::Catalog::ForeignKeynow holdscolumnsandreferences_columnsarrays instead ofcolumnandreferences_column, so a key may span several columns. The schema document an application prints forfrappe db diffis now version 2: upgrade the application's Caramel and Frappé together.
Breaking changes
- sugar_orm: support multi-column foreign keys (bc8ffb0)
Features
- core: add opt-in multi-tenancy with caramel/tenancy (0d7ea4a)
- frappe: add make tenancy and tenant resources (76dfef8)
- frappe: give new applications AGENTS.md and a short README (3074d5a)
- crema: trace requests with request ids, traceparent and wide log lines (7a271cd)
- crema: instrument SQL, jobs, schedules, outbound calls, cache and views (5343a1b)
- frappe: add the development inspector, toolbar and richer error pages (fd8090e)
- crema: add the ops socket, console and production commands (5c458d7)
- crema: add the opt-in Postgres recorder (4ca9978)
- crema: add the opt-in OTLP trace exporter (6e05b8c)
- latte: collect query statistics in the managed PostgreSQL (7ddbcd8)
- latte: show error badges and notifications through control API v2 (938f4fe)
- latte: write per-site access logs (ea9d9b0)
- latte: collect local traces across sites (8fb4dd8)
Fixes
- sugar_orm: drop undeclared foreign keys before column drops (cf0f186)
- core: match only tenant routes in a tenant, even for an empty block (dcbea8f)
- frappe: check tenant names' length and refuse a missing anchored file (7384b6d)
- crema: act on review findings: no log text, paths or statements in production surfaces (5822a1b)
- latte: narrow the collector's rescue and prove the statistics grant is gone (ed9d6af)
- latte: answer 400 to a collector body that is not an object (b3dab3d)
Caramel 0.7.1
Caramel 0.7.1
0.7.1 - 2026-10-02
Upgrade notes
- A Caramel release that changes only its compiler and Shards launchers (
scripts/crystal,scripts/shards) no longer installs a new managed toolchain. Installing it reuses your toolchain when its pinned tools match, including the one 0.7.0 installed, and writes the release's launchers into it, so compiler caches and editor tools survive the upgrade (ADR 0015 §2). scripts/crystal buildnow runs the compiler without garbage collection (GC_DONT_GC=1). A warm 22-resource dev build is about 0.7 s faster, and each compile peaks about 125 MiB higher (about 1.35 GB at 22 resources).runandspeckeep the collector, because the programs they start inherit the environment.
Fixes
Caramel 0.7.0
Caramel 0.7.0
0.7.0 - 2026-10-02
Upgrade notes
- Caramel can translate an application (ADR 0024). Nothing changes until it runs
frappe make locale CODE. That command addsapp/locales/en.cr,app/locales/CODE.crand thecaramel/i18nlines inconfig/application.cr. Resources generated after it are translated, andfrappe translationslists the keys each locale still lacks. Resources generated before it keep their English text until you replace it witht.calls. - In an existing application, change
html lang: "en"inapp/views/layouts/application.crtohtml lang: Caramel.language, as new applications have it. For a right-to-left locale, also adddir: locale.dir. Caramel::Application::EXPIRED_FORMis removed; useCaramel::Wording.expired_form, which a catalog can translate. Caramel's other messages now come fromCaramel::WordingandSugarORM::Wording, with the same English text as before.- In a translated application, contract and changeset errors are in the request's locale, in pages and in JSON
errorsalike, and so is the router's 404 body (caramel.pages.not_found). A changeset built outside a request, such as in a Cold Brew job, uses the default locale unless the job wraps its work inCaramel::I18n.with(locale) { … }.
Breaking changes
- core: move Caramel's messages into Wording hooks (46f8dc4)
Features
Caramel 0.6.1
Caramel 0.6.0
Caramel 0.6.0
0.6.0 - 2026-10-01
Upgrade notes
- Installing this release creates a new managed toolchain directory because its compiler and
Shards launchers changed. The first builds start with an empty compiler cache. Editor users
must runfrappe lsp installagain; rebuilding crystalline can take about 20 minutes. - Corretto adds Blueprint-shaped
have_htmlexpectations and content blocks forrender_partial. Existing matcher calls still work;render_pagenow requires a real doctype. See testing HTML. Lexbor 3.6.4 is a development dependency: existing applications must add it underdevelopment_dependenciesand refreshshard.lockbeforefrappe setup; generated apps include the pin. Development installs build it withccandar(Apple Command Line Tools on macOS orbuild-essentialon Debian/Ubuntu). Production installs omit the parser entirely. - HTML expectations check numeric leaf values, accept conditional nested class arrays, and join direct text across comments. Unsupported leaf values raise with a
.to_sremedy. Table rows and cells insidehx-partialenvelopes use htmx's template parsing context. The production case inventory records the regression coverage and functional authoring exercises.
Features
- corretto: add Blueprint-shaped HTML expectations (8decb18)
Fixes
- corretto: cover production HTML and authoring edge cases (5fd7b51)
Caramel 0.5.1
Caramel 0.5.1
0.5.1 - 2026-09-30
Fixes
- latte: let only exact matches make a service adoption ambiguous (71c3916)
Caramel 0.5.0
Caramel 0.5.0
0.5.0 - 2026-09-30
Upgrade notes
- Routes now bind a JSON object where they answered 415 (ADR 0020). Each member must have its field's JSON type, and same-origin
fetchsends the page's CSRF token asX-CSRF-Token. An application that reopenedCaramel::RequestInputto parse JSON, orCaramel::Application#handleto receive a webhook, should delete the reopen: bind JSON through the contract, or declareingress body: :raw, limit: 256.kilobytes, csrf: false, authenticate: :signed?on the webhook's action. Caramel::RequestInput.read(request, max_form_bytes: n)still works for 1 byte to 64 MiB, and raisesArgumentErroroutside that range. It is deprecated; pass the route's policy instead, asCaramel::RequestInput.read(request, Caramel::Ingress.new(limit: n)). A body that is neither a form nor a JSON object now answers 415 with "Expected a URL-encoded form, multipart form or JSON object".- A custom
Caramel::Router::Dispatchermust implementmatch(request)anddispatch(context, match). Routers fromCaramel::Router.drawalready do. - A form's
_methodoverride into a route whoseingressreads the body differently (another body, limit or CSRF setting) answers 405: that route is reached with its real method. - The router now builds the action before its contract binds, so that an authenticator can run first. An action's own
initializetherefore also runs for requests that end in a route 404 or a contract failure. - Specs never received the development
.envand still do not. Put test-only settings the application reads itself, such asWEBHOOK_SECRET, in a committed.env.test.frappe newnow adds one. - Instead of querying
caramel_jobs, read a job withCaramel::ColdBrew.status(id)and learn of retries and failures withon_retry_scheduledandon_failed(ADR 0019). Jobs run at least once, so a job that calls another service should send it a stable identifier to deduplicate. - To run workers without a web server, start the application binary with
work, optionally with--queues=,--concurrency=and--no-scheduler. - If
frappe devin an existing project stops on an asset output conflict, delete the public file it names to republish it fromapp/assets. scripts/crystal, the compiler launcher, changed, so installing this release sets up a new toolchain directory and its first builds start with an empty compiler cache. If you use the editor tools, runfrappe lsp installagain after installing; rebuilding crystalline takes up to about 20 minutes. In the first editor session afterwards, go to definition into Crystal's standard library can find nothing until you save the file once.- Each compile now starts with a 1 GB heap, which uses about 250 MB more memory per compiler and saves most of its early garbage collections. Set
GC_INITIAL_HEAP_SIZEyourself to choose another size.
Features
- frappe: give specs the application's test settings from .env.test (cb7c730)
- core: run Cold Brew without HTTP with the work command (e0c83d2)
- core: report job status and call hooks after a failure is written (788b26c)
- core: let an action declare how its route reads the request (7740df1)
- core: send JSON, uploads and raw bodies from Corretto's client (3c8a9c1)
- frappe: mark URL resource fields with :url (0283a82)
- core: answer errors found after the contract with render_errors (2119c5d)
- frappe: generate only the resource actions --only names (ace706e)
Fixes
- frappe: forward bodiless responses through the dev gateway (8a29a35)
- core: treat a closed stream as a disconnect, not an error (986c29b)
- frappe: record the assets a new project publishes (c918e2f)
- release: skip the migration probes when nothing they compile changed (f9cedf9)
- core: hold every ingress to the authenticator it names (b1f72b1)
- checks: verify the session's compiler and keep the lint proofs strict (8e17b8b)
- frappe: load the saved row in a request spec only when a check reads it (f82fe02)
- core: refuse a subtype ingress that drops its parent's authenticator (9fcafe0)
- frappe: run frappe dev's build for commands over the same sources (831971c)
- corretto: keep each worker's spec binary while its inputs are unchanged (58135a2)
- corretto: build spec binaries while the application migrates (b4f4fae)
- core: let crystal tool expand read the work command's options (e10b6dc)
- core: let frappe expand parse the work command's options again (551b9dc)
- frappe: make the dev build's semantic phase its Tier-1 type check (93365c6)
- toolchain: start the compiler with a 1 GB heap (e7d8ee6)
- toolchain: skip scripts/crystal's metadata rewrite when nothing changed (7b54d5a)
- toolchain: give each checkout program its own compiler cache root (ccaa191)