Skip to content

Configuration ​

The harness is configured via harness.yaml in your project root. Create one with kcp-harness init.

Full Reference ​

yaml
version: "1.0"

governance:
  domains:
    - manifest: "./knowledge.yaml"    # Path to knowledge manifest
      paths:                           # File paths governed by this manifest
        - "docs/"
        - "src/models/"
      urls:                            # URL prefixes governed by this manifest
        - "https://docs.example.com/"
      tools:                           # Custom tool names to govern
        - "custom_knowledge_tool"

  policy:
    fail_closed: true          # Block access when governance can't verify (default: true)
    audit_all: true            # Log pass-through calls too (default: true)
    max_units: 5               # Maximum knowledge units per plan
    strict: false              # Strict mode — reject low-relevance units
    budget:                    # Monetary budget ceiling
      amount: 1.00
      currency: USDC
    context_budget: 50000      # Token budget ceiling
    env: prod                  # Environment (affects temporal gates)

  confidence:                  # Post-synthesis confidence gate (harness_assess)
    threshold: 0.7             # Pass/fail line, 0..1 — callers may tighten, never loosen
    severity: critical         # Label recorded on verdicts
    route_to_role: account-owner  # Route failed verdicts to this approval role
    expires_after: 72h         # TTL for routed tickets
    policy_ref: POL-9.1        # Policy citation carried as ticket evidence

  approvals:                   # Human-approval gates
    provider: file             # Ticket store: file (persisted) or memory
    dir: .kcp-harness/approvals
    grant_max: 24h             # Hard cap on any approval's validity (default 24h)
    require_signed_resolutions: false  # true: an unsigned/invalid resolution fails closed, at
                                        # resolve() AND when the store is read (recommended)
    require_args_binding: false # true: a ticket not bound to the call's arguments is never a
                                 # grant (recommended; default false for pre-upgrade tickets)
    max_reviewed_at_skew: 5m   # How far ahead of the store's clock a reviewedAt may be (default 5m)
    trusted_keys:               # Optional. Reviewer public keys (paths or inline PEM/base64/
      - ./keys/kari.pub          # hex). When set, a signature must verify against one of these
                                  # to bind it to a named identity; when omitted, the signature's
                                  # own embedded key is used (integrity only, not identity).
    rules:
      - match:                 # Absent criteria match everything; present ones AND together
          tools: [Write, Edit]
          paths: [records/]
        required_role: account-owner
        expires_after: 72h     # Unresolved tickets expire (fail-closed)
        policy_ref: POL-7.2

downstream:
  - name: "filesystem"         # Downstream MCP server name
    command: "npx"             # Command to launch
    args:                      # Arguments
      - "-y"
      - "@modelcontextprotocol/server-filesystem"
      - "."

audit:
  path: ".kcp-harness/audit.jsonl"   # Audit log path

Governed Domains ​

Each domain maps a knowledge.yaml manifest to the paths, URLs, and tools it governs. When a tool call targets a governed path, the harness routes it through the manifest's 14-gate cascade.

You can have multiple domains:

yaml
governance:
  domains:
    - manifest: "./docs/knowledge.yaml"
      paths: ["docs/"]
    - manifest: "./api/knowledge.yaml"
      paths: ["src/api/"]
      urls: ["https://api.example.com/"]

Policy ​

FieldTypeDefaultDescription
fail_closedbooleantrueBlock ungoverned access to governed paths
audit_allbooleantrueLog pass-through (non-governed) tool calls
max_unitsnumber5Maximum knowledge units per plan
strictbooleanfalseReject units below relevance threshold
budgetobject—Monetary budget ceiling (amount + currency)
context_budgetnumber—Token budget ceiling
envstring—Environment name (affects temporal gates)

Human-Approval Gates ​

governance.approvals holds calls for a named human — no matter what the automated governance paths would decide. See Governance Model for the state machine and invariants.

FieldTypeDescription
providerfile | memoryTicket store. file (default) persists to dir and survives restarts
dirstringStore directory (default .kcp-harness/approvals)
rules[].match.toolsstring[]Tool names the rule applies to (absent = all)
rules[].match.pathsstring[]Governed path prefixes (absent = all)
rules[].required_rolestringRole that must approve — required
rules[].expires_afterdurationTicket TTL (30m, 72h, 7d); expired = fail-closed
rules[].policy_refstringPolicy citation carried as ticket evidence
rules[].grantonce | session | durationWhat an approval authorises: the first matching call (once), the opening session (session, default), or a duration (15m, 4h, 1d, same session). Always capped by grant_max. A typo is a config error
grant_maxdurationHard maximum validity of any approval, measured from the moment the store recorded it, not from the reviewer-supplied reviewedAt (default 24h)
require_signed_resolutionsboolRequire a valid ed25519 signature on every resolution (default false). Enforced in resolve() and on every read of the store: an unsigned or unverifiable resolution line is ignored, the ticket stays pending, and the call is denied (grant_denied / invalid). Recommended true, with trusted_keys
trusted_keysstring[]Reviewer public keys (paths or inline PEM/base64/hex) a signature must verify against. Without them the signature's own embedded key is used (integrity, not identity)
require_args_bindingboolNever honour a grant from a ticket that carries no argsDigest (default false, for tickets written before binding was explicit; recommended true). Exempt: the harness_assess ticket, which has no call arguments. See Argument binding
max_reviewed_at_skewdurationHow far ahead of the store's clock a resolution's reviewedAt may be before resolve() refuses it and a read ignores it (default 5m)

An approval is a bounded grant, never a standing permission — see Approval grants. What the ticket store does and does not protect is stated in Ticket store trust model.

A config must govern something ​

kcp-harness check and kcp-harness serve fail (exit 1) when:

  • governance.approvals.rules exist but governance.domains is empty, or
  • governance.domains has entries but none names a paths, urls, tools or skills entry.

Both leave every call outside governance, and an ungoverned call is passed through, so a mangled file would otherwise be silently open. check warns (and still exits 0) when no domain is configured at all, or when approvals are configured but no rule's match.paths overlaps any domain path (no ticket could ever open). A config whose root, governance, or governance.domains has the wrong YAML type (a list, a scalar) is a parse error rather than an empty configuration.

Approval requirements are org policy, not knowledge provenance — they live here in harness.yaml, never in the (signed) knowledge.yaml.

Confidence Gate ​

governance.confidence configures the harness_assess tool.

FieldTypeDescription
thresholdnumberPass/fail line, 0..1. A caller-supplied threshold can tighten this but never loosen it
severitystringLabel recorded on verdicts (e.g. critical)
route_to_rolestringWhen set (and approvals are configured), failed verdicts open an approval ticket for this role
expires_afterdurationTTL for routed tickets
policy_refstringPolicy citation carried as ticket evidence

Conformance Routing ​

governance.conformance routes holds opened by the procedural conformance gate (an active skill's action_scope violation) — independent of the confidence gate above, since "out of scope" and "low confidence" are different events that may need different reviewers or policy citations.

FieldTypeDescription
route_to_rolestringRoute conformance holds to this approval role (requires governance.approvals)
expires_afterdurationTTL for routed conformance tickets
policy_refstringPolicy citation carried as conformance ticket evidence

When governance.conformance is absent, a conformance hold falls back to governance.confidence's routing fields if configured, then to a hardcoded default role (governance-reviewer) with no policy citation.

Audit ​

The audit log is an append-only JSONL file. Each line is a self-contained event. See Audit Log for the full event schema.

Environment Variables ​

VariableDescription
KCP_HARNESS_CONFIGOverride config file path (default: harness.yaml)
KCP_HARNESS_AUDITOverride audit log path
ANTHROPIC_API_KEYRequired if kcp-agent needs Claude API access

Released under the Apache 2.0 License.