Skip to content
SukramJPublic

About

Matter in pure Go: device and bridge side (cluster servers, OTA, media) and a full commissioner/controller, as an embeddable library. A semantic port of matter.js. Not certified by the Connectivity Standards Alliance.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

2 watching

Forks

Latest commit

 

History

435 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-fabric

go-fabric is a pure-Go implementation of the Matter protocol, packaged as a library a host application embeds. On the device side it brings the TLV codec, the Interaction Model, PASE and CASE session establishment, MRP over IPv6 UDP and TCP, DNS-SD advertisement, the cluster servers a bridge needs (including the media clusters, the OTA requestor and provider, and DiagnosticLogs over BDX), and the endpoint assembler that turns a host's own device list into a Matter topology. The host keeps its device model; this module owns the wire format and hands back the port contracts (contract/) a device implements to appear as a bridged endpoint. On the controller side (controller/, ADR 0020) it is a full commissioner: discovery, attestation (with the CSA Distributed Compliance Ledger, opt-in), NOC issuance, the client interaction and a typed image of a remote node, bindings and the group sender — examples/reference-controller drives it from the command line. It implements the Matter specification (currently 1.6.1) and follows matter.js as its reference implementation — not a translation of its TypeScript, but its behaviour. matter.js is our executable specification: where its production-hardened behaviour departs from the spec text, we follow matter.js and record the departure; the spec still defines what is mandatory. Cluster IDs, revisions, attribute IDs, constraints and wire shape are mirrored from matter.js HEAD rather than transcribed from the specification, and the extracted matter.js element model ships embedded so parity is a test, not a claim.

Status

As of v0.22.2 (2026-11-12); the starting point of the milestones is the roadmap's baseline of 2026-10-17.

Area State
Device side all 135 clusters of the matter.js snapshot served, all 91 device types generated (comparison, roadmap)
Controller side full commissioner (BLE, Wi-Fi and Thread network steps, keys behind crypto.Signer, the embedded DCL snapshot), controller role stages 1–6c, Joint Commissioning after connectedhomeip (comparison)
BLE controller: done with milestone 1 — ble/bluez on Linux, ble/esphome through ESPHome Bluetooth proxies, pair --ble, proven against a matter.js node over virtual controllers; device: node.Network.BLE with ble/bluez as the GATT peripheral on Linux, commissioned over BLE onto Wi-Fi (guide, milestone 7); proven by chip-tool under chip's BlueZ and wpa_supplicant mocks (make chiptool-ble-wifi) and by the weekly btvirt job in both directions, the hardware test follows
Wi-Fi device: node.Network.WiFi.Driver joins the network a commissioner provisions; wifi/wpasupplicant is the driver on Linux (wpa_supplicant over D-Bus, a nested module), examples/ble-wifi-light the example node with BLE and Wi-Fi (operations, milestone 7)
Thread a Thread Border Router over an OTBR and ThreadNetworkDirectory on the device side (guide); the commissioner provisions datasets; no Thread radio (comparison)
ICD shipped with milestone 5: the device side (node.Config.ICD, Check-In) and the controller's ICD client (guide)
Certification not pursued; certifiability is a goal (certifiability)
Verified ecosystems Apple Home, Home Assistant; Google Home and Alexa pending (roadmap)

Not certified

This is an independent open-source implementation. It is not certified by the Connectivity Standards Alliance, and it is not a project of the Alliance. No warranty or assurance is made about rights that may be required to implement it. Using it does not certify anything: it does not assure compliance with the Matter specification, and it does not convey any right to describe a device, product or service built with it as Matter compliant, certified or similar. Certification requires membership in the Alliance and compliance with Alliance policy; so does any use of Alliance trademarks and logos. See licenses/NOTICE-matter.js.txt, reproduced from matter.js, which states the same terms for the project this one is ported from.

Why "Matter" is not in the name

"Matter" and the Matter logo are trademarks of the Connectivity Standards Alliance. Their use — in a product, project or repository name as much as on a device — is reserved to Alliance members and certified products under the Connectivity Standards Alliance Trademark and Logo Usage Guidelines and Terms (https://csa-iot.org/resources/governing-documents/; the terms are restated in licenses/NOTICE-matter.js.txt: "Only the Alliance and its members may use Alliance trademarks and logos, including, without limitation, the Matter trademarks and logos"). This project is neither, so the mark is not part of its name or of the names of the repositories built on it (go-ha2fabric, go-hamapping); the word appears only descriptively — a library that implements the Matter specification, a bridge for Matter controllers — and never to suggest certification or endorsement. The name go-fabric is the specification's own term for a commissioned network of nodes.

Certification is not pursued by this project. Certifiability is a goal: the module is meant to let a product built on it pass certification, and the CSA certification test families run against the reference daemon to hold it there. What passes, what does not and why, and what a product owner must supply that a library cannot is in docs/certifiability.md (ADR 0011).

Documentation

The site (rendered from docs/) is at https://sukramj.github.io/go-fabric/; the API reference is pkg.go.dev.

docs/index.md Where to start, by role: embedding the device side, driving the controller, evaluating the architecture.
docs/architecture.md The two roles, the layers, the request path, the package map and the scope boundaries that are decisions rather than backlog.
docs/getting-started/ A minimal device host and a minimal controller, each a compiling example.
docs/guides/host-view.md A bridge as a host writes it — two declared devices, the change's origin, the device's lifecycle — every line explained.
docs/guides/ Host ports, concurrency, persistence.
docs/security.md The security model of both roles.
docs/matterjs-comparison.md Feature-by-feature against matter.js, with a verdict on whether each gap is worth closing here.
docs/certifiability.md What the CSA certification families say about this module, family by family.
docs/matter-parity-contract.md What parity means and which standing guards enforce it. Read before your first change.
docs/matter-ecosystem-observations.md What Apple Home, Google Home and Alexa were actually observed to do.
docs/adr/ Architecture decision records.
docs/history/ Earlier planning concepts (German), kept for their reasoning.
notes/parity/by_design.md The catalogue of intentional divergences from matter.js.
notes/parity/matter_behaviour_findings.md Known behaviour gaps that are not intentional, as scoped fix packages.

Examples

examples/reference-bridge is the reference daemon: a bridge on this module, the binary the chip-tool suite runs against. examples/reference-controller is the controller role as a command-line tool — pair a node by its QR or manual code, read, write, invoke, subscribe, provision groups and bindings, serve an OTA image — with its fabric kept in one SQLite file; its README lists every command.

API stability

The module carries its own SemVer lane, independent of any host that embeds it.

What "public API" means here

Every exported identifier outside internal/ is public API. The module already draws that line for itself: internal/ holds three kinds of package, and Go makes all of them unimportable from outside — the one-way seams through which the facade, the test-support packages, the reference programs and the module's own tests reach package internals (bridgeseam, channelseam, coreseam, deviceseam, exchangeseam, fabrictestseam, nodeseam, surfaceseam, udpseam, inflight, clockvar); shared internals behind them (serialqueue, forward, netwatch, valuejson); and test support (paritytest, chipdm, the chip-tool suite chiptool). Nothing else is private by convention, so nothing else may be changed as if it were.

Depend freely on bdx/, binding/, bootid/, bridge/, client/…, clock/, cluster/…, commissioning/, contract/, controller/…, device/, diag/, diagevent/, eligibility/, endpoint/ (including endpoint/sqlitestore), groups/, icd/, im/, im/subscription, logring/, mdns/, node/, parity/, schema/, secure/…, store/, surface/, thread/, tlv/ and transport/…. The device layer device/ and the node facade node/ are public API since v0.3.0; that release freezes nothing, and the v1.0.0 freeze is still ahead.

bridge/bridgetest, endpoint/endpointtest, controller/ble/bletest, clock/clocktest, surface/surfacetest, store/storetest and fabrictest are public API on the same terms as the rest, not a lower tier. They exist for the reason net/http/httptest exists — a consumer's tests need to place a bridge in a state the production API is not shaped to reach — and a consumer's test suite is as expensive to break as its production code.

Three things outside internal/ are still not API. conformance/ is this module's own suite, shaped for the tests in this repository rather than for a consumer -- one of its three exported identifiers takes a *testing.T, and the other two exist to serve it. examples/reference-bridge, examples/reference-controller and everything under script/ are programs and the packages that serve them (examples/reference-controller/cli, the guards and generators' own packages under script/) — runnable, not a library. Copy from them; do not build against them.

One value-level caveat on parity/ and schema/: their Go surface is covered by everything below, but the data behind it is a matter.js HEAD extract. Cluster revisions, attribute IDs and constraint values move when upstream corrects them. That is a behaviour change, not a signature change, and it is announced the same way — see the exception under Pre-1.0.

The deprecation window

An identifier on its way out is marked, kept working, and only then removed.

  1. Marked. Its doc comment gains a paragraph beginning Deprecated: , naming the replacement and the release the removal becomes permissible in. That exact prefix is what gopls, staticcheck (SA1019) and the Go documentation renderer key on, so a consumer sees it in an editor without reading a changelog.
  2. Kept. A deprecated identifier keeps its exact behaviour for the whole window. It is not degraded, does not start logging, and does not become a no-op. A rename lands the new name first and leaves the old one delegating to it.
  3. Removed no earlier than the second minor release after the one that marked it. Deprecated in v0.4.0 means removable in v0.6.0, not before. Consumers who upgrade minor-by-minor therefore see at least one release in which their code still compiles and the warning is already visible.

Suspended until a second consumer or v1.0.0 (owner decision, 2026-10-21). While the reference consumer is the module's only one and migrates in one step, a replaced identifier is removed in the next minor release, without the window, once docs/guides/migrating-to-the-facade.md names its replacement — a removal without its line there is a defect. The removal is announced under ### Removed as below. The window returns, as written above, with the second consumer or with v1.0.0, whichever comes first.

Currently deprecated, each with its replacement and the release its removal becomes permissible in:

Deprecated Replacement Removable in

A patch release (v0.x.y) never removes or renames a public identifier and never changes a signature. Deprecations may be marked in a patch release; they are only ever acted on in a minor one.

Pre-1.0

The module is at v0; v0.1.0 is its first tag. Before it, main was the only consumable version and could break in any commit, which is why consumers tracked a pseudo-version. main is still consumable the same way — see CONTRIBUTING.md — but a tagged version is what a consumer should pin.

SemVer permits a v0 module to break on any minor bump. This module does not use that permission as a default. The window above applies at v0 exactly as it would at v1 — outside its suspension until a second consumer or v1.0.0 (above): a breaking change is a minor bump, never a patch, and wherever the old identifier can be kept working it is kept working for the full window.

v0.3.0 is the first release to act on the window: it removes the identifiers v0.2.0 marked for removal in it, each listed with its replacement under ### Removed in CHANGELOG.md.

Two changes bypass the window, and both are named as such in their entry:

  • A matter.js parity correction. matter.js HEAD is the gold standard for every cluster ID, revision, attribute ID and wire shape in this module. When upstream corrects one, this module follows it in the next release without a window. Holding a value stable because it is stable would mean knowingly shipping a wrong one, and the failure it produces is a silent pairing abort in a controller nobody can attach a debugger to.
  • A security fix that cannot be made without an API change. It ships in the next release, marked ### Security.

What v0 does not excuse: an unannounced break. Every one of these lands in the changelog before a consumer meets it.

How a consumer learns about a break

CHANGELOG.md is the single place. It follows Keep a Changelog, so the headings already carry the meaning:

  • ### Deprecated — the release that marks an identifier. The entry gives the full import path and name, the replacement, and the earliest release the removal may happen in.
  • ### Removed — the release that removes it. The entry repeats the replacement, so a consumer who skipped the deprecation release still finds it here rather than in a diff.
  • ### Changed — behaviour that moved under an unchanged signature. A parity correction lands here and says which matter.js element changed.
  • ### Security — a fix that forced an API change out of band.

A release note carries, for the version it names: every entry from those four headings, and an explicit statement of whether upgrading requires a source change. "No source change required" is a claim worth making when it is true, because it is the only sentence most consumers need to read.

The rule behind all of the above: a break that appears only in a commit message, a doc comment or a diff has not been announced. If it is not in the changelog, it does not ship.

A release pull request (head branch release/*) is also the gate of the certification run: it runs every chip-tool job and certification family the nightly run does, and cannot merge with one of them red (Certifiability).

A guard holds the rule: make apidiff compares every public package with the last release tag (golang.org/x/exp/cmd/apidiff, a tool dependency of the module) and prints the incompatible changes, and make apidiff-check, a CI job, fails when one of them is not named under [Unreleased] in CHANGELOG.md (### Changed, ### Removed or ### Deprecated).

Licence

Apache License 2.0 — see LICENSE and NOTICE (ADR 0023: the same licence as matter.js and connectedhomeip, with their patent grant; v0.4.0 and earlier were released under MIT and stay so). Upstream notices and the dependency licences are recorded in THIRD-PARTY-NOTICES.md. Contributions need the contributor licence agreement in CLA.md, agreed once per account in the first pull request.

About

Matter in pure Go: device and bridge side (cluster servers, OTA, media) and a full commissioner/controller, as an embeddable library. A semantic port of matter.js. Not certified by the Connectivity Standards Alliance.

Topics

Resources

Contributing

Security policy

Stars

3 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages