Installed harnesses in the Threads picker

A provider package being available on a portal is not the same as a person installing it. CLI packages such as Claude Code declare personalInstall: true; the Store copies their Harness/{id} node into the installer's {user}/Harness namespace. The installed node is the selection, while the provider module supplies the runtime IHarness with that id.

BuiltInHarnessProvider deliberately omits runtimes whose definition has RequiresInstall. Publishing every loaded CLI runtime in the global Harness namespace would offer it to people who had never installed it. The global catalog still supplies the native MeshWeaver harness.

Harnesses are options of the Threads app, not apps

The coding-assistant harnesses β€” Claude Code, GitHub Copilot, Codex, Cursor, Grok, OpenCode and Antigravity β€” are options of the Threads app (AI/AiThreads), never apps of their own. Each package declares hostedIn: AI/AiThreads (PluginContent.HostedIn), which means:

Which harnesses an instance runs is deployment configuration: the loaded modules and Features:Ai:Clis:*. On the fleet, that belongs in the Models app (/Hosting/Models, the AI domain's fleet app). A switch there is owed; today the flags are set in the record's portal configuration.

The marks

A harness that runs its own agent loop declares the same two marks a language model carries (AI/ModelDataResidency): where prompts are processed (Harness.DataResidency: πŸ‡ͺπŸ‡Ί EU only, 🌍 global, ❔ not established) and where the maker is based (Harness.ModelOrigin + Harness.ModelMaker). The runtime declares them (IHarness.Definition) and HarnessProvenance resolves them by harness id. That way a per-user copy installed before the marks existed shows them too. The native MeshWeaver harness carries none, because it processes wherever the picked model does and each model row shows its own. ❔ is never treated as EU.

Harness Processing Origin Why
Claude Code 🌍 Global πŸ‡ΊπŸ‡Έ Anthropic Anthropic's first-party API (api.anthropic.com) is a global endpoint
OpenAI Codex 🌍 Global πŸ‡ΊπŸ‡Έ OpenAI api.openai.com is a global endpoint
Grok Build 🌍 Global πŸ‡ΊπŸ‡Έ xAI api.x.ai is a global endpoint
Google Antigravity 🌍 Global πŸ‡ΊπŸ‡Έ Google the Gemini API (generativelanguage.googleapis.com) is a global endpoint
GitHub Copilot ❔ not established πŸ‡ΊπŸ‡Έ GitHub (Microsoft) routes to several makers' models; no residency evidence
Cursor ❔ not established πŸ‡ΊπŸ‡Έ Anysphere (Cursor) routes to several makers' models from its own service
OpenCode ❔ not established ❔ unknown runs whichever provider the user configures

The endpoint rule is DataResidency.FromEndpoint, the same one the model marks use. None of these harnesses is EU-only.

One query contract

AgentPickerProjection.BuildHarnessQuery owns the exact namespace union:

namespace:{user}/Harness|{space}/Harness|Harness nodeType:Harness

The builder omits absent or reserved route partitions, deduplicates repeated namespaces and projects the content needed by registry consumers. Both ObserveDefaultComposer and the interactive ThreadChatView picker use it. The picker resolves the current navigation context before deriving the space partition and retains its circuit-user access context for the read. No fan-out across all readable partitions is needed or appropriate.

The /harness skill's global-only literal remains a platform fallback, not the query a context-aware Threads client should execute. The picker recognizes the harness composer field and resolves the canonical registry, just as it does for the agent and model fields.

Diagnose the boundary that failed

On 2026-09-22 an active personal Claude Code harness existed and the Store reported installed, but the picker showed only MeshWeaver. Installation had succeeded. OpenPicker grouped harnesses with custom commands and ran the skill's literal namespace:Harness query, while composer defaults already read the personal + space + global union. The personal copy could never match the interactive picker's query.

Check these separately before changing installation, permissions or runtime registration:

  1. Does the installed node exist at the user's actual {user}/Harness/{id} path and read Active?
  2. Does the picker query include that namespace under the same browser user?
  3. Does the selected full path resolve to an installed node and a registered runtime?
  4. Only then diagnose that runtime's connection and provider-specific login.

HarnessPickerQueriesTest pins the namespace union and its no-user and reserved-context cases. HarnessPickerQueryTest executes it against a mesh containing personal, space, global and uninstalled package entries. PickerHarnessQueriesTest pins the Threads routing from the skill request to that canonical builder. The separate HarnessInstallGateTest covers runtime execution's active-install requirement; passing it alone never proved picker discoverability.