Treeship
Concepts

Agent Harnesses

How Treeship attaches to and observes each agent surface. The differentiator behind Verified coverage.

A harness is how Treeship attaches to and observes a specific agent surface. Native hooks for Claude Code, an MCP bridge for Cursor / Codex / Cline, skill files for Hermes / OpenClaw, shell-wrap for any custom agent, git-reconcile as the universal backstop. Harnesses make agents observable.

Cards describe who an agent is. Harnesses describe how Treeship is attached to it. The two stay distinct on purpose: the same surface (Claude Code) might one day have multiple harnesses (native hook vs MCP-only), and the same harness will instrument many cards (every agent of that surface in this workspace).

The 1:1 mapping today

In v0.9.8, every supported surface has exactly one harness. The harness IDs match what users type to treeship add:

Harness IDSurfaceCoverageAuto-installable?
claude-codeClaude Codehighyes — native hook + MCP
cursorCursormediumyes — MCP
clineClinemediumyes — MCP
codexCodex CLImediumyes — TOML MCP
hermesHermesmediumyes — skill file
openclawOpenClawmediumyes — skill file
ninjatech-superninjaNinjaTech / SuperNinja remotebasicno — see NinjaTech integration
ninjatech-ninja-devNinja Dev IDEmediumno — manual MCP
generic-mcpAny MCP clientmediumno — manual register
shell-wrapCustom shell-wrap agentbasicnotreeship wrap only

The four "no auto-installer" rows still have manifests. treeship harness inspect <id> is honest about what they could capture vs what's actually attached.

Manifest vs state

Treeship splits harness data into two physically separate types so reports can't conflate "could capture" with "did capture":

HarnessManifest — static metadata, in code:

pub struct HarnessManifest {
    pub harness_id: &'static str,
    pub surface: AgentSurface,
    pub display_name: &'static str,
    pub connection_modes: &'static [ConnectionMode],
    pub coverage: CoverageLevel,
    pub captures: PotentialCaptures,        // ← what this harness COULD capture
    pub known_gaps: &'static [&'static str],
    pub privacy_posture: &'static str,
    pub recommended_backstops: &'static [ConnectionMode],
    pub install: Option<InstallProfile>,
}

HarnessState — per-workspace, on disk at .treeship/harnesses/<id>.json:

pub struct HarnessState {
    pub harness_id: String,
    pub status: HarnessStatus,              // detected / instrumented / verified / ...
    pub coverage: CoverageLevel,
    pub active_connection_modes: Vec<ConnectionMode>,
    pub last_smoke_result: Option<SmokeResult>,
    pub last_verified_at: Option<String>,
    pub verified_captures: VerifiedCaptures, // ← what's actually been PROVEN
    pub linked_agent_ids: Vec<String>,
    ...
}

PotentialCaptures is bool per signal. VerifiedCaptures is Option<bool> per signal: Some(true) proven, Some(false) smoke ran but signal didn't fire, None never asserted (the default).

Status lifecycle

Detected → Available → Instrumented → Verified

                        Drifted / Degraded / Disabled
StatusWhat it means
DetectedA manifest exists; nothing on disk.
AvailableThe manifest has an installer but Treeship hasn't installed it in this workspace. (Reserved for "user declined" path.)
InstrumentedTreeship installed the snippet/config. Generic trust-fabric smoke may have passed.
VerifiedA harness-specific smoke has proven this harness's own capture path on this machine. Setup's generic smoke does not promote here.
DriftedThe on-disk install no longer matches what Treeship would write. (Reserved for a future drift-check command.)
DegradedCapture is incomplete — a previously-proven signal stopped firing. (Reserved.)
DisabledUser explicitly opted out.

Setup's smoke runs a generic init → session → wrap → close → package verify round-trip. It proves Treeship's signing pipeline works. It does not prove Claude Code's native hook fired, or that Cursor's MCP routing actually captured a tool call. Setup therefore promotes harnesses to Instrumented, not Verified. Verified is reserved for harness-specific smokes that exercise each capture signal.

CLI

treeship harness list                    # every manifest joined with workspace state
treeship harness inspect <id>            # full manifest + state for one harness
treeship harness smoke <id>              # generic trust-fabric smoke (does NOT prove harness-specific capture)

harness inspect shows two distinct rows:

potential captures (when attached and working):
  files.read     yes
  files.write    yes
  commands.run   yes
  mcp.call       yes
  model/provider yes

verified captures (proven by harness-specific smoke):
  (none yet -- run a real session through this harness)

How linkage works

When you run treeship setup or treeship agent register, Treeship records the relationship between a card and its harness in two places:

  • AgentCard.active_harness_id — points the card at the harness it's attached through.
  • HarnessState.linked_agent_ids — lists every card on the other side.

Both update on re-run; harness inspect <id> shows linked cards alongside last smoke result.

See also