Skip to content

Releases: caramelizedev/caramel

Caramel 0.10.0

Choose a tag to compare

@edreesjalili edreesjalili released this 08 Oct 22:51

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

  • crema: show each query as a card with its SQL laid out and its binds listed (0bca849)
  • crema: light up a placeholder and its value together (7de8e5d)

Caramel 0.9.1

Choose a tag to compare

@edreesjalili edreesjalili released this 08 Oct 19:55

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

Choose a tag to compare

@edreesjalili edreesjalili released this 07 Oct 16:07

Caramel 0.9.0

0.9.0 - 2026-10-07

Upgrade notes

  • The development toolbar frappe dev adds 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, j and k move 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 localStorage for 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 $n and the copy starts with a comment saying so. The Binds column shows values as the copy writes them (42, 'acme', NULL), and a nil bind 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 repeated SELECT suggests 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

Choose a tag to compare

@edreesjalili edreesjalili released this 06 Oct 13:00

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 inbound traceparent continues the caller's trace. The application logs one canonical line per request through the crema log source, and serve and work set up logging themselves: JSON in production, text in development and test (CARAMEL_LOG_FORMAT, LOG_LEVEL). The old request_id=… error_type=… error line is gone; the error line carries error_class and fingerprint instead. Caramel::DevelopmentError.response now takes a Caramel::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 new caramel_jobs.context column (a framework migration, so run frappe migrate); and each database pool names itself in application_name. Cold Brew's worker, maintenance, scheduler and hook error lines are now error entries from the crema source. Caramel::Database::Config has an application_name. SugarORM::Repo has two private hooks, observe and observe_checkout, that caramel/crema/sql redefines. dump value is a development aid.
  • frappe dev gets 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; set CARAMEL_EDITOR) and compile errors that link to the editor. frappe traces, frappe trace REF and frappe errors read what the session kept (frappe errors lists only what happened after the newest successful build, so a rebuild clears errors it fixed); MRDP gains the codes RUNTIME and REPEATED_QUERY. frappe lint and new applications' .ameba.yml enable Caramel/Dump, which reports a leftover dump; add it to an existing application's .ameba.yml to adopt it. The development gateway's status answers latest, and Latte.app has an Open inspector item.
  • A running application opens an owner-only ops socket (ADR 0028): serve next to its application socket, work only when CARAMEL_OPS_SOCKET names a path, off to 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) and APP db diagnose (also frappe db diagnose) need only the database. Caramel::CommandLine.with_database is public for registered commands, and Crema.command adds application commands.
  • require "caramel/crema/recorder" makes an application keep per-minute counts and latency histograms in caramel_metrics, read by APP insights and the ops console. New applications require it in config/application.cr; add the line after require "caramel" to adopt it, and run frappe 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 endpoint OTEL_EXPORTER_OTLP_ENDPOINT names, with the usual OTEL_* headers, service name and sampler variables (ADR 0028). It does nothing without an endpoint. Caramel::Outbound calls carry the sampling decision in their traceparent.
  • Latte's managed PostgreSQL preloads pg_stat_statements and auto_explain (ADR 0029); the next start of an existing cluster restarts it once. Each site's development database gets pg_stat_statements in a caramel_stats schema, which frappe db diagnose reads and frappe db dump leaves out. No role is granted pg_read_all_stats, so a site's role sees statement text only for its own statements, and utility statements (such as ALTER ROLE … PASSWORD) are not tracked. auto_explain logs the text and plan of statements that take 250 ms or more to postgres.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 errors and last_error. Version 1 is still served and unchanged; Frappé, Corretto and Latte.app now ask for version 2, so run latte stop once 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's X-Request-Id. proxy.log no 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 with OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4318 and OTEL_EXPORTER_OTLP_PROTOCOL=http/json; frappe dev sends its application's traces there, and the inspector and frappe trace REF --md show what other services did in the same trace under "Across services". If another program holds port 4318, Latte keeps running and frappe services shows the collector unavailable.
  • frappe new writes an AGENTS.md that maps the application for coding agents, a CLAUDE.md that imports it, and a shorter README.md. Existing applications keep their files; copy AGENTS.md and CLAUDE.md from templates/application in the release source to adopt them.
  • The Caramel/ServiceNoun lint 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 as frappe make tenancy Account. That command adds the tenant's schema, migration, sign-up page and home page, require "caramel/tenancy" in config/application.cr, and a tenant App::Account, by: :slug do … end block in config/routes.cr. Resources generated after it belong to the tenant and live under /SLUG; frappe make resource … --central makes one every tenant shares. To make an existing populated table tenanted, follow the ADR's "Plugging in on existing data".
  • SugarORM::Catalog::ForeignKey now holds columns and references_columns arrays instead of column and references_column, so a key may span several columns. The schema document an application prints for frappe db diff is 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

Choose a tag to compare

@edreesjalili edreesjalili released this 02 Oct 11:52

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 build now 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). run and spec keep the collector, because the programs they start inherit the environment.

Fixes

  • toolchain: keep the managed toolchain when only its launchers change (d095022)
  • toolchain: build without the compiler's garbage collector (f67c5df)

Caramel 0.7.0

Choose a tag to compare

@edreesjalili edreesjalili released this 02 Oct 10:00

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 adds app/locales/en.cr, app/locales/CODE.cr and the caramel/i18n lines in config/application.cr. Resources generated after it are translated, and frappe translations lists the keys each locale still lacks. Resources generated before it keep their English text until you replace it with t. calls.
  • In an existing application, change html lang: "en" in app/views/layouts/application.cr to html lang: Caramel.language, as new applications have it. For a right-to-left locale, also add dir: locale.dir.
  • Caramel::Application::EXPIRED_FORM is removed; use Caramel::Wording.expired_form, which a catalog can translate. Caramel's other messages now come from Caramel::Wording and SugarORM::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 errors alike, 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 in Caramel::I18n.with(locale) { … }.

Breaking changes

  • core: move Caramel's messages into Wording hooks (46f8dc4)

Features

  • core: add opt-in internationalization with caramel/i18n (6f4b2fd)
  • frappe: add make locale, translations and translated resources (ad93ca8)

Caramel 0.6.1

Choose a tag to compare

@edreesjalili edreesjalili released this 01 Oct 13:05

Caramel 0.6.1

0.6.1 - 2026-10-01

Fixes

  • sugar-orm: compile each write's query once (5ff1208)
  • core: compile action egress once instead of once per action (be9b969)

Caramel 0.6.0

Choose a tag to compare

@edreesjalili edreesjalili released this 01 Oct 04:40

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 run frappe lsp install again; rebuilding crystalline can take about 20 minutes.
  • Corretto adds Blueprint-shaped have_html expectations and content blocks for render_partial. Existing matcher calls still work; render_page now requires a real doctype. See testing HTML. Lexbor 3.6.4 is a development dependency: existing applications must add it under development_dependencies and refresh shard.lock before frappe setup; generated apps include the pin. Development installs build it with cc and ar (Apple Command Line Tools on macOS or build-essential on 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_s remedy. Table rows and cells inside hx-partial envelopes 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

Choose a tag to compare

@edreesjalili edreesjalili released this 01 Oct 02:09

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

Choose a tag to compare

@edreesjalili edreesjalili released this 30 Sep 15:43

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 fetch sends the page's CSRF token as X-CSRF-Token. An application that reopened Caramel::RequestInput to parse JSON, or Caramel::Application#handle to receive a webhook, should delete the reopen: bind JSON through the contract, or declare ingress 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 raises ArgumentError outside that range. It is deprecated; pass the route's policy instead, as Caramel::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::Dispatcher must implement match(request) and dispatch(context, match). Routers from Caramel::Router.draw already do.
  • A form's _method override into a route whose ingress reads 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 initialize therefore also runs for requests that end in a route 404 or a contract failure.
  • Specs never received the development .env and still do not. Put test-only settings the application reads itself, such as WEBHOOK_SECRET, in a committed .env.test. frappe new now adds one.
  • Instead of querying caramel_jobs, read a job with Caramel::ColdBrew.status(id) and learn of retries and failures with on_retry_scheduled and on_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 dev in an existing project stops on an asset output conflict, delete the public file it names to republish it from app/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, run frappe lsp install again 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_SIZE yourself 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)