workerd / messagechannel
AGENTS.md9.1k starsChanged 8 months agoApache-2.0View on GitHub
An informal specification of MessageChannel and MessagePort as implemented in workerd, derived from, and kept in lockstep with, the test suite in this directory. The tests are the normative artifact. Both the C++ implementation (src/workerd/api/messagechannel.{h,c++}) and the TypeScript implementation (src/per_isolate/messagechannel/messagechannel.ts, behind the TS_MESSAGE_CHANNEL autogate) are covered. The TypeScript classes subclass EventTarget through the seam in src/per_isolate/events/event-target-internals.ts, and both implementations clone messages with the same serializer, so the dispatch and cloning machinery is shared by construction; the divergences are in class…
Trending
More talk lately.about the whole repository
Who's talking about cloudflare/workerd
- A Hacker News story“OS Workerd, Cloudflare's JavaScript/WASM Runtime”Hacker News · Sep 27, 2022 · 27 points
- withastro/astro“Cloudflare adapter returning [object Object]”GitHub · Oct 10, 2025 · 18 reactions
- supabase/supabase-js“The 'cache' field on 'RequestInitializerDict' is not implemented - Cloudflare Workers”GitHub · Mar 28, 2024 · 16 reactions
- NixOS/nixpkgs“Package request: workerd”GitHub · Nov 12, 2024 · 13 reactions
- nodejs/node“src: improve buffer.transcode performance”GitHub · Aug 1, 2024 · 13 reactions
The biggest 5 of 39 mentions linking to the repository that our crawl found. Each line is their own headline.
See all 39
Talked about on GitHub, Bluesky, Hacker News and Stack Overflow (39 times).
On GitHub · 32
- Oct 10, 2025Cloudflare adapter returning [object Object] — withastro/astro18 reactions · 15 comments
- Mar 28, 2024The 'cache' field on 'RequestInitializerDict' is not implemented - Cloudflare Workers — supabase/supabase-js16 reactions · 24 comments
- Nov 12, 2024Package request: workerd — NixOS/nixpkgs13 reactions · 10 comments
- Aug 1, 2024src: improve buffer.transcode performance — nodejs/node13 reactions · 26 comments
- Feb 19, 2024Add Curve25519 — w3c/webcrypto9 reactions · 16 comments
27 more on GitHub
- Nov 3, 2025Optimize TextEncoder::encode — nodejs/performance7 reactions · 33 comments
- Oct 23, 2023🐛 BUG: pages dev output is unnecessarily verbose — cloudflare/workers-sdk7 reactions · 7 comments
- Nov 24, 2025util: improve textencoder encodeInto performance — nodejs/node6 reactions · 8 comments
- Aug 8, 2024Fix fetch adapter in cloudflare workers — axios/axios6 reactions · 1 comment
- May 25, 2024Partially fix #3160 by properly handling resultsFormat query — cloudflare/workers-sdk6 reactions · 12 comments
- Jan 23, 2026src: improve textEncoder encode performance with simdutf — nodejs/node5 reactions · 8 comments
- Jan 19, 2024Implement Vitest testing environment for Miniflare 3 — cloudflare/workers-sdksays it tested it5 reactions · 7 comments
- Nov 28, 2024src,lib: remove the cost of encoding parameter serialization — nodejs/node4 reactions · 3 comments
- Aug 8, 2026deps: bump the npm group in /kanarek-companion with 2 updates — trvny/trvny3 reactions · 4 comments
- Aug 8, 2026deps: bump the npm group in /weather-feed with 3 updates — trvny/trvny3 reactions · 4 comments
- Aug 8, 2026deps: bump the npm group in /mcp/status-mcp with 2 updates — trvny/trvny3 reactions · 4 comments
- Jan 24, 2026build(deps-dev): bump @cloudflare/workers-types from 4.20260123.0 to 4.20260124.0 — magicappdev/magicappdev3 reactions · 5 comments
- Nov 1, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20261029.1 — paglaai/PaglaROUTER2 reactions · 2 comments
- Oct 25, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20261022.1 — paglaai/PaglaROUTER2 reactions · 3 comments
- Oct 18, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20261015.1 — paglaai/PaglaROUTER2 reactions · 3 comments
- Oct 11, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20261008.1 — paglaai/PaglaROUTER2 reactions · 4 comments
- Oct 4, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20261001.1 — paglaai/PaglaROUTER2 reactions · 4 comments
- Sep 27, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20260924.1 — paglaai/PaglaROUTER2 reactions · 4 comments
- Sep 20, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20260917.1 — paglaai/PaglaROUTER2 reactions · 3 comments
- Sep 16, 2026[wrangler] Add Analytics SQL binding support — cloudflare/workers-sdk2 reactions · 4 comments
- Sep 13, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260821.1 to 5.20260910.1 — paglaai/PaglaROUTER2 reactions · 4 comments
- Aug 23, 2026chore(deps-dev): bump @cloudflare/workers-types from 5.20260801.1 to 5.20260821.1 — paglaai/PaglaROUTER2 reactions · 3 comments
- Aug 18, 2026Use GPT-5.6 Terra and Sol for Bonk — cloudflare/vinext2 reactions · 24 comments
- Apr 21, 2026build(deps-dev): Bump @cloudflare/workers-types from 4.20260411.1 to 4.20260421.1 in /workers/auth-api — Trancendos/infinity-adminOS2 reactions · 4 comments
- Apr 14, 2026build(deps-dev): Bump @cloudflare/workers-types from 4.20260411.1 to 4.20260414.1 in /workers/ai-api — Trancendos/infinity-adminOS2 reactions · 4 comments
- Apr 14, 2026build(deps-dev): Bump @cloudflare/workers-types from 4.20260411.1 to 4.20260414.1 in /workers/files-api — Trancendos/infinity-adminOS2 reactions · 4 comments
- Jan 24, 2026build(deps-dev): bump @cloudflare/workers-types from 4.20260123.0 to 4.20260124.0 — magicappdev/templates2 reactions · 2 comments
On Bluesky · 4
- Mar 24, 2026workerd : le runtime JavaScript/Wasm open source de Cloudflare Workers — @news.humancoders.com4 likes and reposts
- Aug 22, 2026Current status: trying to build github.com/cloudflare/w... on various sandbox providers — @jeremymorrell.dev1 likes and repost
- Mar 24, 2026workerd : le runtime JavaScript/Wasm qui propulse Cloudflare Workers est maintenant open source. Basé sur les standards web, il permet… — @humancoders.com1 likes and repost
- Nov 5, 2024Technically workers are open source github.com/cloudflare/w... — @userops.bsky.social1 likes and repost
On Hacker News · 2
- Sep 27, 2022OS Workerd, Cloudflare's JavaScript/WASM Runtime27 points · 2 comments
- Oct 5, 2023Cloudflare workers is adopting Ada URL parser2 points
On Stack Overflow · 1
- Oct 1, 2024How to user KV in cloudflare workers?1 vote
Where files are headingNew AGENTS.md files have more rules about keeping secrets out of the code, and fewer about code style.
Of the AGENTS.md files we read, the 31,542 first seen in the last six months, against the older ones: the kind of rule that gained most share, and the kind that lost most. About files like this in general, not this one, and an estimate, since a kind is a pattern in the words.
In this repository79 other files it gives its agents.
- AGENTS.mdAGENTS.md
- build/AGENTS.mdAGENTS.md
- src/bench/streams/AGENTS.mdAGENTS.md
- src/bench/streams/body/AGENTS.mdAGENTS.md
- src/bench/streams/compression/AGENTS.mdAGENTS.md
- src/bench/streams/digest/AGENTS.mdAGENTS.md
- src/bench/streams/encoding/AGENTS.mdAGENTS.md
- src/bench/streams/identity/AGENTS.mdAGENTS.md
- src/bench/streams/piping/AGENTS.mdAGENTS.md
- src/bench/streams/readable/AGENTS.mdAGENTS.md
- src/bench/streams/readable-byte/AGENTS.mdAGENTS.md
- src/bench/streams/strategies/AGENTS.mdAGENTS.md
- src/bench/streams/transform/AGENTS.mdAGENTS.md
- src/bench/streams/writable/AGENTS.mdAGENTS.md
- src/cloudflare/AGENTS.mdAGENTS.md
- src/node/AGENTS.mdAGENTS.md
- src/per_isolate/AGENTS.mdAGENTS.md
- src/per_isolate/crypto/AGENTS.mdAGENTS.md
- src/per_isolate/events/AGENTS.mdAGENTS.md
- src/per_isolate/webfs/AGENTS.mdAGENTS.md
- src/per_isolate/webstreams/AGENTS.mdAGENTS.md
- src/pyodide/AGENTS.mdAGENTS.md
- src/rust/AGENTS.mdAGENTS.md
- src/rust/cxx/AGENTS.mdAGENTS.md
- src/tests/events/AGENTS.mdAGENTS.md
- src/tests/events/eventsource/AGENTS.mdAGENTS.md
- src/tests/node/AGENTS.mdAGENTS.md
- src/tests/node/http-client/AGENTS.mdAGENTS.md
- src/tests/node/http-server/AGENTS.mdAGENTS.md
- src/tests/node/net/AGENTS.mdAGENTS.md
- src/tests/node/stream/AGENTS.mdAGENTS.md
- src/tests/streams/AGENTS.mdAGENTS.md
- src/tests/streams/cache/AGENTS.mdAGENTS.md
- src/tests/streams/compression/AGENTS.mdAGENTS.md
- src/tests/streams/digest/AGENTS.mdAGENTS.md
- src/tests/streams/encoding/AGENTS.mdAGENTS.md
- src/tests/streams/formdata/AGENTS.mdAGENTS.md
- src/tests/streams/htmlrewriter/AGENTS.mdAGENTS.md
- src/tests/streams/identity/AGENTS.mdAGENTS.md
- src/tests/streams/inspect/AGENTS.mdAGENTS.md
- src/tests/streams/iocontext/AGENTS.mdAGENTS.md
- src/tests/streams/piping/AGENTS.mdAGENTS.md
- src/tests/streams/r2-patterns/AGENTS.mdAGENTS.md
- src/tests/streams/readable/AGENTS.mdAGENTS.md
- src/tests/streams/readable-byte/AGENTS.mdAGENTS.md
- src/tests/streams/scaling/AGENTS.mdAGENTS.md
- src/tests/streams/sockets/AGENTS.mdAGENTS.md
- src/tests/streams/strategies/AGENTS.mdAGENTS.md
- src/tests/streams/transform/AGENTS.mdAGENTS.md
- src/tests/streams/writable/AGENTS.mdAGENTS.md
- src/workerd/api/AGENTS.mdAGENTS.md
- src/workerd/api/crypto/AGENTS.mdAGENTS.md
- src/workerd/api/node/AGENTS.mdAGENTS.md
- src/workerd/api/streams/AGENTS.mdAGENTS.md
- src/workerd/io/AGENTS.mdAGENTS.md
- src/workerd/jsg/AGENTS.mdAGENTS.md
- src/workerd/server/AGENTS.mdAGENTS.md
- src/workerd/util/AGENTS.mdAGENTS.md
- src/wpt/fetch/AGENTS.mdAGENTS.md
- types/AGENTS.mdAGENTS.md
- The first 60 shown.
The file
We split this AGENTS.md into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 41
Every member is brand-checked and throws JSG's illegal-invocation TypeError for any other receiver, an object inheriting from …
≈ “Common” is an estimate: at least 1 in 5 of the 40,246 AGENTS.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
MessageChannel and MessagePort
An informal specification of MessageChannel and MessagePort as implemented
in workerd, derived from, and kept in lockstep with, the test suite in this
directory. The tests are the normative artifact. Both the C++
implementation (src/workerd/api/messagechannel.{h,c++}) and the
TypeScript implementation (src/per_isolate/messagechannel/messagechannel.ts,
behind the TS_MESSAGE_CHANNEL autogate) are covered. The TypeScript
classes subclass EventTarget through the seam in
src/per_isolate/events/event-target-internals.ts, and both
implementations clone messages with the same serializer, so the dispatch
and cloning machinery is shared by construction; the divergences are in
class shape and in the peer bookkeeping.
Interface
[Exposed=Worker]
interface MessageChannel {
constructor();
readonly attribute MessagePort port1; // own data properties, not accessors
readonly attribute MessagePort port2;
};
[Exposed=Worker]
interface MessagePort : EventTarget {
undefined postMessage(any message,
optional (sequence<any> or PostMessageOptions) options);
undefined start();
undefined close();
attribute EventHandler onmessage;
};
dictionary PostMessageOptions { sequence<any> transfer = []; };- The classes are globals under
expose_global_message_channel, and are always reachable throughnode:worker_threads, which hands out the same constructors. new MessagePort()throwsTypeError: Illegal constructor, from a subclass too. MessageChannel is subclassable.- Every member is brand-checked and throws JSG's illegal-invocation
TypeError for any other receiver, an object inheriting from
MessagePort.prototypeincluded. - Methods and accessors are enumerable, like every JSG member; accessor
names and lengths follow
spec_compliant_property_attributes.
Core semantics
- Transfer: unsupported. A non-empty transfer list throws
Error: Transfer list is not supported, after the options and every list element have been read and before the message is serialized. - Cloning: postMessage() structured-clones its message first, so an
uncloneable value throws
DataCloneError(SharedArrayBuffer aTypeError) even on a closed pair, and getters run. The peer is looked for afterwards, so a getter that closes the port drops the message. - Delivery: deferred (never inside postMessage()), in order, as a
trusted MessageEvent whose
sourceandtargetare the receiving port,originnull,portsempty. - The port message queue follows the port's 'message' listeners, as in
Node.js: the first one (onmessage or addEventListener()) starts delivery,
and removing the last, by
removeEventListener(),onceor an AbortSignal, returns the port to queueing.start()starts delivery without a listener, so queued messages go to nobody. Per spec, only onmessage or start() would enable the queue. - onmessage is an HTML event handler attribute: positioned at first
assignment, kept across reassignment, repositioned after being cleared.
A non-callable object is retained and starts the port but is never
called; a primitive clears it. The handler's
thisis the global object. - close() closes both ports and fires a trusted 'close' on each, the peer's first; a throwing 'close' listener's exception escapes close() under every dispatch policy. A closed port is terminal.
- Listener exceptions under
spec_compliant_dispatch_exceptions: each is reported, the remaining listeners run, then the port dispatches a 'messageerror' whosedatais the exception. Without the flag the first throwing listener ends the dispatch and its exception is redispatched as a 'message'; if that throws too, the delivery's reaction rejects, unhandled. - Prototype pollution: delivery and listener bookkeeping call nothing user code can patch.
Compatibility flags
| Flag (enable date) | Selects | Unflagged behavior tested by |
expose_global_message_channel (2025-08-15) | classes as globals | legacyClassesAreNotGlobals, legacyClassesThroughWorkerThreads |
set_tostring_tag (2024-09-26) | [object MessagePort] branding | legacyToStringTag |
spec_compliant_dispatch_exceptions (2026-09-15) | reporting and 'messageerror' | legacyExceptionIsRedispatched, legacyEscapingExceptionIsAnUnhandledRejection |
spec_compliant_property_attributes (dateless) | accessor names and lengths; globals as own properties | the main cells (the -opt-in cells enable it) |
immutable_api_prototypes (dateless) | C++ constructors' prototype non-writable | the main cells (the -opt-in cells enable it) |
The main cells pin the three dated flags on; the legacy cells pin them off
by their disable names, so every cell keeps its @all-compat-flags
variant. nodejs_compat and enable_nodejs_worker_threads_module are
pinned everywhere for node:assert, node:test, node:util and
node:worker_threads.
Divergence ledger (C++ vs TypeScript)
| # | Area | C++ | TypeScript | Pinned in |
| 1 | Constructor static inheritance | getPrototypeOf(MessagePort) === Function.prototype | === EventTarget | prototypeChains, legacyClassesThroughWorkerThreads |
| 2 | Constructors' prototype | writable unless immutable_api_prototypes | never writable | constructorAttributes |
| 3 | Calling a constructor without new | JSG's TypeError | the language's TypeError | constructorsRequireNew |
| 4 | Port whose peer is collected | closed when the peer's destructor runs | closed when it next looks for the peer | not pinned: depends on the collector; both close without a 'close' event |
| 5 | MessagePort.prototype string key order | constructor last | constructor first | prototypeKeys |
| 6 | A proxy for an array as postMessage() options | converted as a dictionary | an array (Array.isArray()) | proxiedArrayOptions |
The TypeScript implementation also deserializes a message whose peer has gone; the work is not observable, so it is not in the ledger.
Assertion catalogue
| Module | Asserts |
api-surface.js | member attributes, names and lengths; key order (#5); prototype chains (#1); constructor attributes (#2); runtime class marks; toStringTag branding; MessageChannel's own port1/port2; globals and node:worker_threads identity |
inspect.js | util.inspect() of a port, a channel and MessagePort.prototype |
construction.js | MessagePort not constructible, from a subclass either; new required (#3); MessageChannel subclassable |
illegal-invocation.js | every member brand-checked against every non-port receiver |
post-message-arguments.js | options conversion errors; accepted empty forms; transfer type; non-empty lists refused; read order; proxied arrays (#6) |
cloning.js | SharedArrayBuffer and uncloneable values; closed pairs still serialize; closing during serialization drops the message; the receiver gets a copy; Blob round trip |
delivery.js | both directions, before and while listening; event shape; deferral and order |
message-event.js | user-constructed MessageEvent with port source and ports |
onmessage.js | default null; positional ordering; repositioning after clearing; non-callable and primitive values; handler receiver |
port-queue.js | starting by listener and by start(); requeueing on removal, once and abort; closed ports terminal; closed pairs drop |
close.js | 'close' on both ports, peer first, idempotent; plain onclose property; throwing 'close' listener escapes |
listener-exceptions.js | spec reporting order, 'messageerror', injected messages; throwing 'messageerror' listener |
gc.js | queued messages survive collection, including during start(); ports survive collection |
pollution.js | delivery under patched Promise.prototype, Array.prototype.push and WeakRef.prototype.deref |
legacy-shape.js | not globals; usable through node:worker_threads (#1); [object Object] |
legacy-listener-exceptions.js | redispatch as 'message'; escaping exception as an unhandled rejection |
which-impl.js | the cell's implementation and the flags the suite branches on |
helpers.js | descriptor attribute strings |
Web Platform Tests
Most of the webmessaging WPTs need ports to be transferable or run under
web workers in HTML files, so only cases from
Channel_postMessage_Blob.any.js and
Channel_postMessage_DataCloneErr.any.js are adapted here (cloning.js).
Known not to pass:
Channel_postMessage_clone_port.any.jsChannel_postMessage_clone_port_error.any.jsChannel_postMessage_ports_readonly_array.any.jsChannel_postMessage_transfer_xsite_incoming_messages.window.jsChannel_postMessage_with_transfer_incoming_messages.any.jsChannel_postMessage_with_transfer_outgoing_messages.any.jsmessage-channels/close-event/garbage-collected.tentative.any.js: per spec, a port's 'close' fires when its peer is collected; neither implementation fires it (ledger #4).
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

