Waymark v0.2 is out. In the first post I introduced it as a local MCP server for C# and NuGet. This one is about what changed, and about how I actually work with it now.

Here is the problem I kept running into. I work on a system made of several services. Each one lives in its own repository, so I had one editor window per service, and one AI agent per window. Each agent knew only its own repository. When a change crossed two services, I was the one carrying the context between them: copying a contract from one chat to another, explaining the same thing three times, remembering which agent knew what.

Waymark v0.2 turns that around. One Claude conversation works across all my services, in C#, Python and TypeScript, with the real package APIs at the versions my lock files pin, and with my own machine at hand. I sit on one screen and approve what matters.

The code is MIT licensed: github.com/patilprashant6792-official/waymark-local

My setup: two windows, one conversation

This is how my screen looks most of the day. Claude on the left, the Waymark admin app on the right.

Screenshot 1: Claude chat on the left, the Waymark dashboard on the right: live log, recent calls, packages, the code index tile showing C#, Python, JavaScript and TypeScript files

On the left I talk to Claude like I would to a colleague who has my machine in front of them. On the right I watch what it does. Every tool call appears in the live log as it happens. Anything that changes a file, runs my code or leaves the machine waits for me on an approval card, and I click Approve or Deny.

A normal hour looks like this:

  • "The orders service started returning a new field. Find every place in the web app and the billing service that reads that response." Claude searches all three workspaces in one call.
  • "Add the field to the TypeScript type and the Python model, then run both test suites." It edits both, asks to run pytest and the npm test script, and I approve.
  • "Install the GitHub CLI on this machine." It writes a short PowerShell script; I read it on the card, approve it, and it runs.
  • "What does DataFrame.join take in the Polars version we use?" It reads the real package at the version in our lock file, instead of guessing.

I never switch windows to tell one agent what another one learned. There is only one agent.

One orchestrator, many workspaces

In Waymark a workspace is a folder you hand to Claude: a repository, a service, or even an empty folder where you want it to start something new. You add as many as you like on the Workspaces page, and Claude is the one agent that moves between them.

What that gives you in practice:

  • Search across all of them at once. code_search and code_skeleton accept * for every workspace, so a C# backend and a Python service are searched together. Names cross language boundaries differently (TotalAmount in C#, totalAmount in JSON, total_amount in Python), and Claude is told to search for each spelling.
  • Move code between them without retyping it. The file tools copy a line range, a file or a whole folder from one workspace into another on the server side, so Claude does not spend tokens writing the code out again. A preview (dryRun) shows what would be written first, and the build checks the result.
  • Different rules per workspace. Every command gate (Off, Ask or Auto) can be set for all workspaces or for one. My scratch project builds and tests on its own; my main service asks before every test run.

You set this up once:

  1. Open Workspaces, click Add, pick the folder. Waymark shows what it found: solutions, Python and Node projects, the package manager, how many files of each language.
  2. Repeat for each service.
  3. In Claude, ask: "List my Waymark workspaces and give me an overview of each."

Screenshot 2: the Workspaces page with 1 workspace and their language chips

Python and TypeScript, read by structure

In v0.1 only C# was indexed. Now Python and TypeScript/JavaScript are too. C# is still read with Roslyn; Python, TypeScript and JavaScript are read with tree-sitter. Both only parse: nothing is compiled, imported or run.

The tools did not change, only what they understand. Claude works from broad to narrow the same way in every language:

  1. code_skeleton: the folder tree, plus every project's dependencies with the exact version its lock file pins (uv.lock, package-lock.json, a .csproj).
  2. code_search: classes, functions, type aliases and decorators by name, ranked.
  3. code_outline: what a file contains, without the bodies.
  4. code_method: one function in full, with real line numbers that go straight into an edit.

Each language is mapped to the same ideas. A Python class is a type, a Protocol is an interface, a decorator counts as an attribute, a docstring is the summary, and the module is the dotted path. In TypeScript, interfaces, enums, type aliases and namespaces are types, an arrow-function constant is a function, and a JSDoc comment is the summary.

Real packages from PyPI and npm

This is still the part I care about most. An assistant writes the library call it remembers, and for a library that moved between versions that call may not exist in yours. In v0.1 Waymark fixed that for NuGet. Now the same four tools cover three ecosystems, picked with one argument:

NuGet PyPI npm
Read from the compiled assembly the wheel, plus the stub package when the library has no types the declaration files, else @types, else the JavaScript
Version from the .csproj the lock file (uv.lock, poetry.lock, pdm.lock) the lock file (package-lock.json, pnpm-lock.yaml, yarn.lock)
Docs shown XML comments docstrings JSDoc

Nothing is installed, imported or run. The package is downloaded over https, its integrity hash is checked where the registry publishes one, it is read by syntax, indexed on your PC, and the download is deleted.

The rule Claude is taught is the same as before: a member that was not confirmed at your locked version does not exist. For how to use it, it reads the README or the docs, and prose never overrides a confirmed signature.

Screenshot 3: the Packages page with the NuGet / PyPI / npm filter, showing zod, polars and a NuGet package side by side

Build, test, run, and a shell that always asks

Reading code is half the loop. The other half is running it. cmd_dotnet became cmd_project, one tool with actions for all three toolchains:

Toolchain Actions
.NET build, test, format, packages, EF Core, run, and more (unchanged)
Python py_info, py_venv, py_install, py_test, py_lint, py_format, py_typecheck, py_run, py_package_add, py_package_remove, py_list (uv or pip, pytest, ruff, pyright or mypy)
Node node_info, node_install, node_typecheck, node_build, node_test, node_lint, node_script, node_run, node_package_add, node_package_remove, node_list (npm, tsc, your package.json scripts)

Claude never types into a terminal. It fills in a form (an action, options and a one-line purpose) and Waymark builds the real command. The purpose is what I read on the approval card: "Run the test suite after adding the new field."

The Python and Node actions have safety rules you might not expect:

  • Installs run no package code. Python installs take wheels only and never build the project. Node installs are npm ci --ignore-scripts from the lock file. A package that really needs its install script is something I set up myself.
  • A package.json script runs only if it exists there, and its text is shown on the approval card. Options that load extra code (--require, --import, --eval) are refused.
  • npm is started as node npm-cli.js, not through the npm.cmd shim, because cmd.exe would interpret the arguments.
  • Tests, type checks, builds and scripts ask by default. They run code Claude may have just written, and that code runs as me.

And then there is the shell, for everything the typed actions do not cover: installing a CLI, starting a local service, checking a port, cleaning up a folder. cmd_shell takes any PowerShell, cmd or bash script, and every script waits for my approval. It can never be switched to run on its own. I can edit the script on the card before I approve it, and what I approved is what runs. That is how I give Claude my whole machine without giving it my whole machine.

Trying it, or upgrading from v0.1

New install: Windows 10 or 11, git, and a free ngrok account for Claude on the web. Clone the repository, run install.cmd, open http://localhost:47100, add a workspace, and connect Claude with the address the Setup page shows. Python (with uv) and Node.js are optional: they are only needed for the py_ and node_ actions, and py_info and node_info tell you what Waymark found.

One ask

Tell me a PyPI or npm package your assistant keeps getting wrong, with the version you use. I will run it through pkg_find and post what comes back as a reply.