Releases: BrightbeamAI/chap
Release list
0.2.13: the review gate closed on both routes
CHAP 0.2.13: the review gate closed on both routes
Read the next section before upgrading.
If you are upgrading
task.update no longer completes a task that requires review. The call is
refused with -32602 and the message names the way through. Submit the output
with task.complete, which opens the review, and let a reviewer decide.
in_progress → completed is a legal transition and carried no review check, so
until this release a task marked review_required could be finished in one
call: no artefact recorded, no decide.* on the chain, and an audit log that
reads as though the work was simply done. That is the single failure
review_required exists to prevent. Tasks that need no review are unaffected,
and so is every other task.update transition.
Fractional MCP parameters are decimal strings. confidence,
max_cost_usd, weights and weight were declared type: "number". No
caller could satisfy that: CHAP canonicalisation admits integers only, so any
fractional value was refused at ingress with -32602. If you were sending
confidence: 0.86, the call was already failing. Send "0.86". The schema now
says so, and the error message tells a client that gets it wrong what to do.
The other gate
review.request accepts the documented widen path. Adding a reviewer to an
open review means re-requesting the same artefact. The rule was compared after
the default had been applied, so omitting rule on the second request read as
an attempt to change it, and was refused with -32014 on every review not
opened under any_one_approves. Only a rule the caller actually supplied
counts as a change.
Tool descriptions that match the implementation
0.2.13 finished describing all 195 MCP tool parameters, then audited the
descriptions against both coordinators. Nineteen described behaviour the code
does not have. Among them:
control.pausein_flight_policyis recorded and never acted on. Work in
flight is unaffected by either value.control.pausescope: "participant"stops new tasks being assigned to that
member. It does not stop what they are already doing.control.rollbackrestoresmode_ceilingandmembers. The other captured
aspects are held in the snapshot and not reapplied.deliberate.voteweightis recorded but not read; the tally uses the map
given atdeliberate.open.deliberate.opendeadlineis recorded; the coordinator does not close a
vote on it.audit.readhas no tag filter, so grouping by tag is the reader's job.control.snapshotlabelis not a rollback target; rollback resolves an
artefact id.escalate.raisegives the successor an empty input, not the original's.
Each now states what happens and names the error code where a constraint is
enforced. Every claim is checked against both implementations by a probe that
drives 92 calls through each and compares the output byte for byte.
The tool-level descriptions were rewritten too. task.complete still told
callers to follow it with review.request, which 0.2.12 made wrong. The Python
copies of both tables are now generated from the TypeScript ones, so the claim
that they mirror each other is enforced rather than asserted.
Documentation
The decimal-string error ran through the documentation as well as the schema:
a runnable curl in the five-minute start, examples in four scenario files,
the routing profile, and the JCS vector in conformance/test-vectors.md, whose
sample envelope carried 0.42 and whose stated canonical bytes were neither
key-sorted nor whitespace-free. The vector is recomputed and now agrees byte
for byte across both implementations.
Thirteen scrubbed placeholder addresses are repaired. SPECIFICATION.md §8.1
gains the task.update refusal, and profiles/review.md §3.1 covers both
gates.
Packaging
coordinator-mcp imported zod without declaring it, so the bundler inlined
the library into all four entry points: 598 KB each, a 1 MB tarball, and a
second zod instance in the process alongside the MCP SDK's own. It is now a
declared dependency on the range the SDK asks for, and external to the bundle.
Entry points are 50 KB; the tarball is 205 KB.
scripts/check-versions.mjs holds one release version across the forty-eight
places it is written. It found cli.ts carrying a version constant of its own.
CI runs it, so a partial bump cannot reach a tag.
Versions
All nine packages move to 0.2.13 together.
| Package | Version |
|---|---|
@brightbeamai/chap-coordinator, -mcp, -a2a |
0.2.13 |
chap-coordinator (PyPI) |
0.2.13 |
chap-langgraph, chap-pydantic-ai, chap-llama-index, chap-ag2, chap-google-adk |
0.2.13 |
The wire format is unchanged. Both coordinators remain at parity, and both
references pass the conformance harness.
Full detail in CHANGELOG.md.
0.2.12: review rules, modes gating, envelope ceiling
CHAP 0.2.12: review rules, modes gating, and an envelope ceiling
Read the next section before upgrading if you use modes/1.0.
If you are upgrading
task.complete on a trial-mode task no longer completes it. Trial mode
forces review, so the call opens a review and the task moves to
review_requested. A reviewer decision completes it. Anything expecting
completed back from task.complete on a trial task now has to follow the
review.
If you never loaded modes/1.0, nothing changes for you. That is deliberate:
until this release, mode semantics applied to every workspace whether or not
the profile was loaded, and correcting that is most of what this release is.
review_required is enforced
review_required was set in three places, serialised onto the task, and read
by neither coordinator. A task whose review was mandatory completed with
unreviewed output and no decide.* in the chain, which is the failure mode
CHAP exists to prevent.
task.complete now opens the review that review.md §3.1 always described.
The submitted output becomes the artefact under review, and only a reviewer
decision takes the task to completed.
The implicit review is addressed to the members who are neither the completer
nor the assignee. Without that, a single-member workspace would have the
producer approving its own work and the chain would carry a decide.approve
that looked like oversight. Where nobody qualifies, the completion is refused
with -32011 rather than opening a review only its author could decide. An
explicit review.request keeps whatever to it was given.
decide.approve also evaluates review.rule now, rather than completing on
the first approval whatever the rule said.
Modes stops applying to workspaces that never asked for it
Enforcing review_required exposed why nobody had noticed it was inert. New
workspaces defaulted to mode: "trial", and the trial forcing ran with no
check that modes/1.0 was loaded. Every default workspace, including a
Core-only one, silently forced review on every task.
modes.md declares the profile "Depends on: Core", and the workspace
descriptor examples in SPECIFICATION.md use "mode": "production", so the
trial default and the ungated forcing were a defect rather than an intended
default. Mode semantics are now gated on the profile being loaded.
The reference server and the harness
reference/core-plus-review is a from-scratch reimplementation that shares no
code with the packages, and it had none of the review-required behaviour. It
now matches the coordinators, including the eligible-reviewer rule and the
-32011 refusal.
The conformance harness never created a workspace, relying on
participant.join to auto-create one, so it inherited each target's defaults.
Those differ: the Python reference loads every profile and defaults to trial,
the Core+Review TypeScript reference has no modes at all. Once trial began
forcing review, cm-08 failed against one target and passed against the other,
and the two had not been comparable for some time. The harness now pins its
workspace to production mode before any vector runs, and both references pass
all 26.
Also in this release
A maximum envelope size is enforced and published, with request body size and
JSON depth capped in the reference TypeScript servers. whisper.* requires
workspace membership. superseded is terminal in control.pause and
control.cancel. JSON Patch array indices parse through one strict shared
rule. Signature verification fails closed with SIG_VERIFY_FAILED on an
exception. The threaded Python reference server serialises dispatch.
Versions
All nine packages move to 0.2.12 together.
| Package | Version |
|---|---|
@brightbeamai/chap-coordinator, -mcp, -a2a |
0.2.12 |
chap-coordinator (PyPI) |
0.2.12 |
chap-langgraph, chap-pydantic-ai, chap-llama-index, chap-ag2, chap-google-adk |
0.2.12 |
The wire format is unchanged. Both coordinators remain at parity, and both
references pass the conformance harness.
Full detail in CHANGELOG.md.
0.2.11: coordinator-mcp namespace casing
coordinator-mcp only, no behaviour change. The MCP Registry grants the org namespace using GitHub's own casing and proves npm ownership by reading mcpName from the published package; 0.2.10 carried a lowercase value and npm does not allow replacing a published version. The coordinator and A2A packages stay at 0.2.10. See the 0.2.10 release for what actually changed.
0.2.10: MCP registry entry, and two verdicts that changed
CHAP 0.2.10: MCP registry entry, and two verdicts that changed
CHAP is now listed on the official MCP Registry
as io.github.BrightbeamAI/chap, and the MCP server is something a client can
launch rather than a library you have to wire up yourself.
Read the next section before upgrading. Two calls behave differently from
0.2.9, and the usual pins resolve this release automatically.
If you are upgrading
^0.2.9 on npm and >=0.2.9 on PyPI both resolve 0.2.10, so an ordinary
install picks these up with no prompt.
review.request now refuses a substituted artefact. Requesting review a
second time on a task that already has an open review, with different content,
returns -32014 instead of quietly replacing the artefact under review. The
old behaviour discarded a review a human might already have been part-way
through. Requesting again with the same artefact still works and widens the
reviewer set, returning amended: true. Reported by Iman Schrock (#72).
audit.verify_chain no longer reports a pass over a range it did not
check. A workspace can enable chaining part-way through its life, and
verification used to replay from the first chained entry and return ok: true
with a smaller entries_checked beside it. Four entries with three written
before chaining returned a pass having checked one. The verdict is now one of
three terminal outcomes: a broken chain is still an error, a log with entries
outside coverage returns status: "not_evaluated" with ok: false and
reason: "unchained_prefix", and verified requires complete coverage. ok
is true only alongside verified, so code reading ok alone now fails
closed where it previously passed (#76).
Both changes fail closed. Neither can silently accept something the old
version rejected.
Running the MCP server
npx -y @brightbeamai/chap-coordinator-mcpThat serves all 39 CHAP methods as MCP tools over stdio. In a client:
{ "mcpServers": { "chap": {
"command": "npx",
"args": ["-y", "@brightbeamai/chap-coordinator-mcp"],
"env": { "CHAP_DB_PATH": "~/chap.db" } } } }CHAP_DB_PATH points at a SQLite file. Without it the coordinator runs in
memory and workspaces are lost when the client exits, which suits a trial and
does not suit real decisions. If the path is set and the store cannot be
opened, the server exits with the reason rather than starting in memory and
discarding what it was asked to keep. CHAP_PROFILES overrides the profile
set; new workspaces include audit-scitt/1.0 by default so their chain starts
at the first entry, because a workspace that adds the profile later can never
chain-verify what came before it.
The package previously exported makeChapMcpServer and declared no bin, so
npx started nothing. Its peer dependencies are now real dependencies, which
is what makes the standalone launch resolve.
Binding a decision to its content
decide.approve, decide.reject and decide.override accept an optional
approved_artefact_digest, the sha256: digest over the RFC 8785 (JCS)
canonicalisation of the artefact under review. A mismatch returns -32074 and
records nothing, so a decision cannot be attributed to content the decider
never saw. Absent, behaviour is unchanged. Shipped as
CEP-001, from a conversation with Iman Schrock (#71).
Also in this release
The store contract says plainly that it is single-writer, because running two
coordinators against one shared store loses entries and the surviving chain
still verifies. Characterisation tests pin that behaviour rather than leave it
to be rediscovered (#69).
from_seq and to_seq on audit.verify_chain are declared and honoured by
neither implementation. Supplying either is now refused rather than silently
answering the whole-log question with whole-log counts.
AuditVerifyChainResult described valid and breaks, neither of which any
handler has ever returned. The declared type now matches the wire.
The error registry, the identity-vc/1.0 codes, the proposal-process naming
and a missing MAINTAINERS.md are all corrected, and the 0.2.7 changelog
section, 218 lines lost between two commits, is restored.
0.2.11
@brightbeamai/chap-coordinator-mcp only, published immediately after. The
registry grants a GitHub organisation namespace using the organisation's own
casing, io.github.BrightbeamAI/*, and proves npm ownership by reading
mcpName out of the published package. 0.2.10 carried a lowercase value and
npm does not allow a published version to be replaced. No behaviour change.
The coordinator and A2A packages stay at 0.2.10.
Versions
| Package | Version |
|---|---|
@brightbeamai/chap-coordinator |
0.2.10 |
@brightbeamai/chap-coordinator-mcp |
0.2.11 |
@brightbeamai/chap-coordinator-a2a |
0.2.10 |
chap-coordinator (PyPI) |
0.2.10 |
chap-langgraph, chap-pydantic-ai, chap-llama-index, chap-ag2, chap-google-adk |
0.2.10 |
The wire format is unchanged. Both coordinators remain at parity and answer a
shared probe suite identically. The profile identifier stays audit-scitt/1.0:
profile surfaces are expected to move before 1.0, and a bump now would imply a
stability guarantee the 0.x line does not offer.
Full detail in CHANGELOG.md.
CHAP v0.2.9: complete package publish and consolidated 0.2.x hardening
CHAP 0.2.9
First release with the full set on npm and PyPI. The MCP and A2A coordinators and all
five framework adapters, previously unpublished, now ship alongside the coordinators.
Both MCP adapters move to the 2026-07-28 protocol revision while continuing to serve
2025-11-25 clients, and the release consolidates the security, audit-integrity and
robustness work that landed across the 0.2.x line.
The CHAP wire format is unchanged. Both coordinators remain at parity.
Breaking changes
Read these before upgrading from 0.2.8.
- Node 20 is the floor. Node 18 reached end of life in April 2025 and lacks a
standardglobalThis.crypto, which sent id generation down a fallback that threw in
an ES module.enginesis now>=20across every package. - The Python
mcpextra moves to>=2,<3. The transport is built on themcp2.x
SDK, which implements the 2026 boundary natively. Installingchap-coordinator[mcp]
will move you to a new SDK major. - The MCP transports refuse requests they previously served. A request declaring a
protocol version the adapter does not implement is now refused with
UnsupportedProtocolVersion(-32022); a request declaring a version but omitting
clientCapabilitiesis refused withInvalidParams(-32602).resultType,ttlMs
andcacheScopeare emitted to 2026-era callers and withheld from handshake-era
ones, which receive the result shape their own revision defines.
MCP 2026-07-28
The 2026 revision is stateless: instead of negotiating once through an initialize
handshake, every request carries its protocol version and client capabilities in
_meta, and the server accepts or rejects each request independently.
server/discoveris implemented in both languages, advertising
["2026-07-28", "2025-11-25"]because both eras are served.- Only
2026-07-28may be declared per request. The 2025-11-25 revision is reached
throughinitialize, as its own revision defines, and an
UnsupportedProtocolVersionpayload names only the declarable versions so a retry
cannot land on the same refusal. - Results are typed and cacheable for a 2026-era caller.
- The Python transport is built on the
mcp2.x SDK; the TypeScript adapter implements
the same rules against SDK 1.x. Both were verified against the same probe suite and
answer it identically, error codes, messages and payloads included.
Security
Key lifecycle bound to signatures, membership floors on mutating methods, step-up fixed
and scoped, adapters can no longer fabricate decisions, SCITT verification fails closed,
and an optional read-authorisation gate. See the changelog for the full list.
Fixed
Reads no longer mutate the audit chain, chain verification runs from genesis and no
longer reports an unchained workspace as tampered, overrides diff against the artefact
under review, cross-implementation hashing is aligned, and signed workspaces and
in-flight reviews survive a restart.
Documentation
The evidence-chain link formula in the specification and in the conformance test vectors
described two different constructions, neither matching the implementations. Both now
state the implemented form, so a third-party implementation can reproduce a chain the
references accept. The one-entry-per-message invariant is scoped to state-changing
messages, with the four read-only methods named.
Install
# npm
npm install @brightbeamai/chap-coordinator
npm install @brightbeamai/chap-coordinator-mcp
npm install @brightbeamai/chap-coordinator-a2a
# PyPI
pip install chap-coordinator
pip install chap-langgraph
pip install chap-pydantic-ai
pip install chap-llama-index
pip install chap-ag2
pip install chap-google-adkFull detail in CHANGELOG.md.
CHAP v0.2.8: security and audit hardening, and registry-ready packaging
CHAP 0.2.8 is an additive release on 0.2.7. It hardens the coordinators' security and audit behaviour and completes the packaging needed to publish to npm and PyPI. There is no change to the wire format or the message schemas; the protocol itself is unchanged, and the TypeScript and Python coordinators move together at parity.
Security and audit
- Messages that cannot be safely canonicalised are now rejected before they reach a handler, so nothing uncanonicalisable can enter the signed, hash-linked audit log (#21).
- Canonicalisation rejects non-integers and integers outside the safe range, so a record can never silently lose numeric precision, and RFC 6902 patch application is hardened against prototype pollution.
audit.verify_chainno longer runs on a workspace without chaining enabled, and it verifies from the chain's genesis, so an unchained workspace is never reported as tampered while a missing link inside the chain is still caught (#23).participant.joinno longer replaces an existing member. Re-joins are additive, and only attested (OIDC or VC) keys can be added to an existing member, which closes an unauthenticated-join path to member takeover (#25).
Packaging and distribution
- npm packages renamed to
@brightbeamai/chap-coordinator,@brightbeamai/chap-coordinator-mcp, and@brightbeamai/chap-coordinator-a2afor registry-consistent naming. - Packaging and metadata hardened across all nine packages for publication to npm and PyPI.
- Reference servers and the playground updated to the new package names, with a smoke test added.
CHAP v0.2.7: Framework adopters and scenarios
CHAP 0.2.7
An additive release on top of 0.2.6: four more framework bridges and a new
runnable scenarios/ directory. No change to the protocol core, the
coordinators, or the wire format: this release adds adapters and worked
examples around an unchanged 0.2.x protocol.
Highlights
Four framework adopters. chap-langgraph (shipped in 0.2.5) is joined
by four more bridges, each connecting a real agent framework's
human-in-the-loop mechanism to CHAP's review/decide methods. An
approval, edit, or denial in the framework becomes a decide.approve /
decide.override / decide.reject on the audit chain:
chap-pydantic-ai: bridges [Pydantic AI](https://ai.pydantic.dev)'s
deferred-tool approval flow. An edit before approval is recorded as an
override carrying the diff, rationale, and tags.chap-ag2: bridges [AG2](https://github.com/ag2ai/ag2) (AutoGen)
agent turns.chap-llama-index: bridges LlamaIndex
Workflows
human-in-the-loop events.chap-google-adk: bridges Google
ADK human-in-the-loop tool
confirmations.
All four respect the authorisation rules added in 0.2.6 (they join both the
agent and the reviewer, address the review to the approver, and decide from
the approver), each ships with tests that run against the reference
coordinator with enforcement active, and each has a runnable example. The
frameworks themselves are optional dependencies; the bridges and their
tests do not require them installed.
The scenarios/ directory. Runnable, community-contributed domain
narratives on CHAP core, one folder per scenario, distinct from examples/
(capability walkthroughs) and the adapters' own examples/ (framework
demos). It ships with a catalog of all twelve IN_PRACTICE.md scenarios
and the first three worked examples:
01-solo-dev-overrides/in two tiers: a zero-dependency
scenario.pythat records decisions, verifies the hash-linked chain
(and shows a tamper being caught), reconstructs one override, and prints
an override learning report; and asystem/implementation driving the
same story through a real Pydantic AI agent whose review action is
approval-gated, offline, with a one-line path to a live model.02-marketing-copy/: one drafter, one editor; the opener-rewrite
report the audit trail writes itself.03-founder-inbox/: a support inbox reconstructed from the chain,
surfacing a repeated wrong-policy pattern across tickets.
The scenarios directory is open to contribution: good-first-issue scenarios
for newcomers, help wanted for the regulated ones.
Also in this release
IMPLEMENTATIONS.mdupdated with the four new bridges and their test
counts.
Upgrade notes
Nothing to change. This release adds packages and examples; it does not
alter the coordinators, the profiles, or the wire format. Existing 0.2.6
deployments are unaffected. If you use one of the new frameworks, install
its bridge; otherwise there is nothing new to adopt.
Tests
- New bridge suites, all green against the coordinator with authorisation
enforcement:chap-pydantic-ai17,chap-ag214,chap-llama-index13,
chap-google-adk15. - Unchanged elsewhere: TypeScript coordinator 95, MCP 17, A2A 14,
playground 7; Python coordinator 120, langgraph 10. - Conformance harness: 23/23 on both reference implementations.
Packages
All bumped to 0.2.7 in lockstep. The new bridges' publication status
depends on the release-workflow decision; anything not yet on PyPI ships as
source and runs from a clone.
@chap/coordinator,@chap/coordinator-mcp,@chap/coordinator-a2a(npm)chap-coordinator,chap-langgraph, and the newchap-pydantic-ai,
chap-ag2,chap-llama-index,chap-google-adk(PyPI)
Full detail in [CHANGELOG.md].
CHAP v0.2.6: Authorisation and MCP robustness
CHAP 0.2.6
Follows the 0.2.5 adoption release with a real-world MCP integration fix, a
clearer README walkthrough, and an authorisation tightening reported by a
collaborator. Backward-compatible on the wire: no envelope or schema
changes. The authorisation work changes behaviour (it now rejects envelopes
that were silently accepted before), which is why this is a minor version
rather than a patch.
Highlights
MCP adapters now handle stringified-JSON arguments. A real Claude Desktop
integration showed that LLM MCP clients often send structured tool arguments
as JSON-encoded strings instead of native objects or arrays. That left an
artefact stored as a string and crashed a decide.override patch with an
internal error. Both the TypeScript and Python MCP adapters now normalise these
at the adapter boundary, before the envelope reaches the protocol core. The
core is untouched and stays strict; the audit log records correctly-typed
artefacts and the override applies on the first try.
Actor membership is enforced. Previously only a task's assignee was
checked for membership; the actor (from) of a method was not, so a
decision or completion could be attributed to a participant who never joined.
Every actor-action method in Core and review/1.0 now verifies that from is
a joined member and rejects a non-member with not_authorised (-32011). This
makes the audit log's attribution sound. New precondition text at
SPECIFICATION.md §6.3.1.
Reviewer-set eligibility for decisions. To act on a review, decide.* and
abstain.declare now require from to be one of the reviewers the review was
addressed to (the to set on review.request), not merely any member. The
rule field governs how many reviewers must decide; the to set governs
who is eligible. A review addressed to a workspace:<id> or group:<id>
scope admits any member, and a review with no recorded reviewer set falls back
to the membership floor. See profiles/review.md §3.2.
Dual-language README tour. The 90-second walkthrough now shows TypeScript
and Python side by side, and the hero GIF was rebuilt with a step indicator and
progress bar so the six-step Core+review flow is legible.
Upgrade notes
This release tightens enforcement. If you were already joining your
participants before they act, and addressing reviews to the reviewers who
decide them, you need to change nothing: the reference flows, the MCP and A2A
adapters, the langgraph bridge, and the playground are all unaffected. If you
relied on the previously-missing checks, two calls that used to succeed will
now return -32011:
- A
decide.*,task.complete,review.request, orabstain.declarewhose
fromnever joined the workspace. Fix:participant.joinfirst. - A
decide.*orabstain.declarefrom a member who was not named in the
review'stoset. Fix: address the review to that reviewer, or use a
workspace:/group:broadcast scope if any member should be able to decide.
There is no break-glass bypass: admitting a new actor (an escalation target or
an emergency approver) is done by joining them first, so the admission is itself
recorded in the audit chain.
Conformance
- Two new harness vectors:
rv-07(non-member decision rejected) andrv-08
(member-not-in-reviewer-set rejected; the addressed reviewer still succeeds). - The harness now runs 23 vectors and passes on both reference implementations.
Notes
escalate.raisealready required its escalation target to be a member, so it
was unchanged.- The reference implementations surface the membership and reviewer-set
conditions withnot_authorised(-32011) rather than the spec table's
unknown_participant(-32403), because -32403 already denotes
OIDC_TOKEN_INVALIDin their private error range. The broader
spec-versus-implementation error-table reconciliation is tracked separately. - The MCP coercion fix is scoped to the adapter boundary. The same
stringified-JSON input reaching the core through a non-adapter path still
produces -32603, a latent core rough edge left for a separate change.
Tests
- TypeScript coordinator: 95 (+11 authorisation); MCP adapter: 17 (+9 coercion);
A2A adapter: 14; playground: 7. - Python coordinator: 120 (+9 coercion, +11 authorisation); langgraph bridge: 10.
- Conformance harness: 23/23 on both reference implementations.
Packages
All published at 0.2.6:
@chap/coordinator,@chap/coordinator-mcp,@chap/coordinator-a2a(npm)chap-coordinator,chap-langgraph(PyPI)
Full detail in [CHANGELOG.md](./CHANGELOG.md).
CHAP v0.2.5: Adoption release
CHAP v0.2.5
CHAP v0.2.5 is an adoption-focused release for the Collaborative Human-Agent Protocol.
This release makes CHAP easier to run, test, package and integrate across TypeScript and Python implementations.
Highlights
- Publish-ready npm packages for
@chap/coordinator,@chap/coordinator-mcpand@chap/coordinator-a2a - PyPI-ready Python package for
chap-coordinator - New SQLite-backed storage support
- Typed coordinator API for cleaner integration
- New
chap-langgraphbridge for LangGraph human-in-the-loop workflows - Docker-based playground with deterministic
CHAP_NO_LLM=1mode - Single-file audit and override viewer
- Reusable CHAP conformance GitHub Action
- Updated README, quickstart and implementation registry
Conformance
- TypeScript and Python reference implementations pass the CHAP conformance suite
- Conformance harness: 21/21 test vectors passing
Security and reliability
- Hardened audit viewer with HTML escaping and CSP
- Docker playground bound to
127.0.0.1 - SQLite queries use prepared statements
- Improved idempotency checks in the LangGraph bridge