Skip to content

Platform support (Windows · macOS · Linux)

mokata is a first-class citizen on Windows, macOS, and Linux. The core is pure-Python and dependency-free, paths are built with os.path/pathlib (never a hard-coded /), temp files go through tempfile (no /tmp literal), and file I/O is UTF-8 everywhere — so emojis and non-ASCII content write correctly even under Windows' legacy code page.

What's covered

Area Cross-platform behaviour
Hooks Wired as the mokata-hook console entry point (Stage 53b) — a PATH-resolved executable, the same mechanism as the mokata-mcp server. No bare python3. mokata setup pins it to an absolute path in exec form ({"command": …, "args": […]}), which is spawned directly with no shell on any platform. The plugin route can't pin a path (its manifest is static), so it invokes a self-resolving shim, hooks/mokata-hook-launch, under an explicit "shell": "bash" — Git Bash on Windows, and a named error if it is absent. The shim runs the same ladder at hook time and, if nothing resolves, fails loud (exit 1) naming mokata setup claude instead of leaving a silently dead gate. mokata doctor reports any wired hook command that won't resolve. mokata-hook-launch.cmd ships beside the POSIX shim for direct cmd.exe use only — cmd.exe is never a hook shell, so PATHEXT completion of the extension-less path never happens on the hook path.
Statusline The Claude Code statusLine is the same mokata-hook statusline console entry — no shell dependency.
Paths & separators All state, temp_local/, bundle, and dashboard paths use os.path.join; nothing assumes /.
Portable bundles The machine-path-free invariant strips Windows absolute paths (C:\…, UNC \\host\…) and POSIX paths alike — a bundle built on one OS resumes cleanly on another.
Usernames Provenance/author fields resolve via getpass.getuser(), which reads %USERNAME% on Windows (not just $USER).
Encoding / line endings Files are read/written as UTF-8; line-oriented parsing uses splitlines(), tolerant of LF and CRLF.

launch.sh remains a POSIX last-resort fallback only — used solely by a pure plugin-without-pip install where the mokata-hook console script isn't present. The normal, pip-installed path never touches it.

Harness support — only Claude Code wires hooks

Cross-platform is not the same question as cross-harness. mokata's hooks are a Claude Code capability: claude is the only harness that declares hooks in the capability matrix (mokata harness).

Harness commands hooks context injection subagents
claude
cowork
codex · cursor · copilot · windsurf · gemini
aider

What that means concretely: on every harness except Claude Code the gate-guard is never wired, so the run-state gates (approach-approval, spec-persisted, no-code-without-failing-test, spec-scope) enforce nothing there — they degrade with a clear message rather than pretend. The secret-guard is the same hook mechanism, so it too is only enforced where hooks is declared; mokata's other secret layers (the gated CLI/MCP write path) still hard-block. The engine itself is harness-agnostic: a missing capability degrades clearly, never a silent no-op of a gate.

CI coverage

Every push and PR runs the full unit + integration suite on ubuntu-latest and windows-latest, on Python 3.12, across both the jsonschema-present and jsonschema-absent legs. (macOS runners bill at 10× and are dropped from the matrix.) A regression on either OS fails the build.

The declared floor runs on the same gate, not only at release: three further legs pin Python 3.10 — ubuntu × jsonschema-present, ubuntu × jsonschema-absent, and windows × jsonschema-present. They are targeted include entries rather than a version axis, so the floor is covered on both operating systems and both dependency states without doubling the matrix. Every floor leg blocks: none is continue-on-error.

To exercise the floor locally, use the provisioner rather than whatever Python is on your PATH — see running the tests.

Manual-verification leg

Like the live-DB integration leg, behaviour that requires a real Windows process — e.g. an interactive Claude Code session launching a hook on Windows — is proven by the Windows CI matrix leg, not on a contributor's local box. Local test runs assert the same behaviour OS-agnostically (path joins, separator-agnostic basename, the machine-path-free bundle on Windows-style paths, the mokata-hook command shape) so the suite is green on whatever OS you develop on, and the matrix confirms the real Windows run.

A CI runner is not a desktop, and one Windows behaviour is outside what that leg can prove. mokata's attention channel plays a sound on Windows through winsound.MessageBeep. CI can prove the arm is reached and calls what it says it calls; it cannot prove a sound came out. MessageBeep reports nothing about a muted device, an absent audio endpoint or a session with no mixer, and no headless runner has any of those to begin with. The Windows sound arm is therefore called, not verified — no human has yet heard it on a real Windows machine, and this page will say so until one has. Windows ships no visual notification at all; see ux.notify.