Use

Audit

Audit a project for hidden Unicode, lockfile hash drift, and apm-policy.yml.

ht audit is the on-demand security check for files that agents will read. Built-in protection already runs on ht apply (and ht pack); use audit locally or in CI to re-scan a tree, inspect a file obtained outside HarnessTap, or remediate hidden characters. When apm-policy.yml is present, audit loads it and evaluates the install plan (manifest + lockfile + local tree).

ht audit
ht audit --file .cursorrules
ht audit --ci --format json
ht audit --ci --require-policy
ht audit --strip --dry-run

What it scans

With no flags, audit scans lockfile-recorded deployed files (local_deployed_file_hashes in apm.lock.yaml) plus local primitive dirs (.apm/agents|skills|commands|hooks and root agents|skills|commands|hooks) and root context files (AGENTS.md, CLAUDE.md, GEMINI.md).

--file scans one path instead. The path must stay inside the project root (.. and symlink escapes are rejected).

Flags

FlagPurpose
--file <path>Scan a single file
--ciFail on critical hidden Unicode, lockfile SHA-256 mismatch / extra / missing, blocking policy, or required-executable-untrusted
--policy <path>Policy file (default apm-policy.yml at the project root)
--require-policyWith --ci, fail if no policy file is present
--stripRemove critical and warning characters (preserves emoji ZWJ sequences)
--dry-runPreview --strip without writing
--project <path>Project directory (default .)
--format jsonMachine-readable report

--ci cannot be combined with --strip, --file, or --dry-run. --dry-run requires --strip. --require-policy requires --ci.

Policy

apm-policy.yml at the project root is optional. Without it, audit still runs Unicode and path checks and reports policy: skipped. A pinned policy.hash on apm.yml is fail-closed: missing or mismatched policy bytes fail, including under --ci.

Slice 1 evaluates:

  • Sourcesdependencies.allow / deny against git hosts (github.com/*), catalog identities, and local paths
  • Primitivesmanifest.content_types.allow (skill, agent, command, hook, instruction, mcp)
  • Transitive MCP — undeclared MCP from depth > 0 fails unless mcp.allow lists it or mcp.trust_transitive: true (default false)

mcp.trust_transitive is a shipped slice-1 field (default false). It is not a broader trust model.

enforcement: block (and load/hash failures) fail --ci and abort ht apply before any byte is written. enforcement: warn reports violations without changing the exit code.

When the executable trust gate is on, executables.require packages whose executables are untrusted fail --ci with required-executable-untrusted. Approve them with ht approve <ref> (or deny explicitly). Lockfile exec_status records the resolved state per dep. See Executable trust.

See also: Apply.

Exit codes

CodeMeaning
0Clean, info-only, or successful --strip
1Critical Unicode, or --ci integrity failure
2Warning-only findings, or mutually exclusive flags

Apply already blocks critical Unicode before writing unless you pass ht apply --force. --force overrides Unicode only — it does not skip lock SHA-256 checks. Hash drift on a later apply fails closed; refresh with ht apply --update.

See Apply and Pack.