Repository navigation
Releases: Particle-Academy/charlotte
Release list
v0.3.0
Fixes from Charlotte's first paid lab run (flabs runs 146-149, 2026-10-30,
claude-sonnet-5, 4096 output tokens per call): all four builds ended without
a finished page. Regression tests replay the recorded evidence
(tests/Feature/LabRunRegressionTest.php, tests/fixtures/lab-run-147-cms-apply.json).
BREAKING (behaviour, small): a turn that keeps stopping at the output limit
before the page is ready now ends run.failed with code output_limit and
session status failed, where 0.2.0 recorded run.finished and went idle.
What to do: if your host treats only idle as "the agent stopped
normally", nothing; an output_limit failure was already an unfinished page.
If you branch on run.failed codes, add output_limit. Set
charlotte.max_continuations to 0 to fail on the first cut-off instead.
Fixed
- A response cut off at the output limit no longer ends the turn with
nothing built. When a run finishes withlengthbefore the page is ready
(nocms_finishat the current revision) and nobody asked to stop, Charlotte
continues the turn with a short host message
(TurnRunner::CONTINUATION), up tocharlotte.max_continuationstimes
(default 3), on the SAME host run context, so a host's step and cost caps
bound the whole turn. Each continuation is its own run:run.finished
(finishReason: "length"), thenrun.startedcarrying the new field
continues(the previous run's id). In run 146 the model spent 3,962 of its
4,096 output tokens on adaptive thinking, emitted no tool call, and the
session went idle unfinished; runs 148 and 149 ended the same way. cms_apply(and every tool) argument errors now name the field. An
invalid_requesterror reads
{index: null, path: "$.arguments.<field>", expected, got, hint}instead of
a bare$.arguments. Whenopsarrives as a string that is not valid JSON,
gotsays so and counts the unclosed or extra braces and brackets. In run
147, 8 of 20cms_applycalls sentopsas a string; every one was invalid
JSON with one unclosed{, and with nothing naming it the model resent the
same broken heading six more times.
Changed
cms_applyacceptsopssent as a string holding a VALID JSON array of ops.
The decoded ops go through the same fancy-cms validation as an array. Strings
that are not valid JSON are never repaired, because where a missing brace
belongs is a guess. Theopsparameter description now says "a JSON array
of op objects (not a string)".
v0.2.0
Nothing to migrate. Both changes come from the first real consumer (the
fancy-labs website-builder lab). A host that binds nothing new runs exactly as
on 0.1.0; no public signature lost or changed a parameter.
Added
- An optional per-turn run context for hosts that meter spend:
Charlotte::contextUsing(fn (Turn $turn): ?RunContext => ...), or bind a
Charlotte\Runtime\TurnContextFactory. Each turn's prism-harness
RunContext(budget, pricing, cost observer) can now come from the host
without rebuildingTurnDispatcher,TurnRunnerorAgentRuntime. The
default,Runtime\HarnessDefaults, returnsnull, which keeps the harness's
own configuration; billing stays optional. A factory that throws refuses the
turn before any provider call, asrun.failedwith the exception's
HasErrorCode::code()(elserun_failed). See "Host budgets" in the README. TurnRunnertakes the factory as an optional sixth constructor argument,
defaulting toHarnessDefaults, so a host constructing it with five
arguments keeps working.
Fixed
- Optional usage telemetry no longer resolves host dependencies for
generations that are not Charlotte's. Prism firesGenerationCompletedfor
every generation in the app, and the listener built aWorkspace(and so the
host'sPageRepository,AssetCatalogueandLinkPolicybindings) before
checkingcharlotte.telemetry.enabledor the session key. A host binding
scoped to a builder turn therefore threw into unrelated agent roles, even
with Charlotte's telemetry off. The flag and the session are now checked
first and the workspace is resolved lazily, only for Charlotte's own
sessions; a failure resolving it is swallowed like any other telemetry
failure.UsageTelemetry's constructor now also accepts a
Closure(): Workspace(aWorkspacestill works).
v0.1.0
First release. Nothing to migrate: install, publish the config, run the
migrations, and register an authorization hook and a tenant resolver. Without
a hook every route is refused, by design.
Added
- Sessions on prism-harness in a
charlotte_buildermode, with the provider
and model taken from configuration (any Prism provider) and overridable per
session. Turns run on the queue (Charlotte\Laravel\RunTurn), never inside
an HTTP request, one at a time per session. - Nine page tools over a fancy-cms PageSession, extracted from the flabs Sites
lab with the same names and argument bounds:cms_describe,cms_icons,
cms_assets,cms_get,cms_apply,cms_changes_since,cms_finish, plus
the newcharlotte_briefandcms_check. - Drafts: Charlotte edits a draft only.
CharlotteSession::publish()is the one
way to publish, and no tool reaches it. - Autonomy, a dev setting (
charlotte.autonomy) overridable per session:
fullapplies edits to the draft at once;approve_on_savecollects them in
a change set that a person approves (saved to the draft) or rejects. A change
set that no longer applies resolvesconflictedand writes nothing. - A structured brief (
Brief::fromArray) and code-derived checks:
missing_required_fact,unsupported_claim, and the lab's PageChecks
(heading outline, alt text, contrast, link targets, placeholders, meta),
plus page facts for UIs and a host link allowlist. - A versioned, overridable guide: fancy-cms's authoring guide plus
agent-guide/charlotte.md. Overrides are hashed; each session records the
guide hash, and a run whose builder mode does not embed the current guide is
refused withguide_mode_stale. - The event log (envelope v1,
resources/schema/events.v1.json), written in
the same transaction as each mutation, with gap-free per-session cursors and
a long-poll reader.docs/events.mddocuments the contract. - A framework-agnostic
Charlotte\Http\Apiand a thin optional Laravel
controller kit (Charlotte::routes()), behind a dev-supplied authorization
hook (default: deny all) and a host tenant resolver. - Optional usage telemetry through Prism's own telemetry events: feature
detected, off by default,costUsd: nullwhen unpriced, never a refusal. - Security: no
richtextfor any actor, host-catalogue image handles only,
agent links allowlisted, error codes instead of provider messages. docs/fetch-chat.html, a complete chat on plainfetch.