> ## Documentation Index
> Fetch the complete documentation index at: https://docs.visiqlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Claude Cowork Integration

> Govern Claude Cowork — enforcement on host-local sessions via native hooks, plus audit-stream monitoring for sandboxed sessions.

<Note>
  **Pre-GA — not yet generally available.** The **Claude Cowork** card under
  **Integration → Connectors** stays disabled until a Cowork-specific canary
  proves the connector on `main`. The npm package **is** published, so the install
  command below works — but `latest` tracks `main`, which can sit behind the fixes
  already on the integration branch.
</Note>

<Note>
  **Prerequisites.** A VisIQ account ([sign in](https://app.visiqlabs.com)) with a
  harness key from **Settings → Harness Keys**, and the Claude desktop app. This
  harness governs Cowork's own agent, so no separate model key is needed here.
  Hitting an error? See [Troubleshooting](/troubleshooting).
</Note>

`@visiq/claude-cowork-harness` brings VisIQ governance to **Claude Cowork**, the
agent surface in the Claude desktop app.

<Warning>
  **Read this before you rely on it.** Cowork runs a session in one of two places,
  and the difference decides what governance is possible. VisIQ covers both, but
  not equally — and the harness reports which is which rather than averaging them
  into one reassuring number.
</Warning>

## The two surfaces

| Surface        | Where it runs                                                   | What VisIQ does                                                                                                   | How                                                             |
| -------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------- |
| **Host-local** | The desktop app spawns its own `claude` natively on the machine | **Enforcement** — action + retrieval governance; a `deny` stops the tool call before it runs                      | Claude Code hooks (`SessionStart`, `PreToolUse`, `PostToolUse`) |
| **VM sandbox** | The session runs inside the app's Linux guest                   | **Monitoring** — every tool call, its arguments, the model, and the sandbox's own allow/deny answer for each call | Tailing the host-side per-session audit stream                  |

A sandboxed session's configuration lives inside the guest and carries no
`settings.json`, so no host hook can fire for it. The audit stream VisIQ tails
for those sessions is written *after* a tool has already run. **VisIQ therefore
never reports a block on the sandbox surface**, and `status` says so explicitly.

## If an AI coding agent is doing this install

These are its rules — the same guardrail VisIQ prepends to every setup prompt the
platform generates. They are here because this page is one an agent gets pasted,
and because a step below really can fail: `latest` tracks `main`, so it can lag
the fixes already on the integration branch. Improvising around a failed step is
how an agent ends up building a CLI from source and patching the very harness it
was sent to install.

Rules for the AI agent running this setup — read these first:

* Apply ONLY the changes this prompt explicitly shows: its commands, its
  environment/config values, and its exact code snippet(s), if any. Nothing
  else may be written, edited, or patched — not code, not packages, not
  configuration.
* Never improvise a workaround when something fails: no building from source,
  no packing tarballs, no PATH shims or alternative registries, and no
  debugging or patching the VisIQ software itself.
* If any command fails, is unavailable, or produces output that differs from
  what this prompt describes, STOP and report the exact command plus its full
  output back to your operator. A partial install is a safe no-op by design —
  leaving it unfinished is always correct; an unauthorized fix never is.
* Do the steps below IN ORDER, and after each one run the `Check:` command it
  shows and confirm the output before moving on. NEVER report the setup
  complete based on what you intended to do — only on what a check actually
  showed. If a check does not show what it describes, the step is not done.
* Reading is always in scope. Inspect these commands, the URLs they call and
  the integrity checks they run BEFORE executing anything, and tell your
  operator what you found. These rules bound what you may CHANGE, never what
  you may examine — if something here looks wrong, refusing to run it and
  saying why is the correct outcome, not a failed setup.

## Install

<Steps>
  <Step title="Install the harness">
    ```bash theme={null}
    # Install BOTH: the Cowork harness, and the Claude Code harness whose
    # `visiq-claude-code` binary owns the shared credential command used in step 3.
    # The cowork package depends on it, but a dependency does not put a binary on
    # your PATH — only a direct global install does.
    npm install -g @visiq/claude-cowork-harness @visiq/claude-code-harness
    ```

    Check: run `visiq-claude-cowork status`. Its `dispatcher:` line must end in a real
    path — `→ NOT FOUND on PATH` means only one of the two packages landed, and every
    tool call will run **ungoverned**.
  </Step>

  <Step title="Wire the hooks (host-local enforcement)">
    ```bash theme={null}
    visiq-claude-cowork install
    ```

    This writes the governance hooks into `~/.claude/settings.json`.

    Check: `visiq-claude-cowork status` now reads `hooks: installed — <your
        settings.json>`. `not installed` means the write did not happen.
  </Step>

  <Step title="Set credentials">
    ```bash theme={null}
    visiq-claude-code configure --api-key <harness-key> --agent-id <agent-id>
    ```

    Credentials are shared with `@visiq/claude-code-harness` — mint the key under
    **Settings → Harness Keys**.

    Check: `visiq-claude-cowork status` now reads `credentials: resolved` and shows the
    `agent id:` you passed. While it reads `MISSING` the hooks are wired but every one
    of them silently no-ops.
  </Step>

  <Step title="Point at your control plane (optional)">
    `--api-key` and `--agent-id` are the two REQUIRED values. The endpoint is
    **optional and defaults to the VisIQ cloud** (`https://api.visiqlabs.com`). If
    you run a sovereign / self-hosted / on-prem VisIQ, set it — otherwise this
    harness reports every governed tool call to the VisIQ SaaS control plane rather
    than your own:

    ```bash theme={null}
    visiq-claude-code configure \
      --api-key <harness-key> \
      --agent-id <agent-id> \
      --base-url https://visiq.internal.example.com   # OPTIONAL (defaults to the VisIQ cloud)

    # or via the environment
    export VISIQ_BASE_URL=https://visiq.internal.example.com   # OPTIONAL
    ```

    Resolution is the Claude Code harness's own, so `VISIQ_API_KEY` /
    `VISIQ_AGENT_ID` / `VISIQ_BASE_URL` behave exactly as in
    [the Claude Code quickstart](/quickstart/claude-code).

    Check: `visiq-claude-cowork status` still reads `credentials: resolved`. If you
    skipped this step, skip the check with it — the default is the VisIQ cloud, which
    is correct for every VisIQ SaaS account.
  </Step>

  <Step title="Restart the Claude desktop app">
    Hooks are read when a session starts.

    Check: nothing to run here — the two coverage lines in the next step are what say
    whether the restart took effect.
  </Step>

  <Step title="Confirm what is covered">
    ```bash theme={null}
    visiq-claude-cowork status
    ```

    ```
    [VisIQ] Claude Cowork harness 0.1.10 — status
      this process:       unknown (cannot enforce)
      credentials:        resolved
      agent id:           agent_01HQ7ZK3M4N5P6R7S8T9V0W1X2
      hooks:              installed — /Users/you/.claude/settings.json
      dispatcher:         visiq-claude-code-hook → /usr/local/bin/visiq-claude-code-hook
      Claude Cowork (host-local): ENFORCED (PreToolUse deny blocks)
      Claude Cowork (VM sandbox): monitor-only — 3 session(s), 5 audit log(s), all observed
      session tree:       /Users/you/Library/Application Support/Claude/local-agent-mode-sessions
      monitor state:      /Users/you/.visiq/claude-cowork/monitor-state.json
    ```

    That block is not hand-written. `packages/visiq-claude-cowork-harness/__tests__/readme.e2e.test.ts`
    builds exactly the state it depicts, runs the **built** CLI against it, and
    requires this page — and the package README — to match what came back. Only the
    four absolute-path values are exempt (they differ per machine and per OS); every
    label, every count and the version are bound.

    `ENFORCED` is claimed only when BOTH are true: a VisIQ hook is wired under
    `PreToolUse` **and** the `dispatcher:` line resolved to a real executable. Hooks
    present in `settings.json` with a dispatcher missing from your `PATH` mean tool
    calls run **ungoverned**, and `status` says exactly that instead.

    `this process:` is the surface **the command itself** is running on — not a
    coverage line. Run from a normal shell it reads `unknown (cannot enforce)`,
    because the `visiq-claude-cowork` process has no `claude` binary in its own
    ancestry to classify; run from inside a sandboxed session it reads
    `Claude Cowork (VM sandbox) (cannot enforce)`. Neither says anything about
    whether your Cowork sessions are governed — the two coverage lines below it do.
  </Step>
</Steps>

## Monitoring sandboxed sessions

Enforcement is not available inside the sandbox, but visibility is. Run the
monitor to report every sandboxed tool call to VisIQ:

```bash theme={null}
visiq-claude-cowork monitor            # long-running, polls every 15s
visiq-claude-cowork monitor --once     # single pass, for a cron/launchd job
```

Per tool call it reports the tool name (including fully-qualified `mcp__*`
tools), the arguments, the model, session and tool-call ids, sub-agent parentage
and the observation timestamp — each stamped with its surface and `mode:
"monitor"`.

It also reports **the sandbox's own permission decisions**. Cowork asks you to
approve a tool call and writes both halves of that exchange: the request (tool
name and arguments) and your answer — `granted`, and whether you allowed it
`once` or `always`. Denials and standing grants are therefore visible, not
inferred.

### An observed call is not a call that ran

<Warning>
  The audit record for a tool call is written when the model **issues** it —
  *before* the permission prompt is answered. A call you **refuse** still appears
  in the stream, and on its own it is indistinguishable from one that executed.
</Warning>

Every observation carries `cowork.execution` so the two are told apart:

| value         | means                                                                                                                                                  |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `refused`     | you denied it — the tool **never ran**                                                                                                                 |
| `granted`     | you approved it                                                                                                                                        |
| `unconfirmed` | the stream has not said: the call was not gated, or its answer has not been read yet. This is the default, and it is **not** a claim that the call ran |

## Already running the Claude Code harness?

Then your **host-local Cowork sessions are already governed**. Cowork reads the
same `~/.claude/settings.json` as the Claude Code CLI, so
`@visiq/claude-cowork-harness` installs the *same* `visiq-claude-code-hook`
dispatcher rather than a second one — two dispatchers over one file would
double-evaluate every tool call. Installing this package adds the Cowork surface
labelling and the sandbox monitor.

## Fail posture

Agent-side, the harness **fails open** by default: if VisIQ itself cannot answer
— no credentials, endpoint unreachable, no rule bundle — the agent keeps working
and the failure is reported loudly. A policy `deny` always blocks. Opt into
strict fail-closed with `VISIQ_FAIL_MODE=closed`.

## Commands

| Command                                           | Purpose                                            |
| ------------------------------------------------- | -------------------------------------------------- |
| `install [--settings <path>] [--command <cmd>]`   | Wire the governance hooks (host-local enforcement) |
| `uninstall [--settings <path>] [--command <cmd>]` | Remove them, leaving your own hooks untouched      |
| `status [--settings <path>] [--command <cmd>]`    | What is installed, detected, and actually covered  |
| `monitor [--once] [--interval <ms>]`              | Tail the sandbox audit stream (monitor-only)       |

This table is not hand-maintained.
`packages/visiq-claude-cowork-harness/__tests__/usage.test.ts` derives every
signature from the CLI's own flag table and requires this page — and the package
README — to match it, so a flag the CLI accepts and this page omits reds a test
rather than shipping. It had: `status --settings`, `status --command` and
`uninstall --command` are all accepted and acted on, and none was documented.

<Warning>
  **`--settings` configures ONE invocation, not a saved preference.** After
  `visiq-claude-cowork install --settings /custom.json`, a bare
  `visiq-claude-cowork status` reads `~/.claude/settings.json` — a different file —
  and truthfully reports it as uncovered. Following *that* output's advice with a
  bare `install` would write your live config, which is the outcome `--settings`
  exists to avoid.

  So the CLI carries the flag forward. Every command it suggests that accepts
  `--settings` is printed with the file already in effect, ready to paste:

  ```bash theme={null}
  visiq-claude-cowork install --settings /custom.json
  visiq-claude-cowork uninstall --settings /custom.json
  visiq-claude-cowork status --settings /custom.json
  ```

  `monitor` does not take `--settings` — it is suggested bare, because the CLI never
  prints an invocation it would refuse. These examples are re-derived from the
  renderer the CLI itself calls by
  `packages/visiq-claude-cowork-harness/__tests__/hints.test.ts`, so if the
  carry-forward ever stopped, this promise would red rather than ship.
</Warning>
