# When a task says "Repo config not trusted"

Source: https://codeherder.com/docs/repo-harness-config/

Why a device refuses a repo that commits hooks, plugins or helper commands, and how to trust one repo, one plugin marketplace or the whole device.

A repository can commit files that make a coding agent run a command. Examples are hooks, helper programs and plugins. A device does not trust those files by default. This page explains the refusal, and how you fix it.

## What triggers the refusal

Before a session starts, the device scans the repository’s working folder, up to the repo root. It refuses the session when it finds config that runs commands or loads code.

For Claude Code, these files count:

- `.claude/settings.json` and `.claude/settings.local.json`, when they set `hooks`, `statusLine`, `apiKeyHelper`, `env`, `enabledPlugins` or `extraKnownMarketplaces`. Other helper-command keys count too, such as the AWS and GCP sign-in helpers.
- Agent files in `.claude/agents/`, when the frontmatter sets `hooks` or `mcpServers`.
- A skill in `.claude/skills/`, when its `SKILL.md` frontmatter sets `hooks` or `mcpServers`. A skill that CodeHerder delivers for the session does not count.

Other keys, such as `permissions` and `model`, do not trigger it. The instructions files `CLAUDE.md` and `AGENTS.md` do not trigger it either.

The same rule covers some files for two other harnesses:

- Cursor: `.cursor/hooks.json` and `.cursor/mcp.json`.
- OpenCode: `opencode.json` or `.opencode/opencode.json` (also the `.jsonc` forms) that set `plugin`, `mcp`, `formatter` or `lsp`, and non-empty plugin or tool folders under `.opencode/` (`plugin/`, `plugins/`, `tool/` or `tools/`).

A committed `.mcp.json` does not refuse the session. By default, Claude starts in a mode that ignores it, so its servers never run. A marketplace approval alone keeps it off. Trust the repo or the whole device to load its servers.

## What you see

CodeHerder tries another device that can run the task. It then skips the refusing device for that task for 24 hours.

When every capable device refuses, the task shows a **Start refused** badge with the reason **Repo config not trusted**. `ch task show <taskId>` shows the same reason in its `start refusal` row. The refused session records which files and keys the device found. The message is short, so a long list can end with “shortened”.

## Fix it, narrowest first

1. **Remove the config from the repo.** This is the safest fix. A repo without these files starts normally.
2. **Trust a plugin marketplace.** Set `CH_TRUST_HARNESS_MARKETPLACES` on the device to the marketplaces you approve. Use `github:owner/repo` or a git remote. This covers only the `enabledPlugins` and `extraKnownMarketplaces` keys. Hooks, helper commands and `env` still refuse. A plugin’s own MCP servers stay off.
3. **Trust one repo.** Set `CH_TRUST_HARNESS_REPOS` on the device to the repo, for example `github.com/acme/app`. The device then accepts everything that repo commits. Claude also runs the repo’s `.mcp.json` servers and the MCP servers of its plugins.
4. **Trust every repo on the device.** Set `CH_TRUST_REPO_HARNESS_CONFIG` to `true`. This is the broadest choice. It overrides the two lists. Every repo’s hooks, plugins and MCP servers then run.

All three settings **weaken isolation**. A trusted repo runs its commands as the user who runs the device server, with no prompt. Trust only repos whose contributors you trust. See [Who can run code on your device](https://codeherder.com/docs/device-trust/) and [Isolating agent runs on a device](https://codeherder.com/docs/agent-isolation/).

## How the lists match

- Write each entry as a comma-separated item. A list holds at most 64 entries.
- A repo entry is a git remote or a `host/owner/repo` path. The match is exact and ignores case, the scheme, a user name, a port and a trailing `.git`.
- A wildcard, a bare name such as `app`, or an entry with no owner or repo is rejected when you save it. A bad value in the device’s own environment stops the device server at start.
- The device matches a marketplace by its source repository, never by its name. A repo that defines a marketplace with the same name but a different source stays refused.
- A plugin must name a marketplace that the repo’s own settings define.
- The device checks only the repo that holds the session’s working folder. Trusting one repo does not trust a second repo that the same task attached.
- A session that starts in a parent folder has no repo to match. Only the marketplace list or the whole-device setting admits it. See [Start from a parent folder of repos](https://codeherder.com/docs/local-sessions/#start-from-a-parent-folder-of-repos).

## Apply and undo a change

Set the value in the device’s **Settings** section in the web app, or as an environment variable on the device. See [Changing a device’s settings](https://codeherder.com/docs/device-settings/).

A new value takes effect after an operator restarts the device. The device never restarts itself. After a restart that applies a changed value, the 24-hour skip ends for that device and the task tries it again. To end the skip without a change, run:

```
ch device clear-provision-breaker <device>
```

To undo trust, remove the entry, or clear the setting, then restart the device. The next session is scanned again. A session that already runs keeps what it loaded.

## Related guides

- [Changing a device’s settings](https://codeherder.com/docs/device-settings/) — where to set these values
- [Who can run code on your device](https://codeherder.com/docs/device-trust/) — what a trusted repo can do
- [Isolating agent runs on a device](https://codeherder.com/docs/agent-isolation/) — limit what an agent reaches
- [When a task is not moving](https://codeherder.com/docs/task-not-moving/) — find the cause of a stuck task
- [Skills](https://codeherder.com/docs/skills/) — the skills that CodeHerder delivers to a session
