Commit Graph
154 Commits
Author SHA1 Message Date
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
zooqueenandHanzo Dev b3c34fa7c3 feat(lsp): repo answers from /v1/code/lsp, file stays local
One tool, two planes, picked by data the caller already has: `file` names the
file, `repo` (a git.hanzo.ai slug, optional `rev`) says which world it lives
in. Without `repo` nothing changes — the same language server on the same
tree. With it, the question goes to the indexed corpus behind /v1/code/lsp,
which reaches across a repo's dependencies without checking anything out.

Actions map onto ops: locate carries a relation (definition|reference|type|
implementation) because "where is X" is one question with four answers, not
four routes; hover, symbols, diagnostics and complete stand on their own. The
body is {repo, rev?, path, line, character, relation?} in LSP's own frame —
0-based line, UTF-16 character — shifted from the tool's 1-based `line` at the
same boundary the local plane shifts it.

Credentials and base URL come from the one HanzoApi client every cloud-backed
tool already composes; there is no second client and no second lsp tool. The
actions a plane cannot serve say so up front rather than spawning a server or
calling out — rename/code_action/organize_imports/status need a working tree,
type/implementation/symbols are the index's to answer.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 03:14:53 -07:00
zeekayandHanzo Dev 42c6fbbeaa ci: canonical pair — hanzo.yml + forge caller
github.com has no runner for hanzo-build-linux-amd64, so a caller under
.github/workflows is a gate that can never be scheduled. This is the ~7-line
caller on the plane that can (git.hanzo.ai git-runner fleet), pinned @v1.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 02:37:03 -07:00
zeekayandHanzo Dev c36a1eb1c8 rust/tests: repair the two suites that stopped compiling at HIP-0300
test_shell_tools and test_think_tools have not built since the shell->exec
consolidation, so `cargo test` was red and 46 tests were silently not running.
Nothing here is a new assertion — each change follows the tool's live contract,
read off the published 1.1.22 binary rather than guessed:

  shell   ShellTool -> ExecTool, ProcToolArgs -> ExecToolArgs. Pure rename;
          all 16 pass untouched.
  think   ThinkTool::execute returns Value, not String, and HIP-0300 moved the
          payload under "data". Help reports the tool as "tool", not "name".

Tests whose subject no longer exists are deleted, not rewritten to pass:
critic/review with focus, code_snippets, file_paths and work_description (11);
the timestamp and examples keys (2); action-less auto-detect, which now falls
through to help (1).

browser: playwright_available -> driver_running, its successor since the tool
moved to a CDP driver. That file compiled, so this one was failing, not skipped.

351 pass, 0 fail: lib 223, browser 28, fs 27, search 28, memory 22, shell 16,
think 5, research 2. tests/ is excluded from the package, so 1.1.22's contents
are unchanged and no version bump is warranted.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 14:23:33 -07:00
zeekayandHanzo Dev 57cf89b892 rust: take back hanzo-mcp on crates.io at 1.1.22
The name has changed hands four times across three codebases:
  1.1.10, 1.1.11  rmcp client shim
  0.1.0,  1.1.21  rust-sdk re-export facade (ships zero tools)
  1.1.12          this repo, the only lineage with working tools

1.1.21 is what cargo add resolves today: no binary, and its
ToolRegistry::with_defaults() returns [] with the server feature on.
Publish this tree instead, above it, so the name carries the server.

Description said 'blockchain'; there is no blockchain tool. It now
names the 15 tools the registry actually serves.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-05 14:06:58 -07:00
zooqueenandHanzo Dev d0e89b9bf7 feat(rust): research — the /v1/ask answer engine as one tool
Deep research is a MODE of the one door (POST /v1/ask, mode=research), not a
second endpoint and not a client-side loop: the plan → search → read → rank →
synthesize → cite pass runs server-side where it is bounded and billed. The
tool sends `{q,mode}` with `Accept: text/event-stream` and folds the stream
into one cited answer plus the sources behind it.

HanzoApi gains `events()` — POST over SSE — so streaming lives with the other
credentials-and-base-URL knowledge instead of beside a tool, and `frames()`
decodes a body into its `data:` payloads. Both are the shared `@hanzo/ai`
SearchEvent contract: data-only JSON that self-describes via `type`, with the
terminal `[DONE]` a marker rather than an event. Bearer attachment collapses
into one `auth()` now that two request paths need it.

`research` sits beside `web_search` and `web_read` because they are ONE web
capability at three depths — a snippet, a page, a report — so the existing
`ToolsConfig::web_search` flag governs all three and no second flag appears.
A mode this door does not open (`search`, `news`) is refused rather than
silently answered: a wrong answer is worse than an error.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 22:50:50 -07:00
zooqueenandHanzo Dev 6182d0d800 feat(tools): tracker_* — the shared board, so an agent can report its own work
An agent could already keep a todo list (`tasks`), but only on its own disk.
Nothing here reached the board a human looks at, so "what is this agent doing"
had no answer outside the agent. These four tools are the cloud /v1/tracker
surface — the ONE work-item primitive — as MCP tools.

They are deliberately NOT called tasks_*. Three planes are easy to braid and
cloud apps/tracker/contract.go is law about it: a tracker Issue is a work item,
hanzoai/tasks is durable async execution, and the local `tasks` tool is a
private file at ~/.hanzo/todos.json. Naming these tasks_* would have collided
with that third one and pointed callers at the plane nobody can see.

Linking a run needed no new field. An agent's run is a SESSION — "mission" is
not modeled anywhere in the fleet — and the tracker contract already defines
extRef as "a link INTO another plane", so `session` writes the anchor
`session:<id>` and hanzo.app renders that session's live status on the row.
tracker_create defaults source to agent, because the board's ?source=agent
filter is only true if agents say so.

Cloud's own refusal reaches the caller verbatim — "unknown status filter" is
worth more to an agent than a generic failure — and the org is never sent: it
is minted server-side from the bearer, and a tool that sends one is a tool
asking to be trusted about tenancy.

NOTE: the jest suite cannot RUN on main right now — TypeScript 7.0.2 is
installed and ts-jest 29.4.6 cannot read its compiler API, so all 18 suites
fail to load. That break predates this commit and is orthogonal to it (verified
on a clean origin/main checkout). These tools were verified twice: 20 jest tests
green under the TS 5 toolchain, and 11 runtime checks through the shipped
esbuild bundle under main's current dependency state.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 21:57:27 -07:00
zeekayandHanzo Dev e4b7edbb51 Point every Discord invite at the current Hanzo server (discord.gg/CJCyAsm9Vr)
Co-authored-by: Hanzo Dev <[email protected]>
2026-08-04 21:48:16 -07:00