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.