Changelog
Unreleased
- gateway: a first message no domain claims no longer locks the chat to the first domain. The router held a chat in its domain as soon as the session had a draft, and the step engine creates an empty draft (
steps: {}) on the first turn of every domain, sohello there(no keyword hit, the first domain answered) kept every later message there, a ticket opener included. ADR-0001 says sticky means never re-route mid-journey or after completion; now the chat is held when it finished, when a link decided its domain (session.domainDecided), or when the journey has begun (something gathered, a step with state, the summary or a review up:route-lock.ts). A chat that only fell back is classified again, with the active domain's stickiness bias, and its empty draft is dropped when it moves. evals: the bookings suite gainsgreeting-then-opener(red onmain) andsticky-mid-journey(the lock the fix keeps). - gateway, core: the dev trace. With
AGENT_DEV_TRACE=true(default off;.env.examplesets it,render.yamland.env.production.exampleleave it off) every turn carries what the gateway already logged, as a client payload: the route decision (the domain, the link that decided —keywords,systemone,llm,sticky,single,fallback— and its confidence), the step engine's events (drawn,late_draw,redrawn,reopened,settled,skipped,summary), every tool call with the arguments it received (after the carry rule) and its result (masked, clipped), and each model call's time and tokens. It rides the SSEdoneevent and the JSON reply astrace; the last 30 turns are kept on the session andGET /api/session/:id/historyreplays them asturns, so a reload can rebuild the Trace pane.GET /api/healthreportsdev_trace. Nothing new reaches telemetry: spans, metrics and behaviour events keep their counts and enums. Shape:docs/CLIENT-PROTOCOL.md, "The dev trace". - playground: the Trace pane draws the dev trace per turn: the route with its confidence, the step events as a line (asked, redrawn, settled, summary shown), each tool call folded with its arguments and result, the model's calls and timings; a gateway without the flag keeps the old view plus a note saying why. A reload rebuilds both panes from the one
/historyresponse: the Draft pane frompreview(a finished chat came back empty before: the widget clears the preview when a chat completes) and the Trace pane fromturns. The usage pill readinput_tokens/plan_tokensand never showed; it readsturn_tokens/turn_plan, which the gateway sends. The phone layout is unchanged. - widget:
onTurngainstrace(null when the gateway sends none) and a newonHistory(history)hook hands a host the whole/historyresponse when a chat is resumed or opened. Both are additive; the fake-DOM tests cover them. - evals:
TurnResultgainstraceandturns; the checkshasTrace,routeIs,stepEvent,toolCallandreloadKeepsTrace. The support-intakedev-tracescenario walks the journey with them (the route and its confidence,search_customerswith its query and the two matches, Details asked → redrawn → settled, the create refused with writes off, and the same facts after a reload); the bookings routing scenarios assert the route both ways.npm run gateway:evalssets the flag. - core: the review no longer draws the summary over an answer the change made stale. After "Change something" → a section → a changed answer, the steps that
dependsOnit were reset, but the settle calleddrawSummary()directly, sonextOwed()was never asked: the card came back at once still showing the old Priority, a typed yes was a go-ahead, and the ticket was written with the tool's default (medium) while the user had confirmedhigh. The edit settle now goes through the same chain as every other settle: the reset step is asked again (with one line saying why) and the summary returns after it. Found by walking the example by hand while building a new domain on 0.3.0. A reset now counts asbehaviour_events_total{kind="step",type="reset"}, is a log trace line, and aresetevent in the dev trace (the Trace pane says it). The create gate is untouched in all three layers. evals:cardRow(key, { value })checks a drawn summary's field; the example suite gainsreview-edit-reasks-dependent(red on the old engine at the turn the summary returns, and at the typed yes that reached the write tool) andreview-edit-unchanged(an unchanged edit asks nothing again).check:e2enow also drives the review path with writes on and asserts the record on disk is the summary that was confirmed (red on the old engine).
0.3.0 — 2026-10-14
The release the site already describes: tools in Python, simulated users in the evals, an English reader core with opt-in registers; plus what the 0.3 review's walk as a stranger found and fixed.
- core: a partial form submit is drawn again pre-filled and with the missing or invalid rows marked. The redraw's state (pending values, per-row errors, a multi-pick's picks so far) reached the stored step only after the draw, so the card came back empty; the playground showed it. evals:
formRow(key, { value, error })checks a drawn form's row; the example's partial-redraw scenario now asserts the pre-fill and the mark (red on the old engine). - cli:
marg web | new | evals | checkrefuse a flag they do not know (exit 2, the help printed) instead of ignoring it: an oldermarg new … --lang pythonscaffolded a TypeScript server and said nothing.marg newfails when the templates lack the server template for the chosen language;marg --versionprints the version;marg verdict --helpreaches Verdict. - playground: the empty state skips a domain's example openers that are still the template's placeholders (
<verbatim thing a user would type>), so a freshly scaffolded domain does not offer them as suggestions. - site:
/llms.txt— the site's index for coding agents (every page with its title, by section), written by the sync from the same page map as the nav. - docs: a review of 0.3 walked as a stranger and set beside Google ADK, the OpenAI Agents SDK, LangGraph and Pydantic AI, area by area, with every gap ranked and classified (
docs/reviews/0.3-review-2026-10.md), and ROADMAP "0.4 — what the walk found": the trace pane that shows what the gateway knows and survives a reload, a model-played user, the since line and the live version on the site, the skill installable in one line. - templates: a Python tool server.
npm run new-domain -- <name> --lang python(andmarg new … --lang python) writesmcp/server.pyon the officialmcpSDK (2.x,MCPServerover stdio) andmcp/requirements.txt, with the same tools and contracts as the TypeScript server: the validate / preview / create triad, the bearer in_meta["agent/auth"], the session id and the W3C trace context in_meta, the write gate, JSON lines to stderr. The manifest pointspython3at it.SCAFFOLD_LANG=python npm run check:scaffoldproves it; CI runs that on Python 3.11. Guide:docs/guides/python-tools.md. - core: the readers' vocabulary is English; Hindi and Hinglish are an opt-in lexicon.
reply-words.tskeeps the English sets and rewrites; every Hindi and Hinglish word, rewrite, question marker and skip phrase lives inlexicons/hinglish.ts, loaded withAGENT_LEXICONS=hinglish(the gateway logs what it loaded) orloadLexicons(["hinglish"]).extendLexicontakes rewrites, question openers and leads, cut-offs, unfinished tails, question exceptions and skip phrases as well as words. The readers guide describes registers. - evals: simulated users — a scenario may set
userinstead of a turn list; the runner asks it for each next message from a view of the conversation until it returns null;everyTurnchecks apply to every turn;cooperativeUserplays a deterministic persona (an opener, answers for form rows, preferred taps, asides on cue, stops on completion or a refused write). Onesimulated-userscenario in each example suite runs in CI on the mock model.
0.2.1 — 2026-10-14
The first release published by CI through npm trusted publishing (OIDC, provenance generated by npm); 0.2.0 went out by hand. No runtime changes beyond the CLI package's name.
- cli: the package is
@marg-adk/cli(npm refuses the bare namemargas too similar to existing packages); the command is stillmarg.binpaths no longer start with./, which npm 11 rewrote on publish. - release: npm publishing by trusted publishing (OIDC, no token, provenance automatic);
scripts/publish-first.shfor a package's first version by hand; RELEASING.md describes the one-time setup per package.
0.2.0 — 2026-10-14
The adoption release: installable from npm, a site, a playground that is also the dev UI, one command, a method for coding agents, a second example, every model provider, and the pipelines of a public repository.
- models: presets for every provider a developer is likely to meet — Vertex AI, Azure OpenAI (the
api-keyheader), Bedrock, LiteLLM, xAI, Cohere, Hugging Face, Cerebras, Perplexity, NVIDIA — beside the existing OpenAI, Gemini, Ollama, vLLM, Groq, Mistral, DeepSeek, Fireworks, Together, OpenRouter and the native Anthropic adapter;gen_ai.provider.namefollows the semantic conventions for the new ones; a unit test resolves every preset from the environment. - docs:
docs/providers/(one page per model provider, with the env lines; Gemma, gateways such as Apigee, on-device runtimes explained) anddocs/integrations/(observability backends over OTLP — Langfuse, Datadog, Grafana Cloud, Honeycomb, Phoenix, SigNoz, New Relic, Jaeger — stores, speech, decisions, MCP tools, other frameworks, hosting, coding agents); both are sections on the site. - skill:
skills/build-a-domain/SKILL.md, the method for building a domain as a skill a coding agent follows (the worksheet, the build order, the gate, the classification rule, the never-rules); Claude Code loads it from.claude/skills,AGENTS.mdpoints other agents at it,create-marg-appinstalls it in new projects, and the site shows it under Build. - example:
examples/bookings, the second domain, built by following the build-a-domain skill: a venue picker, a Details card with adaterow, a bespoke Time step fed by an availability tool (the no-availability path offers the nearest days and moves the date), its own mock policy and nine scenarios including routing to each domain (npm run evals:bookings, in CI). - core: a
dateform row kind (an ISO day; the widget draws a date input;isIsoDay); the mock model registry is per domain (registerMockModel(fn, domain)), and the agent names its domain on every model call, so two example domains share one gateway; a utility hop with no domain gets an empty mock answer. evals:TurnResult.domainand theinDomain(name)check. - repository: CI fails when a generated path (the site's mirrored docs or build, a package's
dist/or payload) is tracked; Dependabot ignores major bumps of@types/node(the engine is Node 22). - site: https://marg-adk.github.io/marg — VitePress on GitHub Pages, built from the repository's docs on every merge (
website/,npm run site:build): a landing page, Get started · Build · Components · Run · Reference · Community, search, a comparison page, an FAQ. Pull requests build it, so a dead link fails the PR. - marg: the
margcommand on npm —web(the gateway and the playground),new(a domain from the templates),evals(every suite against a writes-off gateway),verdict(a typed decision from the shell),check(the project's gate: typecheck, then every suite with writes off on its own gateway).create-marg-appwires it into a new project's scripts;check:createrunsmarg checkin the created project. - docs: a review of adk.dev and what Marg takes from it (
docs/reviews/), and ROADMAP "0.3 — the surface": the site, the playground as the dev UI, amargCLI, a skill for coding agents, provider pages, user simulation. - playground: redesigned as the dev UI — a plain top bar with the model and writes status, one centred conversation, the live draft and a new trace pane (per turn: runtime or model, every tool call with its time, usage, the create) as side panels that collapse, past chats in a drawer, the domains' example openers on the empty state, usable on a phone. The README GIF is re-recorded on it.
- widget:
header: falsefor host pages with their own chrome;onTurn(turn)hands the host every completed turn's facts (domain, kind, tool trace, usage, completion); bubbles hug their text./api/healthlists each domain's example openers. - deploy: the image ships
tsconfig.base.json(without it tsx lost the path mappings and the gateway crashed at boot — the first Render deploy failed on this); CI now builds the image and probes its health, playground and widget (imagejob, required). - docs: the launch post,
docs/posts/the-model-must-never-read-yes.md(the long form, the Show HN comment, the r/LLMDevs post, the thread), linked from the README. - docs: the README opens with
docs/images/playground.gif, the six-turn journey recorded from the playground on the mock model (0.14 MB). - playground:
render.yaml, a Render Blueprint for the hosted playground (mock model, writes off, no login, rate limits on), deployed at https://marg-playground.onrender.com and linked from the README. - core: the form-reply pair parser scans instead of matching a regex that backtracked polynomially on long runs of spaces in user text (CodeQL, high). The Docker healthcheck and the CI gate poll
/api/health, the path the gateway serves. - repository: the gate runs on Node 22 and 24 with
npm run lint(ESLint, correctness rules only) first; CodeQL, a security workflow (dependency review,npm audit; GitHub secret scanning with push protection on the repository) and the OpenSSF Scorecard run on every PR or weekly; Dependabot keeps npm and Actions current in grouped weekly PRs; CODEOWNERS, issue templates (bug, feature, domain request), a pull-request template that asks for the gate output and a classification of every red,RELEASING.md,.nvmrc,.editorconfig, and badges in the README. - packages: every package is publishable — a build per package (
tsc -p tsconfig.build.jsontodist/, ESM +.d.ts),exports,types,files,publishConfig.access: public;@marg-adk/widgetis now a package (the file plus a manifest);@marg-adk/gatewayships amarg-gatewaycommand that registers the tsx loader and runs the compiled server. The tsx development path throughtsconfig.jsonpaths is unchanged. - create-marg-app:
npx create-marg-app my-agentcopies the templates, the example domain, the shared skills and the scaffolder into a fresh project depending on the published packages. - core: when installed from npm the project root is the working directory (walking up to the nearest
package.jsonor.git), so.env,domains/,examples/andshared-skills/are found in the user's project;AGENT_REPO_ROOTstill overrides. - gateway: the playground page and the widget are located relative to their packages, not the repository;
/api/skillshonoursAGENT_SHARED_SKILLS_DIR. - checks:
check:pack(every package packs clean) andcheck:create(a project from local tarballs installs, boots and passes the example suite); apackagesCI job runs both. - release: a tag
v*runs the gate and publishes every package with provenance (with a token at the time; trusted publishing since — see Unreleased).
0.1.0 — 2026-10-13
First open-source release, extracted and generalised from a production agent.
- core: the domain-agnostic runtime — prompt assembly from markdown skills (typed variants, capabilities, security preamble), the model chain (Anthropic, any OpenAI-compatible endpoint, a scripted mock) with failover, breaker, retries and per-endpoint configuration, MCP tools with reconnect and hidden
internal_*tools, sessions with bounded memory and healed history windows, durable stores with fallback, two-stage tool-output trimming, runtime-owned steps (draw / read / settle / chain / late draw / redraw / review / carry / dependencies / reload redraw), whole-content readers, the create gate and attested-list guard, tolerant ui-block parsing and sanitising, OpenTelemetry seam, structured logs off the main thread. - verdict: typed decisions (
choice/noul/score) with rules, System One (Laya / any compatible server), LLM logprobs and mock backends; a cascade; calibration maths; a CLI, an MCP server and a System One-compatible HTTP server. - gateway: HTTP + SSE; sessions with verified identity and owner checks; the agent-token exchange; rate limits with runtime-turn refunds; usage caps in plan tokens shown as percentages; media (upload ≠ attach); voice (Deepgram or any Whisper-compatible endpoint); nudges; health, metrics, HTTP tracing; a metering sink; graceful shutdown.
- evals: the scenario runner with sharding, reruns, flake classification and a gate report.
- widget: streaming, chips, multichips, lists, cards with sections, toggles, forms with echoes, tables, progress, media, bars; resume, nudges, voice, uploads; link scheme allowlist.
- example: support ticket intake, end to end offline with a scripted mock model; 7 scenarios.
- checks:
check:otel(the telemetry seam against in-memory exporters and a stub log sink),check:scaffold(the templates produce a domain that compiles and passes its own suite),check:e2e(the real write path with writes on); the widget driven under a fake DOM in tests. - observability: Docker Compose for OpenObserve (+ optional collector), generated dashboards and alerts (
o2:dashboards), an idempotento2:bootstrap. - deploy: a non-root Dockerfile with a health check, Compose profiles (stores, observability, decisions with Ollama + laya, edge with Caddy), a production env example, DEPLOY.md; a CI workflow.
- docs: the pattern, the lessons, the playbook, the production checklist, the client protocol, decisions, observability, metering, security, the auth design, six ADRs, guides, templates.
Source: CHANGELOG.md — edit it there; the site mirrors the repository.