Govern
Documentation

Version Latest

Harness packs

Publish signed harness packs in Neural Inverse Govern, gate them on evals, assign them to the organisation, teams and projects, and run A/B experiments with staged rollout.

A harness pack is the developer-experience layer the Neural Inverse Editor puts on top of an agent engine (Claude Code, Codex or the Neural Inverse engine): instructions, skills, subagents, tools and MCP servers, context sources, workflow rules, model routing and evals. Govern stores packs, signs every published version, decides which version each organisation, team and project gets, runs experiments and staged rollouts, aggregates outcome metrics and gates promotion on evals.

Packs are not policy. Agent policy and other governance are evaluated separately and always win; nothing in a pack can weaken them.

The console service is Harness, with the Harness and Experiments pages and Harness usage under Monitor. Routes are under /api/v1/orgs/{orgID}/harness.

Layers

LayerPublished byParent
Starter (claude-starter, codex-starter, neural-inverse-starter)Neural Inverse (platform)None
Sector pack (for example firmware)Platform, or an organisationA starter
Company layerYour organisationA starter or a sector pack
Project layerA file in the repository, resolved by the Editor onlyNone

A layer may lock fields (for example instructions.never_touch). Govern refuses to publish a lower layer that sets a locked field, and checks locks again whenever a version is assigned.

Permissions

PermissionAllowsBuilt-in roles
harness:readList packs and versions, read assignments, experiments, metrics and eval runs; receive one's own packOwner, Admin, Member
harness:publishCreate and archive packs, publish versions, change version statusOwner, Admin
harness:assignSet and remove assignmentsOwner, Admin
harness:experimentStart experiments, advance rollouts, promote, roll back, stopOwner, Admin
harness:eval:submitPost eval runsOnly eval runner keys

harness:eval:submit is matched exactly: no role, wildcard or ordinary API key includes it.

1. Configure signing (operator)

openssl genpkey -algorithm ed25519 -out /etc/keystone/harness-signing.pem
chmod 600 /etc/keystone/harness-signing.pem
export NI_AUTH_HARNESS_SIGNING_KEY_FILE=/etc/keystone/harness-signing.pem
export NI_AUTH_HARNESS_SIGNING_KEY_ID=hk-2026-10            # optional
VariablePurpose
NI_AUTH_HARNESS_SIGNING_KEY_FILE or NI_AUTH_HARNESS_SIGNING_KEY_PEMActive Ed25519 private key. Without it, packs can be read and assigned but not published (503 signing_unavailable).
NI_AUTH_HARNESS_SIGNING_KEY_ID, NI_AUTH_HARNESS_SIGNING_KEY_NOT_BEFOREKey id and start of validity
NI_AUTH_HARNESS_RETIRED_KEYS_FILERotated-out public keys, each with not_after
NI_AUTH_HARNESS_SEED_DIRPlatform manifests published at startup
NI_AUTH_HARNESS_ACTIVITY_RETENTION_DAYSHow long Editor activity events are kept (default 395, at least 91)

The public keys are at GET /.well-known/neuralinverse-harness-keys.json. The Editor verifies every layer with that set and refuses unsigned or tampered packs. Without a seeded starter for an engine, a person with no assignment gets 404 no_harness.

2. Publish

curl -sS -X POST "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/harness/packs" \
  -H "Authorization: Bearer $ORG_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"slug": "acme-firmware", "kind": "company"}'

curl -sS -X POST "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/harness/packs/$PACK_ID/versions" \
  -H "Authorization: Bearer $ORG_ADMIN_TOKEN" -H 'Content-Type: application/yaml' \
  --data-binary @acme-firmware.yaml
  • Each version must be a valid neuralinverse.harness/v1 manifest, greater than every earlier version, with a parent range that matches a published version.
  • Sector and company versions must declare at least one eval.
  • Secrets are references only: MCP server env_refs values must be vault:<name>, and any field named like a credential is refused.
  • Manifests are limited to 1 MiB, 200 skills, 50 subagents, 50 MCP servers and 100 evals.
  • ?draft=true stores an unsigned draft; publish it later with PATCH .../versions/{version} and {"status": "published"}.

Published versions never change. Their status can become deprecated (still served where assigned) or withdrawn (final, never served or assigned).

3. Pass the eval gate

A version can be assigned, run in an experiment or promoted only when it passes the promotion gate on the target engine: a passing eval run recorded for your organisation, or, for a platform version, by a platform runner. Starters are exempt.

Eval runs come from a runner (CI or a sandbox) with an eval runner key. Only a platform super administrator creates runner keys:

curl -sS -X POST "$KEYSTONE_URL/api/v1/harness/platform/runner-keys" \
  -H "Authorization: Bearer $SUPER_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"organization_id": "'$ORG_ID'", "name": "acme-ci", "expires_at": "2027-10-01T00:00:00Z", "reason": "Nightly evals for Acme"}'

The runner posts results:

curl -sS -X POST "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/harness/packs/$PACK_ID/versions/1.0.0/eval-runs" \
  -H "Authorization: Bearer $RUNNER_API_KEY" -H 'Content-Type: application/json' \
  -d '{"engine": "claude-code", "model": "claude-sonnet-5-5", "logs_ref": "ci://runs/1842",
       "results": [{"eval_id": "uart-bringup", "passed": true}]}'

Every declared eval needs exactly one result; the run passes when all pass. A super administrator can bypass the gate with override_reason, which is audited as harness.eval_gate.overridden.

4. Assign

curl -sS -X PUT "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/harness/assignments" \
  -H "Authorization: Bearer $ORG_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"scope": "team", "scope_id": "'$TEAM_ID'", "pack_id": "'$PACK_ID'", "version": "1.0.0", "engine": "claude-code"}'

scope is org, team or project (a repository identifier such as github.com/acme/fw). Parent ranges are resolved to exact versions when you assign, so a newer starter changes nothing until you assign again. The most specific assignment wins: project, then team, then organisation. Remove one with DELETE .../assignments?scope=team&scope_id=<team id>.

The Editor calls GET /api/v1/me/harness?project=<repository>&engine=<engine> at sign-in and every 15 minutes.

5. Experiment and roll out

curl -sS -X POST "$KEYSTONE_URL/api/v1/orgs/$ORG_ID/harness/experiments" \
  -H "Authorization: Bearer $ORG_ADMIN_TOKEN" -H 'Content-Type: application/json' \
  -d '{"scope": "org", "engine": "claude-code",
       "control": {"pack_id": "'$PACK_ID'", "version": "1.0.0"},
       "candidate": {"pack_id": "'$PACK_ID'", "version": "1.1.0"},
       "candidate_percentage": 5, "bucket_unit": "user", "min_sample": 100}'

Each person (or project, with bucket_unit: project) lands in a sticky bucket; buckets below the candidate percentage get the candidate. Both arms must pass the eval gate.

ActionRoute
Raise the rollout (it can only go up)POST .../experiments/{id}/rollout with {"candidate_percentage": 25}
Promote the candidatePOST .../experiments/{id}/promote
Roll back to the controlPOST .../experiments/{id}/rollback
Stop without a decisionPOST .../experiments/{id}/stop
Results per armGET .../experiments/{id}/results

Results show metrics and deltas only once both arms reach min_sample. GET .../packs/{packID}/versions/{version}/metrics aggregates sessions, suggestions kept, edited and discarded, tasks completed, median duration, tokens and cost. Editor activity events carry identifiers, counts and outcomes only, so no code, prompt or completion is stored.

Audit

Pack, version, assignment, experiment, eval run and runner key changes are audited inside the transaction of the change (harness.pack.created, harness.version.published, harness.assignment.set, harness.experiment.promoted, harness.eval_run.recorded and others). On the hosted service, custom packs and experiments depend on the plan (403 not_entitled); self-hosted includes everything.

Last reviewed 17 October 2026View as Markdown

Harness packs · Docs · Neural Inverse