Bug fixes, tests, documentation, and focused enhancements are welcome. Spec questions are
welcome too: if SPEC.md and the code disagree, that is a bug in one of them, and saying which
is half the work.
Do not report an exploitable vulnerability in a public issue or pull request. Follow
SECURITY.md to send a private report.
AGENTS.md is the one copy of the things a change here can quietly break — the
golden vectors and why a failing one means the wire format moved, exact canonical encoding,
fail-closed on the money path, and the MCP server holding nothing. It is written for whoever
edits the code, human or model. Read it before your first pull request; it is not restated
here, because a second copy would drift from it.
pnpm only — a stray package-lock.json must not be committed. The version is pinned by
packageManager in package.json, so corepack picks it
up on its own.
pnpm install --frozen-lockfileTurn on the repository's hooks once, in your clone:
git config core.hooksPath .githooksThat is one hook, commit-msg, and it refuses a message carrying a coding-agent session
link. Those URLs resolve for nobody but the account that made them, and a public history
cannot take one back — this repository's history was squashed once to remove them, and the
hook exists so that does not happen twice. Git will not run a hook out of a fresh clone on
its own, which is why the same check also runs on every pull request
(scripts/no-agent-trailers.sh, one definition, two callers).
CI runs exactly these three against the code, in this order (plus the commit-message scan above):
pnpm install --frozen-lockfile
pnpm -r --include-workspace-root build
pnpm -r --include-workspace-root test--include-workspace-root is not optional: the library is the root package (mcp/ is the
only child), so a plain pnpm -r skips it and mcp/ then builds against a stale dist/. The
same reason means you must build before running examples/live-deal.mjs — it imports dist/.
- One problem per pull request. Bug fixes and small documentation improvements can go straight to a pull request; discuss a change to the wire format, the state machine, or the rail interface in an issue first, because those are the things other people's already-posted frames depend on.
- Add tests for behavior that changes. A bug fix should include a regression test that fails without the fix. Prefer assertions on observable behavior over private implementation details.
- Keep
SPEC.mdand the code in agreement, and say in the pull request which one you treated as correct. - Every user-visible change gets a
CHANGELOG.mdentry under[Unreleased], following Keep a Changelog. Leave version bumps and dated release sections to a maintainer. - Avoid unrelated refactors, formatting sweeps, or version bumps in the same pull request.
- New surface on the money path: say what a hostile counterparty gets from it, or say "nothing".
Explain what changes for a caller and why, link related issues, and confirm the three CI commands
pass locally. Keep the branch current with main; address review with additional commits or a
clean rebase. All required checks must pass before merge.
Publishing runs from .github/workflows/release.yml on a v* tag, and holds no registry
token: pnpm exchanges the workflow's OIDC id-token for a short-lived one and attaches
provenance, so there is no long-lived secret in this repository to leak. A fork cannot push
a tag, so there is no route from an untrusted pull request to the registry.
One release:
- Fold
[Unreleased]inCHANGELOG.mdinto a dated section and set the version in bothpackage.jsonandmcp/package.json— the workflow refuses to publish if the tag and the two manifests disagree. - Tag it
vX.Y.Zand push the tag. - Approve the
npmenvironment when it asks.
pnpm -r --include-workspace-root publish runs in dependency order, so @flop-labs/tclk
lands before the MCP server that depends on it, and already-published versions are skipped —
a re-run after a partial failure finishes the release rather than failing on what already
went out.
To rehearse without publishing, run the workflow manually: workflow_dispatch takes the
same path and ends in --dry-run.
Bootstrapping. npm can only attach a trusted publisher to a package that already exists,
so the very first version of each package goes out by hand (pnpm publish, authenticated
locally). After that, configure each package's trusted publisher on npmjs.com — this
repository, workflow release.yml, environment npm — and every later release comes from
the tag.