Skip to main content
Glama

Harness-Mesh

Run one coding ticket across Claude Code, OpenAI Codex, DeepSeek Harness, Google Antigravity and ZCode. A ticket owns one isolated Git worktree; individual assignments may fail over between harnesses, models and sessions while the worktree and partial work stay in place.

中文文档 · Security · Docs · Contributing · MIT License

What the product is

Harness-Mesh is a local orchestration layer, shipped as:

  • a Python package (harness_mesh) with a typed data model and SQLite ledger;

  • a CLI, hmesh, for status, model discovery, dispatch, context and patches;

  • an stdio MCP server, hmesh-mcp, exposing 18 tools to a controller harness;

  • a local runtime directory, .harness-mesh/, holding state, worktrees and paged resources.

It does not provide a model, a hosted service, a web UI or a multi-user scheduler. It orchestrates the harness CLIs you already have installed and authenticated on the machine. Prompts and code are sent to those CLIs; the mesh process itself keeps a local ledger and bounded summaries.

Related MCP server: agentbus

Who it is for

  • Developers who use more than one coding harness and want one task queue instead of copying prompts between terminals.

  • Platform and agent-infrastructure engineers who need quota-aware routing, worktree isolation and auditable assignment history.

  • Researchers and reviewers evaluating cross-harness scheduling, failover and shared-context behaviour.

It is not a replacement for a harness's permission model, sandbox, or vendor terms. It assumes you have legitimate access to each CLI and its models.

Scope

In scope

Out of scope

Dynamic discovery of locally authorised models from configuration, environment, live model endpoints and CLI enumeration

Maintaining a fixed or hosted model catalogue

Difficulty tiers plus market-aware routing by task kind, and skill/plugin injection

Training or hosting models

Ticket/Assignment failover on quota exhaustion, unauthorised models, credential failures and transient errors

Multi-tenant authentication, RBAC or billing

Git worktree isolation, dirty-workspace sync, dependency pre-apply and explicit patch application

Merging worktrees automatically without review

Shared project instructions, a cross-harness memory blackboard and dependency context

Uploading project data to a remote service

Claude Code, Codex, DSH, Antigravity and ZCode adapters

Changing a vendor CLI's own protocol beyond the configured template

Requirements

  • Python 3.11+.

  • One or more supported harness CLIs installed and logged in. A harness that Harness-Mesh runs as a worker needs its own command-line login; see Logins: controller versus worker.

  • Git available on PATH for isolated worktrees.

  • macOS is the primary target for the shipped App Bundle paths. Linux/WSL works with binaries on PATH; real-machine tests skip when the macOS bundles are absent.

Install

python3 -m venv .venv
.venv/bin/pip install -e ".[dev]"

Two entry points are installed:

  • hmesh — operator CLI.

  • hmesh-mcp — MCP stdio server.

Optional Antigravity Python SDK support:

.venv/bin/pip install -e ".[antigravity]"

One-command install into desktop harnesses

After installing the Python package, register Harness-Mesh in every detected desktop harness with one command:

cd /path/to/your/project
hmesh install

What it installs:

Harness

Integration

Claude Code

claude mcp add user-scope MCP server

OpenAI Codex / ChatGPT desktop

codex mcp add MCP server in ~/.codex/config.toml

Google Antigravity

agy mcp add MCP server in ~/.gemini/config/mcp_config.json

ZCode

Generates a local MCP plugin + marketplace, registers/installs it through zcode plugins; if the CLI is unavailable, leaves the marketplace ready for the UI

DeepSeek Harness

Adds an @deepseek-ai/dsh-mcp-client entry to ~/.dsh/profiles/{desktop,headless}/cordis.patch.yml (with backup)

Useful options:

hmesh install --dry-run                 # print planned commands/files, change nothing
hmesh install --yes                     # non-interactive install
hmesh install --approve read            # pre-approve 11 read-only MCP tools
hmesh install --harness zcode           # one harness only (repeatable)
hmesh install --workspace /path/project # pin the MCP workspace explicitly
hmesh install --uninstall               # remove integrations

Without --dry-run, hmesh install prints the planned files and commands and asks for confirmation. A non-interactive shell must pass --yes.

MCP tool pre-approvals

Interactive sessions ask before an MCP tool runs. Headless commands such as codex exec and agy -p cannot answer that prompt, so hmesh install writes per-tool allow rules:

hmesh install --approve dispatch   # default: 14 read and dispatch tools
hmesh install --approve read       # 11 read-only tools
hmesh install --approve all        # 16 tools; apply_task_patch and install_integration stay manual
hmesh install --approve none       # write nothing and remove rules written by hmesh

dispatch, the default, approves the eleven read tools plus dispatch_task, parallel_dispatch and cancel_task. Dispatched work runs in an isolated worktree; its changes reach the primary checkout only through apply_task_patch. The four write tools stay manual: apply_task_patch, report_quota_status, update_project_context and install_integration change the primary workspace, shared state or another application's configuration. --approve all pre-approves report_quota_status and update_project_context as well, but apply_task_patch and install_integration are always manual and are never written into a harness allow rule. Independently of harness approvals, the MCP server refuses every write tool under HARNESS_MESH_READ_ONLY=1 and refuses workers the controller-only write tools; hmesh apply and hmesh install apply the same gate.

Harness

File

Rule

Claude Code

~/.claude/settings.json

permissions.allow gains mcp__harness-mesh__<tool>

Codex

~/.codex/config.toml

A managed block holds [mcp_servers.harness-mesh.tools.<tool>] with approval_mode = "approve"

Antigravity

~/.gemini/config/config.json

userSettings.globalPermissionGrants.allow gains mcp(harness-mesh/<tool>)

ZCode, DeepSeek Harness

none

Workers call MCP tools without approval settings

The installer is idempotent. It keeps a <file>.harness-mesh.bak copy before the first edit, writes through a temporary file, re-parses the result and restores the previous bytes if validation fails. Lowering the level or uninstalling removes only entries with the mcp__harness-mesh__ or mcp(harness-mesh/ prefix, plus the Codex managed block; other rules stay in place. --dry-run prints the approval count and each entry without touching files. hmesh doctor reports approved and missing tools against the default dispatch level and changes no files; on Codex, a service-wide default_tools_approval_mode = "approve" counts as covering every tool.

Headless runs cannot answer approval prompts. Measured on the real harnesses (2026-11-01): codex exec denies the MCP call with "approval policy is never" unless the server is approved; agy -p auto-denies it unless permissions.allow holds a matching rule such as mcp(harness-mesh/list_harnesses). The per-tool rules above cover the selected level; the service-wide Codex setting -c 'mcp_servers.harness-mesh.default_tools_approval_mode="approve"' remains a manual alternative that approves every tool. ZCode and DeepSeek Harness workers call the tools without extra configuration, and Claude Code shows the server as connected. Interactive sessions prompt as usual.

ZCode's --scope project still records the marketplace and plugin in the global state files ~/.zcode/cli/plugins/known_marketplaces.json and installed_plugins.json, even though the plugin and its cache are project-scoped. hmesh install --uninstall removes both entries; the matching zcode plugins uninstall and zcode plugins marketplace remove commands do the same by hand.

Restart the desktop application after installation and start a new chat/task. Existing chats may keep a cached tool list. The installer is idempotent; editing an existing DSH entry or re-adding an MCP server replaces the previous registration rather than duplicating it.

When another harness arrives later

Claude Code and Codex are often installed first; ZCode or another supported harness may follow. The two roles need different handling.

Worker. No action. Dispatch re-resolves the binary for every assignment and routing re-checks adapter runnability, so the next ticket can use the new harness. Only the model inventory is cached, for five minutes.

Controller. The harness must have the Mesh MCP server or plugin registered before it can call these tools. Mesh reports the gap and leaves the decision to you:

  • hmesh integrations lists every configured harness as integrated, detected_not_integrated, stale (registered but the command no longer runs), not_detected or ignored.

  • hmesh doctor and hmesh status end with one line naming the detected harness and the install command.

  • Inside a controller conversation, list_harnesses adds integration_hints. The agent explains the hint, calls plan_integration to show the files, approval entries and commands, and calls install_integration only after you agree.

plan_integration returns a plan_id: the first 16 hex characters of a SHA-256 over the normalised plan and the current content of the target files. install_integration recomputes the plan and refuses any id that no longer matches, so editing a config file between review and install forces a new review. It is a write tool; the default dispatch level leaves it for manual approval. Workers are refused through the same lineage resolution as nested dispatch, HARNESS_MESH_READ_ONLY=1 blocks it, and the target harness must restart before its tool list appears.

hmesh integrations ignore zcode stops the reminder and unignore restores it. The command writes only integration.ignore in the Mesh config; it never edits another application's configuration.

Logins: controller versus worker

A harness can play two roles, and each role uses a different login.

Role

Who calls the model

Login it needs

Controller

You, inside the harness, for example the Claude Code desktop app calling the harness-mesh tools

The login the harness application already has

Worker

Harness-Mesh starts the harness command-line tool as a subprocess to run a ticket

The command-line tool's own credentials

The two logins can differ. Measured on macOS with the Claude Code desktop app (2026-11-01): the app was logged in and called every harness-mesh tool as a controller, while the bundled claude command reported loggedIn: false and Not logged in · Please run /login. The desktop app hands credentials to the sessions it hosts through its own channel; no keychain item, credentials file or API key existed for a separately started claude to read. A command-line Claude Code used as a controller is itself the command line, so it needs the command-line login too.

When a worker is not logged in, Harness-Mesh does not fail the ticket. The first attempt returns not_logged_in, the harness circuit opens (hmesh quota shows claude_code/*: state=open reason=not_logged_in), routing skips that harness and the ticket moves to another one, for example Claude models served through Antigravity. Probes run automatically and the circuit closes once the login works.

To use the Claude Code command line as a worker, log in once in a terminal and confirm it:

claude auth login        # or set ANTHROPIC_API_KEY
claude auth status       # loggedIn must be true

The same rule applies to every harness: a worker uses that tool's own login. hmesh status and hmesh quota show which harnesses are usable. Not verified: whether a worker started by a Harness-Mesh server hosted inside the desktop app can inherit the desktop login; on the test machine it could not.

Quick start

# Discover installed harnesses, real CLI versions and authorised models.
hmesh status

# Force the three-layer model discovery and the tier mapping.
hmesh models --refresh

# Inspect quota circuits and waiting tickets.
hmesh quota --probe

# Fetch market prices and evaluation scores, then preview a route.
hmesh market refresh
hmesh market show --unmatched
hmesh route --objective "Design the migration plan" --kind plan

# List indexed SKILL.md files and MCP/plugin manifests.
hmesh skills

# Write and read a shared project fact.
hmesh context set arch.overview "Federated Harness Mesh" --category architecture
hmesh context list

# Print the MCP configuration for a controller harness.
hmesh init-mcp --print

# Dispatch a ticket and inspect the result.
hmesh dispatch --harness deepseek \
  --objective "Create a short design note in docs/mesh.md" \
  --difficulty medium --fallback codex --fallback zcode

hmesh tasks
hmesh read <task_id> diff --limit 4000
hmesh apply <task_id> --strategy patch
hmesh apply <task_id> --strategy copy --force-copy
hmesh doctor

Start the MCP server with background recovery, effects consumption and market refresh (the default):

hmesh-mcp

Disable every background worker for a pure request/response server:

hmesh-mcp --no-monitor

The server reads HARNESS_MESH_WORKSPACE for the primary project root and HARNESS_MESH_CONFIG for an optional YAML configuration. Without that variable the loader reads $XDG_CONFIG_HOME/harness-mesh/config.yaml (usually ~/.config/harness-mesh/config.yaml) and then ~/.harness-mesh/config.yaml.

Supported harnesses

The defaults target the real macOS installations observed on a developer machine. All paths and command templates are configuration, not code.

Harness

Default binary search

Real non-interactive protocol

Model discovery

Claude Code

~/Library/Application Support/Claude/claude-code/*/*/claude.app/Contents/MacOS/claude

claude -p <prompt> --output-format json --model <model> --effort <effort> ...; write mode adds --dangerously-skip-permissions, read-only adds --permission-mode plan, resume adds --resume <id>

~/.claude/cache/model-catalog/*.json, ~/.claude.json, settings, env, /v1/models

OpenAI Codex

/Applications/ChatGPT.app/Contents/Resources/codex-cli/bin/codex and plugin app-server path

codex exec ... --json ...; write mode adds --full-auto, read-only adds --sandbox read-only, reasoning uses -c model_reasoning_effort=...

~/.codex/config.toml, ~/.codex/models_cache.json, env, /v1/models

DeepSeek Harness

/Applications/DeepSeek Harness.app/Contents/Resources/runtime/cli/bin/dsh

dsh --profile headless --patch <overlay> --json <prompt>; generated overlay re-enables local credentials and merges the desktop model/provider row

~/.dsh/profiles/*/cordis.patch.yml, env, optional API, plus the built-in runtime channel

Google Antigravity

/Applications/Gemini.app/Contents/Helpers/agy

agy -p <prompt> --output-format json --model <model> --effort <effort>; write mode adds --dangerously-skip-permissions, read-only --mode plan, resume --conversation <id>

agy models CLI (spinner frames cleaned), local settings, env, Gemini API

ZCode

/Applications/ZCode.app/... wrapped into .harness-mesh/bin/zcode

wrapper runs the Electron binary with the CJS entry and provider config; `zcode -p --cwd --json --mode plan

yolo, resume --resume `

hmesh status returns available: true only when the binary resolves and its version command succeeds. Model lists are runtime data and are never hard-coded.

How it works

Ticket, Assignment and failover

Ticket task_x (one Git worktree)
  ├── Assignment #1  claude_code/claude-opus-<version>   ended_quota
  ├── Assignment #2  codex/gpt-<version>-<variant>             completed
  └── failover_history: quota_exhausted:rate_limit_429
  1. dispatch creates a ticket and an isolated worktree. If the primary checkout has uncommitted files, sync_uncommitted copies them into the worktree and records a baseline commit.

  2. The router selects an authorised, quota-healthy model for the task's difficulty tier and runs one adapter.

  3. On quota exhaustion, an unauthorised model, a harness-wide login failure, or a transient error, it records a ContinuationCheckpoint and creates a new assignment on the next harness/model. The worktree is reused.

  4. Recovery Notes force the next agent to inspect git status and git diff before continuing. The final diff is measured against the baseline commit, so only the ticket's net changes are returned.

  5. Outputs are capped: summary, diff preview and raw logs are bounded; full content is saved as diff, transcript and assignments resources and read page by page with read_task_resource.

Quota policies:

  • failover (default): create a new assignment on the next healthy candidate.

  • wait_and_resume: suspend the ticket as waiting_for_quota and resume it after a real provider probe succeeds.

  • fail: fail immediately.

Circuits are CLOSED / OPEN / HALF_OPEN. A probe makes one deliberately tiny real model call; local configuration alone never closes a quota circuit. A successful assignment also closes it.

Shared project context

  • ProjectContextManager scans AGENTS.md, CLAUDE.md, .harness-mesh/PROJECT_CONTEXT.md, .cursorrules and .github/copilot-instructions.md, with a character budget.

  • update_project_context writes architecture notes, conventions, API contracts, decisions, pitfalls and notes to a SQLite blackboard. Later tickets receive <project_shared_memory>.

  • context_files are rendered as bounded <context_file_previews> so the child agent does not start with a blind search.

  • depends_on injects upstream summaries, modified files and diffs as <upstream_task_outputs> and pre-applies the upstream diff into the downstream worktree baseline.

  • auto_record_context records a completed ticket's summary as a shared note.

These blocks are project data, not instructions that override the ticket objective or the security policy.

Sessions and permissions

TaskRequest.session_id flows through MCP and AdapterCall. Adapters map it to --resume (Claude/ZCode), codex exec resume <id>, --session-id (DSH) or --conversation (Antigravity). Write-mode templates inject each CLI's approval bypass; read-only tickets use plan/read-only modes and run in a disposable worktree.

Market data and model routing

The mesh can rank models by published price and evaluation score instead of relying only on the four difficulty tiers. The data layer is read-only and separate from dispatch.

Sources

Source

Authentication

Fields used

OpenRouter /api/v1/models

none

list price per token, context window, reasoning and tool flags

models.dev /api.json

none

list price per million tokens, context window, release date

Epoch AI benchmark_data.zip

none

reasoning and coding benchmark percentiles, benchmark dates

Artificial Analysis /api/v2/language/models/free

ARTIFICIAL_ANALYSIS_API_KEY

intelligence index, list price, output speed

models.dev lists the same model once per provider, including hundreds of resale gateways. Those rows fold onto one canonical model per name. The price comes from the model vendor's own entry (listed in market.first_party_providers), then from OpenRouter, then from the median of every priced offer. An entry that prices input and output at zero counts as unknown, not free.

Epoch AI publishes the CC BY 4.0 "Capabilities & benchmarking" archive and needs no key, so it is the default evaluation source. Each benchmark contributes one percentile computed inside a 540-day reference window (market.epoch.reference_window_days); an axis with fewer than three scored benchmarks stays empty (market.epoch.min_benchmarks). The two axes are intelligence_reasoning and intelligence_coding, and intelligence is the equal-weight mean of the axes a model has. Artificial Analysis takes precedence when ARTIFICIAL_ANALYSIS_API_KEY is set. Without either source the mesh computes a labelled heuristic from the existing discovery score, the price percentile, the reasoning flag and the release date.

The heuristic is not an evaluation. Every score carries intelligence_source: epoch_ai, artificial_analysis, override or heuristic. hmesh market show and the get_model_market MCP tool print that field.

Epoch AI data is CC BY 4.0 and requires attribution. hmesh market show ends with Benchmark data: Epoch AI, 'Capabilities & benchmarking', https://epoch.ai/benchmarks (CC BY 4.0); --json carries the same string in attribution, and every routing decision includes it.

hmesh market refresh writes a snapshot to .harness-mesh/state.db. The default lifetime is six hours. Epoch AI and Artificial Analysis are cached for at least twelve hours; Artificial Analysis is also limited to 20 requests per process per day. A failed refresh keeps the previous snapshot and marks it stale. Cached data older than seven days still works and is flagged expired.

market.enabled: false or HARNESS_MESH_OFFLINE=1 stops every outbound request.

Hands-off refresh

The cache stays current without a manual step. The MCP server refreshes in the background at start-up when a source is missing or past its TTL, then on a TTL cadence. The first dispatch that finds no market data at all waits at most market.wait_seconds (8 s) and then continues with the local tiers while the refresh finishes in the background. One-shot commands (dispatch, route, status, models, market show) run the same refresh synchronously under the same 8 s bound and fall back to the previous snapshot or the heuristic when a source is slow or down. A failed refresh only logs a warning.

The controller sends an objective, nothing else. dispatch_task over MCP and hmesh dispatch default target_harness to auto, so the mesh routes across every installed harness and picks the model. The MCP initialize response states the same rule to every client. Passing model or target_harness explicitly keeps the previous behaviour.

On a machine with only some of the five harnesses, hmesh status, hmesh models and list_harnesses report a missing harness as not installed with the reason and leave its models and tier map empty; hmesh doctor ends with N of 5 harnesses installed. hmesh install --dry-run returns skipped for a missing binary, and ZCode is skipped as ZCode not found without writing a plugin when neither its CLI nor its app is present.

The market score also drives discovery: when a harness model matches the catalogue, its capability_score, assigned_tiers and tier map come from the market intelligence instead of the local heuristic. hmesh models, hmesh status and list_harnesses show each model's intelligence, intelligence_source and blended price, so the tier a user reads, the model dispatch picks and the route preview agree. hmesh doctor adds a read-only market row with the sources, the last successful refresh, staleness, the match rate and the unmatched models.

Task kinds and tiers

task_kind is plan, audit, review, implement, refactor, debug, test, docs or auto. auto reads the objective (Chinese and English keywords) and otherwise follows evaluate_difficulty.

Tier

Task kinds and difficulty

Rule

premium

plan, audit, review, or critical

highest intelligence; ties go to the lower blended price

balanced

refactor, debug, or high

highest intelligence per blended dollar among candidates at or above 85% of the best score

value

implement, test, docs, or low/medium

cheapest candidate at or above a difficulty floor (0.55 for low, 0.70 for medium)

blended_price = (3 * input + output) / 4 in USD per million tokens. A model with no known price is left out of price comparisons and used only when nothing else qualifies.

routing.axis_weights decides which evaluation axis a task kind is scored on: plan, audit and review use reasoning 0.7 / coding 0.3; implement, refactor, debug and test use coding 0.7 / reasoning 0.3; docs uses reasoning 1.0. When a model has only one axis, that axis carries full weight.

Claude Code and Codex bill through a subscription quota rather than per token. The router uses the API list price as a proxy for quota consumption and states that in every decision record.

Routing modes

routing.mode defaults to auto. manual keeps the model you pass; off uses the four difficulty tiers. HARNESS_MESH_ROUTING overrides the configured default, and a request-level routing_mode wins over both.

routing.pins fixes {harness, model} for one task kind. routing.premium_hints and routing.value_hints add weight to matching models; routing.strict_hints: true turns them into a hard filter. The example configuration uses exact glm-5.3, so it does not match glm-5.3-flash.

When no market snapshot exists, no harness model matches the catalogue, or the planner returns no choice, dispatch falls back to discovery.resolve_model(harness, difficulty). The decision record keeps the reason.

Decision record

Every result carries a routing object: mode, task kind, tier, chosen harness/model/effort, intelligence and its source, axis_scores (both axis scores with the weights used), benchmarks_used, the attribution string, list prices, the top three alternatives with scores, the data sources, fetched_at, stale, expired and the match confidence. The same block appears at the top of the transcript.

Not connected

The Aider polyglot leaderboard has no data after 2025-10. The community LMArena snapshot (oolong-tea-2026/arena-ai-leaderboards) has returned empty leaderboards every day since 2026-10-20. api.llm-stats.com returns vendor-reported scores marked verified: false, only four models carry an AA-Index, and its terms page returns 404. None of the three is used.

MCP tools (18)

Tool

Purpose

list_harnesses

Installed harnesses, real binary, version, authorised models, tier map and quota state

discover_harness_models

Force three-layer discovery for one or all harnesses

get_model_market

Read cached list prices, context windows and intelligence scores; intelligence_source names the source

preview_routing

Rank a task without dispatching: task kind, tier, chosen model and alternatives

list_skills_and_plugins

Search indexed SKILL.md files and MCP/plugin manifests

dispatch_task

Create a ticket, choose a model and run assignments with failover

parallel_dispatch

Dispatch several tickets concurrently

get_task_status

Ticket status plus assignments and failover history

read_task_resource

Page through diff, transcript or assignments

get_quota_status

Circuits, waiting queue; probe_now probes and resumes

get_integration_status

Five-state integration report for every enabled harness; read-only

plan_integration

Reviewable install plan and plan_id; writes nothing

install_integration

Write tool: installs only when plan_id still matches; workers and read-only mode are refused

report_quota_status

Manual reset, open or half_open

apply_task_patch

Apply a completed isolated worktree to the primary workspace with patch or merge (copy stays CLI-only)

cancel_task

Cancel a running or waiting ticket; child processes are killed

get_project_context

Read shared memory entries and scanned instruction files

update_project_context

Write or update one shared project fact/contract

CLI

hmesh install [--dry-run] [--yes] [--approve LEVEL] [--harness H]... [--uninstall]
hmesh doctor [--harness H] [--json]
hmesh status [--refresh] [--json]
hmesh integrations [--json]
hmesh integrations ignore|unignore NAME [--json]
hmesh models [--refresh] [--harness H]
hmesh quota [--probe]
hmesh route --objective O [--kind K] [--difficulty D] [--harness H] [--json]
hmesh market refresh [--source S]... [--json]
hmesh market show [--model GLOB] [--axis reasoning|coding] [--unmatched] [--json]
hmesh skills [--query Q]
hmesh dispatch --objective O [--harness H] [--difficulty D] [--kind K] [--routing-mode M] [--fallback H]...
hmesh tasks [--status S]
hmesh read <task_id> [diff|transcript|assignments] [--offset N] [--limit N]
hmesh apply <task_id> [--strategy patch|merge|copy] [--force-copy]
hmesh context list [--category C] [--json]
hmesh context set <key> <content> [--category C] [--author A] [--task-id T]
hmesh init-mcp [--print] [--target PATH]
hmesh version

Configuration

The template lives at config/harnesses.example.yaml. Copy it to ~/.config/harness-mesh/config.yaml (or any path passed via --config / HARNESS_MESH_CONFIG). Files inside the checkout (config/harnesses.yaml, .harness-mesh/config.yaml) are treated as untrusted repository content and are ignored by default: a cloned repository must not be able to choose which binary runs or where credentials are sent. HARNESS_MESH_TRUST_WORKSPACE_CONFIG=1 merges only non-executable fields (market, routing, sizes, quotas) from the workspace file; --config and HARNESS_MESH_CONFIG are always trusted because the operator named them explicitly. Resolution order is: the command name on PATH (for example claude, codex, dsh, agy, zcode), then the configured binary_paths (built-in macOS app-bundle locations plus any you add), then the macOS ZCode shim. A standard CLI install that lands on PATH therefore needs no configuration and no absolute path; the bundled paths only help desktop-app installs that do not put their CLI on PATH. If a harness lives outside PATH, add it to binary_paths in the user-level config file. Binary search supports ~ and * globs and selects the newest version. ZCode on macOS is wrapped automatically into .harness-mesh/bin/zcode.

The ledger lives under state_dir: the directory is created/tightened to 0700, and state.db plus its -wal/-shm side files to 0600. Transcripts, diffs and checkpoints are redacted before they are stored; the transcript resource is capped by transcript_max_chars (default 200000). If you upgrade from 0.4.1, the first 0.4.2 process rewrites legacy credential-shaped provider rows and vacuums the ledger; restart every harness that runs hmesh-mcp so the hardened server is the one in use.

Templates support {prompt}, {system_prompt}, {system_prompt_file}, {model}, {effort}, {workdir}, {mcp_config}, {task_id} and {assignment_id}. Empty flag/value pairs are dropped, so <cli_active_default> means "use the harness's own active model".

Key settings:

Setting

Default

Meaning

state_dir

.harness-mesh

Ledger, worktrees, generated MCP configs

allowed_workspace_roots

service workspace

Optional allowlist for request-level workspace_root; symlinks are resolved before containment checks

auto_init_repo

false

Refuse a non-Git workspace unless it is explicitly enabled

auto_approve_shared_write

false

Injection of approval-bypass flags when workspace_mode=shared_write

ZCode extra.restricted_mode

build

Mode used when approval is withheld (build, edit or plan); zcode -p would otherwise default to yolo

max_active_assignments

8

Global cap on simultaneously running assignments

summary_max_chars

1500

Summary returned to the controller

diff_preview_max_chars

4000

Diff preview returned to the controller

transcript_max_chars

200000

Cap for the paged transcript resource; head and tail are kept

max_call_depth

3

Nested dispatch depth limit

max_failover_attempts

4

Maximum failovers per ticket

quota_probe_interval_seconds

60

Background recovery probe interval

difficulty_timeout_seconds

600/1200/1800/3600

Per-tier assignment timeout

market.enabled

true

Read-only market data and its snapshot cache

market.ttl_seconds

21600

Snapshot lifetime for OpenRouter and models.dev

market.wait_seconds

8

Longest automatic refresh before dispatch or a command continues

market.sources

four sources

Providers to refresh

market.first_party_providers

[] (the example config lists twelve)

Vendors whose own models.dev entry sets the list price

market.epoch.reasoning_benchmarks

six benchmarks

Benchmarks that feed the reasoning axis

market.epoch.coding_benchmarks

nine benchmarks

Benchmarks that feed the coding axis

market.epoch.reference_window_days

540

Percentile window before a benchmark's latest release

market.epoch.min_benchmarks

3

Minimum scored benchmarks before an axis counts

market.aliases

{}

Map a harness model id or glob to a market key

market.overrides

{}

Glob-keyed intelligence and price overrides

routing.mode

auto

auto, manual or off; HARNESS_MESH_ROUTING wins

routing.floors

0.55/0.70

Value-tier intelligence floor by difficulty

routing.axis_weights

per task kind

Reasoning/coding weights used to score a task

routing.premium_hints / routing.value_hints

[]

Model globs weighted per tier

routing.strict_hints

false

Turn hint weighting into a filter

routing.pins

{}

Fixed harness/model per task kind

integration.ignore

[]

Harness names whose integration hints are suppressed

Testing

.venv/bin/ruff check src tests
.venv/bin/python -m compileall -q src tests
.venv/bin/pytest -v

The fast suite uses mocked adapters, temporary Git repositories, httpx.MockTransport market providers and cached snapshots. It opens no sockets. Live HTTP checks live in tests/test_real_machine_market.py and run only with HARNESS_MESH_REAL_MACHINE=1; the Artificial Analysis branch also needs ARTIFICIAL_ANALYSIS_API_KEY. tests/test_local_machine_harnesses.py additionally exercises the real locally installed harnesses when the macOS bundles are present; it asserts real binary resolution, real model inventories, and a real DeepSeek ticket that creates a file in a worktree and applies it back. See CONTRIBUTING.md for the development workflow.

Operational notes

  • The mesh state directory may contain source excerpts and prompts. Keep it out of commits and shared archives.

  • Approval-bypass flags make a disposable worktree convenient, not safe. Built-in harnesses default to auto_approve: true for isolated worktrees; shared_write suppresses bypass unless auto_approve_shared_write: true. Use isolated worktrees, review diffs, and respect provider terms.

  • The DeepSeek built-in runtime strips credential-shaped environment variables from its shell tool. That reduces accidental key exposure but does not create a sandbox.

  • A one-shot hmesh dispatch --policy wait_and_resume exits after scheduling the suspension; the long-lived MCP server runs the background monitor and effects consumer. Use hmesh quota --probe or the MCP tool to resume manually.

  • Antigravity SDK timeouts cancel waiting but cannot kill a third-party worker thread.

  • Codex CLI versions differ in accepted approval flags. The built-in default injects --full-auto; the example YAML overrides it with --dangerously-bypass-approvals-and-sandbox for codex-cli 0.166. Adjust execute_template or extra.auto_approve_args for your version.

Workspace and context boundaries

  • The MCP server and CLI require a Git workspace; startup fails from $HOME, /, or a directory without Git.

  • Request-level workspace_root must resolve (including symlinks) inside allowed_workspace_roots, which defaults to the service workspace.

  • Sensitive filtering covers .env and real credential/key files, plus .ssh, .aws, .gnupg, and .git path segments. .env.example, .env.sample, .env.template, .env.dist, ordinary credentials_service.py-style source, and public *.pub keys stay visible. Every skipped path is reported in skipped_sensitive and warnings; Mesh no longer edits the user's .git/info/exclude.

  • Worktree symlinks are rewritten as relative links into the worktree. Escaping or dangling links are reported; apply rejects symlink diffs that leave the target root.

  • Approval bypass flags are suppressed for shared_write unless auto_approve_shared_write: true; the DeepSeek built-in shell drops credential-shaped environment variables, cloud key names, SSH agent sockets, and URLs containing passwords.

  • Shared memory is capped at 128 characters per key, 4,000 per entry and 6,000 rendered characters. Only controller entries render as verified; worker and auto entries render in a separate unverified block. Author validation checks the name only.

  • Mesh Git commands disable hooks, fsmonitor, pager, external diff and protocol.ext, record a per-task metadata guard once, and reject apply or abort the ticket when metadata changes after task start.

  • MCP call depth can be recovered from the worktree cwd or lineage marker when inherited environment variables are unavailable; max_active_assignments caps running assignments.

Trademarks and independence

Harness-Mesh is an independent open-source project. It is not affiliated with, sponsored by, or endorsed by Anthropic, OpenAI, DeepSeek, Google, or ZCode. Claude, Codex, DeepSeek Harness, Google Antigravity, and ZCode are names or trademarks of their respective owners, used here only to describe interoperability. Each harness remains governed by its own licence, acceptable-use policy, and data terms.

License

MIT. See LICENSE.

Available Tools

18 tools
apply_task_patchB

Apply the isolated worktree changes back into the primary workspace.

Only patch and merge are exposed over MCP. The copy strategy is destructive and remains a CLI-only operation.

Inputs: task_id (required), strategy. Returns: object

cancel_taskB

Cancel a running or waiting ticket. The worktree is retained for inspection.

Inputs: task_id (required). Returns: object

discover_harness_modelsC

Run the three-layer model discovery waterfall for one or all harnesses.

Inputs: harness, force_refresh. Returns: object

dispatch_taskB

Dispatch a ticket.

Only the objective is required. Leave target_harness at "auto" and model unset to let the mesh choose; pass task_kind when it is known. Quota exhaustion creates a new Assignment on another harness and resumes in the same worktree.

Inputs: objective (required), model, skills, plugins, +25 more. Returns: object

get_integration_statusA

Report whether each installed harness can reach Mesh as a controller.

States are integrated, detected_not_integrated, stale, not_detected and ignored. Read-only: detection never writes.

Inputs: no named parameters. Returns: object

get_model_marketB

Read cached model prices, context windows and intelligence scores.

intelligence_source says whether a score came from Artificial Analysis, a user override or the local heuristic. This tool never refreshes the cache and never performs a network request.

Inputs: limit, query. Returns: object

get_project_contextC

Read the cross-harness project memory blackboard and instruction files.

Inputs: category, include_instructions. Returns: object

get_quota_statusA

Show quota circuits and the waiting_for_quota queue.

probe_now triggers recovery probes and resumes waiting tickets.

Inputs: probe_now. Returns: object

get_task_statusC

Return ticket status plus every assignment and failover hop.

Inputs: task_id (required). Returns: object

install_integrationA

Install one harness after the user approved the reviewed plan.

This is a write tool: it refuses workers and HARNESS_MESH_READ_ONLY=1, and it refuses any plan_id that no longer matches a freshly computed plan. The target harness must restart before the tools appear.

Inputs: harness (required), plan_id, approve_level. Returns: object

list_harnessesC

List locally available harnesses, discovered authorised models, tier bindings and quota state.

Inputs: refresh_models. Returns: object

list_skills_and_pluginsC

Search indexed SKILL.md files and MCP/plugin manifests.

Inputs: query. Returns: object

parallel_dispatchA

Dispatch multiple tickets concurrently.

Every task accepts the same fields as dispatch_task, including task_kind, routing_mode, max_price_per_mtok and min_intelligence. target_harness is optional and defaults to auto.

Inputs: tasks (required), max_concurrency. Returns: object

plan_integrationA

Return the exact installation plan and plan_id without writing.

harness must be an enabled configured name and approve_level one of read, dispatch, all or none. Show this plan to the user and ask for consent before calling install_integration.

Inputs: harness (required), approve_level. Returns: object

preview_routingB

Preview the routing decision for an objective without dispatching it.

Inputs: objective (required), task_kind, difficulty, target_harness. Returns: object

read_task_resourceB

Page through a large diff/transcript/assignments payload to protect the controller context window.

Inputs: task_id (required), limit, offset, resource. Returns: object

report_quota_statusC

Manually reset or mark a quota circuit (actions: reset, open, half_open).

Inputs: harness (required), model, action, cooldown_seconds. Returns: object

update_project_contextC

Write or update one shared project fact or interface contract.

Inputs: key (required), content (required), task_id, category, +1 more. Returns: object

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    B3.2/5.0

    Scored across 18 tools

    Disambiguation4/5

    Most tools map to a distinct resource+action, and the three-phase integration flow (status → plan → install) is explicitly separated by read/write semantics. Minor ambiguity remains between get_quota_status and report_quota_status, since 'report' sounds like a read but actually mutates the circuit, and the model-information trio (discover_harness_models, list_harnesses, get_model_market) requires reading descriptions to separate cache reads from live discovery.

    Naming Consistency4/5

    The surface is overwhelmingly verb_noun snake_case (get_task_status, cancel_task, update_project_context) with clear read/write prefixes. Deviations are cosmetic: parallel_dispatch inverts the verb order, preview_routing lacks an explicit object, and discover_harness_models/get_model_market stretch the pattern without breaking it.

    Tool Count4/5

    18 tools sit at the high end of comfortable but each corresponds to a real operation across dispatch, quota, integration, model discovery and project context. Nothing looks like filler, though the set is broad enough that a controller may need a session to build a mental map.

    Completeness4/5

    Core lifecycle is well covered: routing preview, dispatch (single and parallel), status, cancel, patch application, quota read/write and integration detect/plan/install. Gaps are real but workaroundable: there is no list_tasks to enumerate tickets before calling get_task_status, no uninstall/ignore integration despite the 'ignored' state, and no tool to edit tier bindings that list_harnesses reports.

    Maintenance

    ActivityMaintained
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      B
      maintenance
      Enables repository-aware lifecycle management and controlled delegation of coding tasks to trusted worker harnesses via MCP, with execution isolation, recovery, and verified handoff.
      36 npm
      8
      Apache 2.0
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables coordinating Claude Code and Codex on one machine by fanning out tasks to multiple agents in isolated Git worktrees, comparing results, picking a winning candidate, and handing off work between harnesses. It provides MCP stdio tools, a CLI, and a local loopback web cockpit.
      Apache 2.0
    • A
      license
      Not graded
      quality
      A
      maintenance
      Enables AI coding providers to run structured multi-agent workflows with shared documents, tracked tasks, handoffs, and health-gated completion evidence. It integrates with multiple coding tools while keeping task state, actions, and health results in the harness.
      29 npm
      MIT