Repository navigation
Releases: AnastasiyaW/crossweft
Release list
crossweft 0.2.10
Release commit (pin this in CI): 13bbefd0a7bbde9cc3165d74f568b6e9d1be2858
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@13bbefd0a7bbde9cc3165d74f568b6e9d1be2858" # v0.2.10ui_actions: a new guard that follows every UI control (a button's
data-action, a keyboard callback) through the hand-written tables that
dispatch it -- maps, registries, prefix rules -- to its handler and, with
"routes": true, to a route a link declares. A control nobody handles, a
handler no control sends to, and a key bound twice are problems
(ui:<id>:dead|unrouted|orphan|conflict; anallowthat excuses nothing
isstale-allow). A UI request path ending in/is one request, not
every route below it.crossweft actions [--json]
prints each control's chain. The polyglot-shop example gains an admin page
andsmoke/click_smoke.py, which presses every mapped button in Chromium and
waits for its request (with a self-test that must turn red on a handler that
throws).- The
crossweftskill explains theui:problems andcrossweft actions;
after upgrading, re-runcrossweft agents.
crossweft 0.2.9
Release commit (pin this in CI): f127e9d7ac5d249e36f736d6157f07e8f60e1b73
python -m pip install "git+https://github.com/happyin-app/crossweft.git@f127e9d7ac5d249e36f736d6157f07e8f60e1b73" # v0.2.9crossweft validators --incrementalfor the stop hook: a self-test or normal run
that passed last time is reused while everything it observed is unchanged -- the
bytes of the files it read, the directories it listed, the paths it checked, the
environment variables it read, the output of the read-onlygitcommands it ran,
the validator itself and the runtime. The runner learns this by tracing each run
(Python audit hooks, also in Python child processes). A run that starts any other
program, forks, uses a socket, a database driver orctypes, or has a child that
did not report, is never reused; failures are never kept; a kept run expires after
24 hours. The report marks reused rows, says why a kept run ran again (the first
input that changed), and names every run that could not be kept, with the reason. Validators seeCROSSWEFT_VALIDATORS_INCREMENTAL=1. CI runs plain
crossweft validators.goneon a legacy link maps a retired route the server still answers on purpose
({"status": 410, "replaced_by": "<current link>"}): it no longer needs a finding as
route:unmapped, removing the tombstone isroute:gone-unserved, and a client
literal that still names it isroute:gone-called.
crossweft 0.2.8
Release commit (pin this in CI): d00defb4675665e938d2d25866a4bdd2c7098e33
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@d00defb4675665e938d2d25866a4bdd2c7098e33" # v0.2.8- The README,
docs/agents.mdanddocs/enforcing-across-repos.mdnamed 0.2.6 in their
install, clone and CI examples while the package was 0.2.7, so a reader installed the
previous release. They now name this release, and this repository's own map compares
each of those install, clone, CI and pre-commit examples, the README status line and the
Codex plugin manifest with the package version, so these examples can no longer drift
from the release.
crossweft 0.2.7
Release commit (pin this in CI): 417190c90915c0f895ea2944eca780bd626509c5
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@417190c90915c0f895ea2944eca780bd626509c5" # v0.2.7- Built-in hazard rules, opt-in with
"hazards": {"include": [globs]}in
crossweft.json(optionalexclude,rules): script lines that run without
an error and still break what another program reads.cmd-digit-redirect
(echo x=%V%>>fileloses a one-digit value to a stream handle),
empty-to-zero([int]$parts[1],int(x or 0)turn a missing status into 0),
toolchain-env-name(set RC=%ERRORLEVEL%before cmake/cl/msbuild/make) and
glob-length-guard(case??..?*reject branch refuses exactly-N input).
Hits arehazardsproblems keyed by a digest of the line, excusable by a
finding; anincludeglob that names no file is fatal. Planted unsafe and
safe cases run incrossweft self-test; see docs/model-reference.md.
crossweft 0.2.6
What it is
When a product is written in several languages, the costliest bugs live between files. A Go server and a TypeScript client both hold the same API version, the same DTO fields, the same env var names. An agent changes one side, the tests stay green, and the install breaks on a customer's machine.
Crossweft keeps a map of these seams next to the code and checks that both sides agree.
How it works
- The map.
seams/modellists the components, the links between them and, for every value written by hand on both sides, a guard that reads both files. - After every edit. If the agent touches a file that sits on a seam, Crossweft names the file on the other side and the guard that watches it.
- Before finishing.
crossweft checkruns. If a seam disagrees, the hook sends the agent back with what to fix, so "Done" means both sides agree.
It works as a Claude Code plugin (hooks and a skill), a Codex skill, an MCP server for other agents, and a GitHub Action for CI. Python 3.9+, standard library only.
Try it on the demo:
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@v0.2.6"
git clone --branch v0.2.6 --depth 1 https://github.com/AnastasiyaW/crossweft
cd crossweft/examples/polyglot-shop && crossweft checkThe story behind it: https://happyin.work/blog/crossweft-seams/ · project page: https://happyin.work/crossweft/
In this release
- README: a GitHub Action section with a workflow example and the inputs table.
action.yml: a description that says what the check catches.
Release commit (pin this in CI): 8db353a01130c13718ff8eef589dfb9197f11d4d
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@8db353a01130c13718ff8eef589dfb9197f11d4d" # v0.2.6crossweft 0.2.5
What it is
When a product is written in several languages, the costliest bugs live between files. A Go server and a TypeScript client both hold the same API version, the same DTO fields, the same env var names. An agent changes one side, the tests stay green, and the install breaks on a customer's machine.
Crossweft keeps a map of these seams next to the code and checks that both sides agree.
How it works
- The map.
seams/modellists the components, the links between them and, for every value written by hand on both sides, a guard that reads both files. - After every edit. If the agent touches a file that sits on a seam, Crossweft names the file on the other side and the guard that watches it.
- Before finishing.
crossweft checkruns. If a seam disagrees, the hook sends the agent back with what to fix, so "Done" means both sides agree.
It works as a Claude Code plugin (hooks and a skill), a Codex skill, an MCP server for other agents, and a GitHub Action for CI. Python 3.9+, standard library only.
Try it on the demo:
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@v0.2.5"
git clone --branch v0.2.5 --depth 1 https://github.com/AnastasiyaW/crossweft
cd crossweft/examples/polyglot-shop && crossweft checkThe story behind it: https://happyin.work/blog/crossweft-seams/ · project page: https://happyin.work/crossweft/
In this release
- A working contact address for questions and adoption help in the README ("Tell us what broke"); the skill and the issue-form contact link point there.
Release commit (pin this in CI): 8bd4f376833f6dae34186069e2db8519e5948353
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@8bd4f376833f6dae34186069e2db8519e5948353" # v0.2.5crossweft 0.2.4
Release commit (pin this in CI): b19e96ae0c7349149edc18ded2e504202cd592e1
python -m pip install "git+https://github.com/AnastasiyaW/crossweft.git@b19e96ae0c7349149edc18ded2e504202cd592e1" # v0.2.4- The repository moved to
github.com/AnastasiyaW/crossweft; GitHub redirects
the old address. Install commands, plugin manifests, the marketplace entry
and the docs name the new one. - Feedback: issue forms for a problem, an idea and an agent report; the skill
tells an agent, when crossweft itself gets something wrong, to draft a short
report for its user (no private code) and let the user decide whether to
send it; the README says where to write. - README: header and how-it-works images, a release badge that follows the
latest release, and a link to the project page. action.yml: a Marketplace-ready name (Crossweft seam check) and colour.
crossweft 0.2.3
Release commit (pin this in CI): d8a57c9f7710be6dfcebbb9b9ca733e2bdfdd342
python -m pip install "git+https://github.com/happyin-app/crossweft.git@d8a57c9f7710be6dfcebbb9b9ca733e2bdfdd342" # v0.2.3validators.excludeincrossweft.json:{"validate_x.py": "<reason>"}for a
validate_*.pythat is not a suite validator, such as a commit-time gate that
judges one staged change. It is not run, and the report lists it with its
reason. An entry that names no file, has no reason, or is also given a
timeout is an error; excluding every file still fails with "nothing ran".
crossweft 0.2.2
Release commit (pin this in CI): 9cd31dd333dd04fc65b9d47540893fd3d98a9ee6
python -m pip install "git+https://github.com/happyin-app/crossweft.git@9cd31dd333dd04fc65b9d47540893fd3d98a9ee6" # v0.2.2check --incremental:--changedagainst the last commit at which the check
passed in this work tree, plus the paths that were uncommitted then (they
rerun, so reverting an uncommitted file cannot bring back unchecked bytes);
the full check when there is no such commit, another crossweft version or
build recorded it (the record keeps a digest of the engine code), or the map,
config or a joint plugin changed. HEAD and the uncommitted paths are read
before the check runs, so a commit landing meanwhile is never recorded. A pass moves the
commit forward. The record lives in the git directory (per worktree, never
committed). Exclusive with--changed; refused with--format sarif.- The stop hook runs
check --incremental. Measured on a 1,140-file map with
13 joint kinds: full check 385 s; a stop after editing one source file 38 s. joints.sourcesincrossweft.json: the plugin files and the helpers they
import, for ajoints.dirthat also holds unrelated code.--changedthen
falls back to the full check only when one of those files changes (before:
any change underjoints.dir). A plugin that imports a helper from its
directory, or reads a file from it while imported or checked, that neither
sourcesnor the kind's inputs cover is an error
(joints:unlisted-read:<kind>:<path>), so the list cannot go stale silently.
Globs match the way--changedmatches them, part by part.
crossweft 0.2.1
Release commit (pin this in CI; a tag can be moved, a commit cannot): 6001e167056261058564d8f6993026521eb669f5
python -m pip install "git+https://github.com/happyin-app/crossweft.git@6001e167056261058564d8f6993026521eb669f5" # v0.2.1- New transform
go-http-status: a Gonet/httpstatus constant name
(StatusTooManyRequests) becomes its number (429), so the statuses a Go
handler writes can be compared with the numeric statuses a client in another
language accepts. The table is Go'snet/http/status.go; an unknown name stays
as it is and never matches a number, so a guard reading it fails instead of
passing. - A join point takes
within(one capture group), like a set side: the point
reads only those regions, e.g. the default block of a file that also documents
an alternative value. Every match inside the regions still counts, so a drifted
copy inside cannot hide. The regex runs on the whole file (not on a slice)
and only matches lying wholly inside a region count, so^,$,
lookbehind and lookahead see the real text; a
withinthat finds no region fails asanchor:join:<id>:within:<path>. engine.Checker.route_registrations(text, function_prefixes, unscannable=None):
the go-chi route enumeratorcheckuses, as a side-effect-free classmethod,
so a joint-kind plugin that needs the server's routes reuses it instead of
keeping a second scanner. Registrations it cannot name go to the optional
callback.- Docs: install by the release commit in CI (tag in a comment). A tag can be
moved and would change what CI runs.

