Commit Graph
161 Commits
Author SHA1 Message Date
zeekay 8a90c75bfd CI, publish and release also run from .hanzo/workflows, on the forge, where Actions is now on for this mirror.
Hanzo CI/CD / test (linux-amd64) (push) Skipped
Hanzo CI/CD / test (linux-arm64) (push) Skipped
Hanzo CI/CD / test-advisory (push) Skipped
Hanzo CI/CD / cicd (push) Successful in 1m29s
publish / publish (push) Successful in 1m0s
Hanzo CI/CD / test-amd64 (push) Successful in 1m48s
CI/CD / cicd (push) Successful in 3m21s
v2.4.11
2026-09-28 18:41:09 -07:00
zeekay e63e2b3e8c examples/kai.ts starts the server over stdio as a client does and asks kai_choice once. 2026-09-28 15:35:10 -07:00
zeekay 8d13859eb0 The kai tools steer a yes/no to a choice whose labels name the outcomes, which Kai answers better than yes and no. 2026-09-28 15:13:12 -07:00
zeekay 0c324b7c18 Publish, CI and release run from .github/workflows, the only directory the hanzoai org runners read. 2026-09-28 14:46:56 -07:00
zeekay e1f6a85d42 The kai tools cap no label or level count, since /v1/decisions caps none. 2026-09-28 14:46:36 -07:00
zeekay e33c38f0a2 The kai tools follow the frozen decision contract: instructions optional, 1 to 100 questions, 2 to 255 labels, 1 to 10 levels, and a noul's confidence. 2026-09-28 14:41:35 -07:00
zeekay 30fafe2616 kai_decide, kai_choice, kai_score and kai_noul ask Kai typed questions on /v1/decisions, in @hanzo/mcp 2.4.11 2026-09-28 14:31:22 -07:00
zeekayandHanzo Dev 201cdd0adc LLM.md is the one committed guide; CLAUDE.md, AGENTS.md and GEMINI.md are local links to it
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-24 15:46:17 -07:00
zeekayandHanzo Dev 5d15d811d1 Publish and CI live in .hanzo/workflows, where the forge looks
publish / publish (push) Successful in 59s
Hanzo CI/CD / test (linux-amd64) (push) Successful in 2m13s
Hanzo CI/CD / test (linux-arm64) (push) Successful in 5m15s
Hanzo CI/CD / cicd (push) Successful in 2m5s
CI/CD / cicd (push) Successful in 7m49s
The forge runs the first of .hanzo/workflows and .github/workflows that
exists. release.yml created .hanzo/workflows on 09-10, and from then on
publish.yml and cicd.yml never ran: @hanzo/mcp 2.4.10 sat on main while
npm served 2.4.9. All three lanes are in one directory now.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 18:55:38 -07:00
zeekayandHanzo Dev e7921ba12f hanzo reads what an action takes, and sends args as given
describe was filtered out of the hanzo tool's resources, and the default
surface has no other tool that reaches it, so a model there could list a
resource's actions but not learn what one takes. It is a resource again:
hanzo(resource="describe", args={subsystem, op}), and a resource's action
list points at it.

Arguments ride in args, one object. A string was spread into
{"0": "{", ...}, and a key beside args, input among them, was merged in as an
argument; both reached the fleet as some other call. Both are now refused as
INVALID_ARGS before anything is sent, and the data alias is gone.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 11:09:52 -07:00
zeekayandHanzo Dev a0c3a2d05b grep's test reads the description the tool now carries
70a0a04 put tgrep first in the grep tool's description and left the test
holding the old words, so the suite failed on main.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 05:37:21 -07:00
zeekayandHanzo Dev a03f7e6820 The graph is on the surface, and hanzo reaches it
The catalog is regenerated from cloud (plugin/gen-mcp-catalog): the graph tool
now carries all thirteen operations, answer, communities, diff, erase, extract,
ingest and path among them, and the Rust crate's copy is synced from it.

The hanzo tool sent {resource, action, ...} to a subsystem handler that reads
{op, input}, so every call from the default surface reached the fleet with no
op. It now sends {op: action, input: args}, the shape the Rust runtime sends,
lists a resource's actions when none is named, and offers only subsystems.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-23 05:37:21 -07:00
zeekayandHanzo Dev 6355e41558 @hanzo/mcp 2.4.10
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:31 -07:00
zeekayandHanzo Dev 7dac625d9a --core-only, list-tools and install --claude-code do what they say
--core-only set enableCore, which the unified surface ignores; it now offers the core group, and serve and list-tools read their flags through one function. list-tools printed four headers for tools that no longer exist and none of the 22; it now lists each tool under its group. install --claude-code wrote ~/.config/claude-code/mcp.json, which Claude Code does not read; it now runs claude mcp add --scope user. The smoke checks all three against dist/cli.js.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:31 -07:00
zeekayandHanzo Dev b5ca2ba8f7 Typecheck again: search asks for rg through onPath
bad040d replaced hasRipgrep with searcher and left one caller, so tsc --noEmit failed before publish could build.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:30 -07:00
zeekayandHanzo Dev 87d4150032 Install from the lockfile again
package.json pins typescript 7.0.2 and the lockfile still said ^7.0.2, so pnpm install --frozen-lockfile refused and publish stopped there.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 13:44:30 -07:00
zeekayandHanzo Dev bd0511890f The README registers the server the way that works, and lists its tools
The README said `npx -y @hanzo/mcp serve` runs an unrelated `serve`
package. With npm 11 it starts this server, and it is the form
`claude mcp add` writes; both forms answered initialize and tools/list
the same way from an empty npm cache, and claude mcp list reports the
added server connected.

The tool section now lists what serve offers, in the groups
src/tools/unified/index.ts defines, and gives the pipe that prints the
names. The "13 tools" and "260+" counts, a --legacy flag the CLI does
not have, the installer steps and the CI claims are gone: list-tools
prints category headers with no tools under them, install --claude-code
writes a file Claude Code does not read, and no workflow runs
smoke-mcp.mjs.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-11 11:44:09 -07:00
zeekayandHanzo Dev 313702d178 The release lane belongs on the native CI, not on GitHub
GitHub Actions is switched off for this repository on purpose — the API
reports enabled=false — so the lane I put under .github/ registered, showed as
active, and could never run. A pipeline that looks alive and does nothing is
worse than one that is plainly absent.

.hanzo/workflows is the native path: git.hanzo.ai runs it on our own fleet and
cd.hanzo.ai delivers. The runner labels follow the canonical <org>-build-<os>-<arch>
form, including hanzo-build-darwin-arm64, which is the target that was never
published and the reason for this lane.

The matrix key is `runner` rather than `on`. YAML 1.1 reads a bare `on` as the
boolean true, so as a key it comes back as True in anything that parses this
file — including the checks that read it.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 20:18:21 -07:00
zeekayandHanzo Dev b31f1113af Open the release before four jobs try to
gh release upload attaches to a release that exists. With the matrix creating
it, four jobs race and three lose — so one job opens it and the builds wait.

Idempotent on purpose: a re-run of a tag that already has a release attaches to
it rather than failing, which is what makes a retry after one target fails a
safe thing to do.

Co-authored-by: Hanzo Dev <[email protected]>
rust-v1.1.24
2026-09-10 20:13:33 -07:00
zeekayandHanzo Dev 318d998101 Build hanzo-mcp for every target the installer offers
hanzo.sh offers `mcp` as a native download and names five published targets.
Nothing in this repository built any of them: hanzo.yml declares a TypeScript
gate, publish.yml ships the npm package, and the tarballs on the last release
covered Linux alone. On macOS the installer asked for a file nobody had built.

So this lane builds the Rust crate — the one whose Cargo.toml calls itself
hanzo-mcp — on the rust-v* tags it is already released under, and attaches each
tarball with the checksum the installer refuses to install without.

Both macOS targets build on the arm64 machine, because the Apple toolchain
cross-compiles to x86_64 without a second host.

fail-fast is off. One target failing leaves the others published, which is a
missing file somebody can chase; fail-fast leaves an empty release, which is an
install that breaks for everyone.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 20:10:47 -07:00
zeekayandHanzo Dev 70a0a046bf Prefer tgrep where the tree carries an index
Trigram index prunes files a query cannot match: 23ms against ripgrep's 78ms
for an absent symbol, which is most of what a search asks. It loses where many
files match (128ms against 78ms), and with no index it scans everything and is
slower than plain grep — so the index is the condition, not the binary.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-10 17:25:10 -07:00
zeekayandHanzo Dev 2171304110 go 1.26.8
One toolchain across the estate. The tree carried 1.26.0, .1, .3, .4 and .5
at once, so which compiler built a binary depended on which repo it came
from.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 23:53:37 -07:00
zeekayandHanzo Dev e1af6af4f4 Move the workflows to .github/workflows
The forge reads .github/workflows natively and github.com reads nothing else,
so one directory serves both planes instead of two conventions that disagree
about which one is live. The reusable in hanzoai/ci already lives there, so a
caller naming that path now resolves to a file that exists.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 19:00:20 -07:00
zeekayandHanzo Dev f24a1aafad ci: a runner label names the platform, not the org
hanzo-build-linux-amd64, lux-build-linux-amd64, zoo-build-linux-amd64 and
every other org-prefixed spelling all meant the same machine. Which org a
job belongs to does not change which host can build it, so the org bought
one pool name per org per arch and each could go stale on its own -- the
evo host alone answered to fourteen names for one label.

One vocabulary now: linux-amd64, linux-arm64, macos-arm64, win-amd64. The
generic labels every plain workflow uses (ubuntu-latest, self-hosted) are
untouched, so naive CI keeps working.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 12:09:48 -07:00
zeekayandHanzo Dev fea24fa037 fix: call the pipeline at the address it actually lives
hanzoai/ci keeps the reusable at .github/workflows/build.yml — the one path
both planes resolve, since github.com reads a reusable only from there and the
forge reads it too. The v1 tag moved with it, so a caller still naming
.hanzo/workflows/build.yml asks for a blob that is not in the tree:

  InsertRun: read hanzoai/ci@v1:.hanzo/workflows/build.yml: object does not exist

The caller itself stays at .hanzo/workflows/cicd.yml on purpose: github.com has
no runner for these labels, so a caller placed there could never be scheduled.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 01:14:29 -07:00
zeekay 3b694c1f9e fix(rust): include cloud catalog in published MCP crate 2026-09-06 02:56:12 -07:00
zeekay 1d741575c8 Follow the cloud surface through the git rename 2026-09-03 12:10:09 -07:00
zeekay 5bde2a515d Pin react, next and typescript to the estate versions
The ranges already admitted them; naming the version is what stops one
repo drifting to a different resolution than its neighbours.
2026-09-03 04:26:25 -07:00
zeekay 1bcb6b0b1a the face is Zen, and it ships from @hanzo/font
One family. Font stacks name Zen and fall back to the native faces, tokens
name the role rather than a face, and the packages that used to supply a
face now point at @hanzo/font.

Self-hosted @font-face blocks are removed rather than renamed: rewriting the
family in one would leave a src pointing at a file this repo no longer ships.
@hanzo/font carries the binaries and declares the faces, so the local copies
go with the declaration that used them.

Comments naming a face we no longer use are deleted, not reworded.
2026-09-01 13:30:05 -07:00
zeekay 48a91758a9 Merge the hand-written cloud surface's last changes
The two lines had diverged on what this client offers: a hand-written tool
naming seven resources against four hosts, or the surface cloud generates
from its own typed operations. The generated one wins, and not by
preference — cloud's gen-mcp-catalog writes src/tools/catalog.json into
this repo, so the fleet already treats it as the destination.

hanzo-cloud.ts stays deleted and the Rust tool keeps reading the catalog.
The iam commits improved a `call` helper that dialled a host per service;
the catalog-driven path takes every address from the document and answers
through the error envelope, so what those commits were correcting is gone
rather than reverted. The hero card's font stack came across untouched.

384 JS tests, 51 Rust tests, typecheck clean.
2026-09-01 09:48:02 -07:00
zeekay c724ae360a Let the tests run again
Every suite had stopped executing. ts-jest peers on `typescript >=4.3 <7`
and this repo builds against 7, so all twenty files died inside ConfigSet
with "Cannot read properties of undefined (reading 'fileExists')" — twenty
failures, zero tests, and nothing to read them by because the push gate
deliberately runs typecheck and build rather than jest.

swc transforms instead: it strips types rather than asking the compiler
to, so it has no TypeScript version to disagree with, and `tsc --noEmit`
already answers the question ts-jest was answering twice.

Running as real ESM then exposed what the CommonJS fallback had hidden.
jest.mock does not hoist there, so a static import binds the real module
and the suite fails on `mockReturnValue is not a function` — an absent
mock reported as a broken one. The search, autogui and ui suites now
register through unstable_mockModule and import after it. One of them had
never mocked fs at all: it cast fs.promises to a mocked type and called
mockImplementation on the real module.

384 tests, twenty suites, all passing.
2026-09-01 09:42:54 -07:00
zeekay 0e21522f6a Carry the ci subsystem and the team messages ops
Regenerated by cloud's gen-mcp-catalog, which writes this file and its
siblings from the fleet's own typed operations. 115 subsystems, 1425
operations.
2026-09-01 02:26:09 -07:00
zeekay 914af987d1 Let cloud write the catalog, and drop the second generator 2026-08-31 23:42:26 -07:00
zeekay 78e75a6488 Write every runtime's catalog in one pass
Three runtimes carry the file and each was refreshed on its own, which is how
they come to disagree. One run writes them all; a sibling repo that is not
checked out is skipped rather than created.
2026-08-30 17:05:43 -07:00
zeekay 94d8398f1a Drop the last /api/ address, and make the mode tests take turns
The registry fallback asked ui.hanzo.ai/api/registry, which 301s to a 404 — so a
dead address stood in for a second chance nobody had. The primary serves; the
fallback is gone rather than moved, because /v1/registry is not served either and
pointing a client at an address the estate does not answer is the same defect
with a better prefix.

The mode tests raced a process-wide singleton: one activates minimal while
another activates guido and reads it back, and cargo runs them in threads of one
process. Three runs gave ok, ok, FAILED. They share a lock now.
2026-08-30 16:15:03 -07:00
zeekay 0a5f63f352 Read the same catalog from Rust
The runtimes are said to mirror one another, and this one listed ten services
against the fleet's 114. Two of the ten had been left behind, and the commerce
base was api.hanzo.ai/api/v1 — an /api/ prefix nothing serves.

Nine routers over four hosts become one dispatch to the single endpoint, and the
service list becomes a read of the file the TypeScript runtime already embeds.

The aliases are removed rather than repointed: three of the four named the old
surface, so they mapped a caller off the API. Spelling is still normalised.
2026-08-30 16:05:35 -07:00
zeekay bb0ba82020 Generate the cloud surface instead of writing it
The seven resources this offered had drifted from the fleet it names: paas is
platform, storage is s3, auth folded into iam, and iam alone carries 97
operations against the handful the hand-written tool reached. It also dialled
four hosts for one API.

The names come from cloud's typed operations now, so this client cannot come to
disagree with the API about what exists. The withholding rule is asked of cloud
rather than restated here — a client deriving its set from the raw catalog offers
what the fleet refuses.

The default surface is unchanged at 22 tools; the fleet sits behind hanzo, whose
resource enum is derived rather than listed.
2026-08-30 15:57:28 -07:00
zeekay 472bafcf7f the job asks for its runner the way the fleet answers
runs-on was a bare scalar. Jobs written that way queue and are never
picked up — link and quest have waited since 10 August, painter since the
5th, none of them with a single success — while repos writing the same
label as a sequence drain within seconds of a push on the same fleet.

Same label, same runners, different shape. It fails silently: nothing errors,
the job simply never starts, so the lane looks configured and does nothing.
2026-08-29 13:31:32 -07:00
zeekay d76fbebc7c Name Zen in the hero card's font stack
The social card asked for Inter first. That is not a face this estate
licenses, ships or ever drew, so a renderer with Inter installed painted
the wrong face and one without it silently fell through to system-ui.
Zen leads now; the same tail follows it.
2026-08-28 11:37:28 -07:00
zeekayandHanzo Dev 63198ee88b iam: pass the scope through, and let the server's refusal speak
Which list routes insist on an owner is the server's rule, and it moves. The
deployed binary requires one on users, sessions and applications and not on
roles, permissions, providers, invitations, tokens or audit-logs; the change
that resolves a listing's tenant centrally is written and unreleased.

So nothing here keeps a copy of that rule. `apps` no longer refuses a missing
owner before asking, and no description promises that leaving it off makes the
credential decide — today that answers 400, carrying the reason, which the
transport already surfaces.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-24 03:44:00 -07:00
zeekayandHanzo Dev 08159273e4 iam: address identity by path under /v1/iam
Users, organizations, roles, applications, providers, permissions,
invitations, tokens, sessions and audit rows are addressed as
/v1/iam/{plural} for a list and /v1/iam/{plural}/{owner}/{name} for a row,
in both the Rust `hanzo` router and the TypeScript iam/auth tools. `id`
splits into its owner and name path segments and a malformed one is refused
rather than sent. Deleting a user is a DELETE on the row; updating one reads
the row and PUTs {"user": merged}.

`owner` is scope: it goes on the wire only when the caller names one, and the
server resolves the rest from the credential. /v1/iam/applications is the one
list that requires it, and asks.

A non-2xx answer is now an error carrying its status and reason — RFC 9457
`detail`, else the envelope `msg`, else `title` — so KMS, PaaS and IAM
refusals surface instead of reading as data. Tests cover the row address, the
id split, and a problem+json refusal against a local listener.

Identity questions belong to the iam service alone, so paas no longer
duplicates users/orgs/roles. Actions with no address behind them (enforce,
system_info, health, mfa status) are gone.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-24 03:26:38 -07:00
zeekay 7d3b47ffba carry the github copy's 1 commits onto the forge
This repo is written on git.hanzo.ai and mirrored to github.com, and the two had drifted apart — 1 commits here the mirror lacked, 1 there this host lacked. Merging rather than overwriting so neither side's work is lost.
2026-08-20 20:59:08 -07:00
zeekay 68747aea94 track the name agents read, so a clone documents itself
LLM.md is the source and stays the source; CLAUDE.md is a symlink to it, so there is
one file and it cannot drift from itself. What changes is that the link is committed
rather than left for each checkout to recreate.

Left untracked, the doc was conditional on a step outside the repo: a fresh clone had
no CLAUDE.md, nothing loaded LLM.md, and an agent worked here having never read what
this repo already explains. Most of the estate already tracks theirs; this is the rest
agreeing with them.
2026-08-20 16:27:45 -07:00
zeekayandHanzo Dev 2e72b6f1f8 fetch: search asks our own API, and says so when it cannot
`fetch:search` scraped html.duckduckgo.com and pulled results out of a regex
over `class="result__title"`. Measured 2026-08-20: that page answers HTTP 202 —
DuckDuckGo's anti-bot challenge — and the markup carries no `result__title` at
all. So the regex matched nothing and the tool returned `{results: [], count: 0}`
for EVERY query: the identical answer it gives when the web genuinely has
nothing. Blind rendered as empty, with no way for a caller to tell them apart,
which is exactly why nobody noticed.

It now asks POST /v1/websearch — the meta-search we ship — reading the base URL
and credential from the same env the tracker tool reads, so the MCP has one way
to reach cloud rather than a second one here.

The failure shape is the point:

  no credential  -> NO_CREDENTIAL, never an empty result list
  cloud refuses  -> its own words verbatim ("sign in to search the web"),
                    because a 401 and a 500 are different problems and
                    flattening both into "search failed" makes an outage
                    look like a bad query
  results        -> carries WHICH ENGINES answered, so a zero-result search
                    with engines listed is a real empty and one with none is
                    a search that did not happen

HONEST GAP: the committed test cannot run. The repo declares typescript ^7.0.2
against ts-jest ^29.4.6, which does not support TS7, so `npx jest` dies in
_resolveTsConfig on "Cannot read properties of undefined (reading 'fileExists')"
— for the pre-existing suites too (edit.test.ts: 0 tests). `tsc --noEmit` is
clean repo-wide; only the transform is dead. The eight assertions were run
against the esbuild-bundled tool instead and all pass; they execute under jest
the moment the toolchain is fixed.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-20 13:48:00 -07:00
zooqueen 197ceef32b LLM.md: where @hanzo/mcp publishes from, and how
This repo is the only publisher of the package; the copy vendored in
hanzoai/extension is a build input and stays private. Records the flat KMS read
and that NPM_TOKEN sits at the org root, so the next reader does not rediscover
it against a 404.
2026-08-19 21:31:19 -07:00
zooqueen 6d5c59c780 publish @hanzo/mcp from its canonical home
/hanzo.yml declared a test block and nothing else, so this repo gated its
commits and never shipped them: 2.4.5, 2.4.6 and 2.4.7 all built green while
npm kept serving 2.4.4.

The lane follows @hanzo/logo, which publishes this way today. It asks the
registry whether the tree is ahead, typechecks and bundles (dist/ is
gitignored, so this is also what fills the tarball), reads NPM_TOKEN from KMS
with the machine identity the fleet already uses, and publishes. A version
already on the registry is skipped, so re-runs are safe.

The copy of this package vendored in hanzoai/extension stays private; it is a
build input, and this is the only place @hanzo/mcp publishes from.
2026-08-19 21:26:12 -07:00
zooqueen c4a13bbf81 serve MCP over stdio and http, and bind no other port
The tool surface reaches a browser through zapd's native host, so the server
side of the localhost WebSocket transport has no counterpart. Removing it
takes `ws` out of the dependencies with it.

2.4.7.
2026-08-19 20:58:55 -07:00
zooqueen 5ff9e09bed serve the tools over streamable http
`serve --transport http` answered "not yet implemented" and exited. It now
serves the streamable http transport through the SDK's StreamableHTTPServer
Transport: a fresh server and transport per request, stateless — no session
header, each POST answered on its own.

The request handlers are registered once, in registerHandlers, and both the
stdio and http paths call it. The tool surface a client sees is the same on
either transport.
v2.4.6
2026-08-14 20:19:23 -07:00
zooqueenandHanzo Dev cf98e8777a auth: the two key shapes are pk- and sk-, and one sentence says so
Cloud's APIKeyPrefixes admits pk- and sk- only (auth_identity.go, 4b030b77).
Every tool here still told the user to set an hk- key, which cloud resolves to
no principal — following the message produced a key that could never
authenticate.

The message is now a single const beside the resolver that mints it, so the
seven tools that report it cannot drift apart again. Resolution order is
untouched: HANZO_API_KEY, then ~/.hanzo/config.json .apiKey.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-08 14:59:50 -07:00
zeekay b1281cd582 initialize is a negotiation, so answer the revision the client asked for
The server replied "2024-11-05" to every initialize, whatever the client asked
for. `hanzo dev` asks for 2025-06-18 and refuses a server that answers anything
else, so it reported `MCP server hanzo failed to start` — in an image where the
binary was on PATH, `dev mcp list` showed it registered, and a hand-written
handshake got 29 tools back. Everything that looked at the server passed;
nothing that PAIRED it with an agent worked.

Negotiation is the whole fix: echo the requested revision when it is one we
serve, answer our newest when it is not and let the client decide. The three
listed revisions are the ones this server can actually serve — initialize,
tools/list and tools/call are unchanged across them, and what the later ones add
is optional and unadvertised. A client pinned to the original revision keeps
getting it, which is the point of negotiating rather than moving the constant.
rust-v1.1.23
2026-08-07 08:03:05 -07:00