Skip to content

mentu-ai/webharness-public

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

WebHarness

Deploy to macOS as easily as you deploy to Vercel. Bundle your Next.js app into a .harness file; your users open it with the WebHarness Player — no Apple Developer account, no Xcode, no notarization wait.

npm @mentu/webharness-cli npm @mentu/webharness-sdk npm @mentu/webharness-mcp License

Status: v0.2.0-beta.2 (changelog, release notes).

npx @mentu/webharness-cli init my-app
cd my-app
npx @mentu/webharness-cli dev

Three packages, all on 0.2.0-beta.2:

  • @mentu/webharness-cli — scaffold, dev-loop, build, sign, bundle. Reference →
  • @mentu/webharness-sdk — TypeScript bindings for 22 native capabilities. API reference →
  • @mentu/webharness-mcp — MCP aggregator that lets Claude Code / Cursor / Zed drive every running app. README →

How it works

Your web app (React, Vue, Svelte, vanilla JS)
        ↕  @mentu/webharness-sdk  (TypeScript)
WebHarness shell             (WKWebView + ControlServer)
        ↕  capability bridge
Vault · SQLite · Perception · MCP plugins · ANE · file system

Your web app runs inside a native WKWebView. The @mentu/webharness-sdk gives it typed access to macOS capabilities through a zero-config bridge. No Swift required.

MCP as the plugin system

WebHarness uses the MCP protocol as its plugin system. Any MCP server is a WebHarness plugin — Claude Desktop plugins, Cursor plugins, and Anthropic reference servers all work without modification. Declare what you need in mcp.servers; the runtime proxies calls.

# webharness.yml
mcp:
  servers:
    - name: github
      transport:
        type: bundled
        command: npx
        args: ["-y", "@modelcontextprotocol/server-github"]
      credentials: github_token        # vault key — injected as GITHUB_TOKEN
    - name: filesystem
      transport:
        type: bundled
        command: npx
        args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]

Then from your app:

import { mcp } from '@mentu/webharness-sdk'
const repos = await mcp.call('list_repos', { user: 'me' })
const found = await mcp.discover('read_file')   // any tool from any plugin

This is why the plugin ecosystem is the npm registry, not a private WebHarness store.

Distribution: two models, both shipped

  • Pack Your Ownwebharness pack produces a .app bundle, you sign with your Developer ID, you notarize. Full control, full friction.
  • Fixed Shell Playerwebharness bundle produces a .harness package (zip of harness.json + web assets). End users open it with the Player — no signing, no notarization. v0.2 ships the format and the file-association mechanics; the Player binary and the WebHarness.io service land in v0.3.

See DESIGN-distribution-model.md.

Capability surface

webharness.yml declares what the app may use. The user sees a one-time consent sheet for tier-.sensitive capabilities (deny-defaulted for the red-tier).

capabilities:
  - fs.read
  - fs.write
  - vault.read         # Keychain-backed credential store
  - vault.write
  - sql.query          # Local SQLite
  - sql.exec
  - sql.migrate
  - sql.tables
  - mcp.call           # Talk to declared MCP plugin servers
  - mcp.discover
  - mcp.route
  - perception.observe # Ambient classifier feed
  - notify.send
  - pdf.generate
  - terminal.create    # PTY sessions
  - browser.agent.browse  # Headless Chromium (148 MCP tools)
  - desktop.orchestrate   # AXUIElement + CGEvent
  - ane.embed          # On-device Apple Neural Engine

# Capabilities that require run-time consent (sdk.requestCapability(name))
optional_capabilities:
  - notify.send

Seventeen native capability domains are baked into the runtime: fs, vault, notify, pdf, sql, perception, browser (screenshot + agent), desktop, terminal, vector, ane, model (Apple Intelligence on macOS 26+), mic, sys, agent, network, workflow, and the mcp proxy. Anything beyond that — and the bulk of the agentic ecosystem — comes through MCP plugins declared under mcp.servers.

SDK

import {
  isNative,
  vault,
  mcp,
  perception,
  sql,
  ane,
  model,
  network,
  desktop,
  sys,
  fs,
  notify,
  requestCapability,
} from '@mentu/webharness-sdk'

// Keychain-backed credentials — per-bundle scope
await vault.set('openai', process.env.OPENAI_KEY!)
const { value } = await vault.get('openai')

// Local SQLite — one DB per app bundle
await sql.migrate('CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT)', 1)
const rows = await sql.query('SELECT * FROM notes')

// On-device LLM via Apple Intelligence (macOS 26+ / FoundationModels)
const status = await model.status()
if (status.available) {
  const { text, tokens } = await model.infer('Summarize: ' + emailBody)
}

// Native Accessibility — read UI of any app without MentuDesktopMCP
const apps = await desktop.apps()
const finderButton = await desktop.find({ role: 'AXButton', app: 'Finder' })

// Active network connections via lsof
const flows = await network.flows({ limit: 20 })

// On-device ANE — embeddings, classification, search, OCR
await ane.embed('hello world')

// MCP plugins — any MCP server is callable
const tools = await mcp.discover('repo')
const out = await mcp.call('list_repos', { user: 'me' })

// Run-time consent for an optional_capability declared in webharness.yml
const ok = await requestCapability('notify.send')
if (ok) await notify.send({ title: 'WebHarness', body: 'hi' })

vs Electron / Tauri

Electron Tauri WebHarness
Bundle size ~150MB ~3MB ~0MB (system WKWebView)
Local AI Apple Silicon ANE
Plugin system npm + bespoke Rust crates MCP protocol (any MCP server)
Distribution DIY signing DIY signing .app or .harness (Player)
Backend language Node.js Rust None (JS SDK only)
Platform Any Any macOS

Project structure

webharness/
├── packages/
│   ├── sdk/          @mentu/webharness-sdk — TypeScript, runs in the web app
│   ├── cli/          webharness CLI — init / dev / build / pack / bundle
│   └── runtime/      Swift — WebHarnessHost (shell), WebHarnessRuntime (lib),
│                      WebHarnessRuntimePackager (CFBundleDocumentTypes for
│                      io.webharness.harness)
├── webharness.schema.json   JSON Schema v0.2 (IDE autocomplete)
├── docs/
│   ├── design/       Eight design docs (DESIGN-*.md) — v0.3 work
│   ├── RELEASE-v0.2.md
│   └── CONTEXT-webharness-vision.md
└── CHANGELOG.md

CLI

Ten commands — init, dev, build, pack, bundle, status, call, logs, run, install-player. Full reference + flags + examples in packages/cli/README.md.

webharness init [name] --template default|menubar|spotlight
webharness dev                                # Connect to native shell (live reload)
webharness pack --sign "Developer ID: …" --notarize <profile>
webharness bundle --out MyApp.harness         # Produce a Player package
webharness status                             # List running WebHarness apps
webharness call canary vault.read '{"key":"x"}'

Documentation

Design docs

The eight design docs in docs/design/ capture v0.3 work scoped out of v0.2. Read them before proposing changes to the deferred surfaces. Roll-up index lives in docs/ARCHITECTURE.md.

Requirements

  • macOS 14+ (some capabilities require macOS 26+ — e.g. model.local.*)
  • Node.js 20+

About

WebHarness — native macOS APIs for web apps + MCP plugin host for AI agents. Public source mirror.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors