Command reference

Canonical HarnessTap CLI commands, aliases, and important flags.

This page mirrors the grouped CLI surface exposed by harnesstap --help. Use it as the canonical reference for command names, aliases, and the most important flags. For workflow examples, see the scenario guides.

Global options

Available on harnesstap / ht:

  • -V, --version prints the HarnessTap CLI version (--harnesstap-version is a hidden alias)
  • -v, --verbose - show verbose error output
  • --no-color - disable ANSI colors
  • --no-interactive - disable interactive prompts
  • -h, --help - show help

Noun shorthand aliases

Full nounAlias
pluginl (legacy shorthand from the old layer noun)
resourcer
harnessh
environmente
profilep
autha
migratem

help

Core HarnessTap concepts and a numbered scenario index. Scenario playbooks live in docs/scenarios/details/.

ht help
ht help --format json
ht help scenario 11
ht help scenario 7 --format json

init

Initialize local HarnessTap state.

ht init
ht init --harnesses claude-code,cursor,codex
ht init --format json

Key options:

  • --harnesses <slugs> - comma-separated registered harness slugs
  • --main <slug> / --aliases <slugs> - deprecated; prepended/appended to the registered set
  • --no-default-profile - skip seeding the global default profile plugin and active-profile.json pointer
  • --interactive - prompt for harness selection instead of relying on explicit flags
  • --format <mode> - human or json

init seeds a local global default profile plugin (tagged profile) from library resources imported from home only when no profile plugins exist yet. Re-running init or starting Desktop does not recreate global default after a rename or when other profiles are present. It writes active-profile.json when that profile is created or the pointer is unset (unless --no-default-profile), and prints the tracked directory list (home as ~). Global apply does not run automatically - run ht profile use "global default" to materialize home harness files.

init completion

Generate shell completion scripts for bash, zsh, or fish. After installation, Tab completes:

  • subcommands and flags for every ht command
  • dynamic values such as local plugin, profile plugin, and resource names
  • harness slugs, cloud accounts, and catalog plugins (when authenticated) for supported commands

Install by appending or saving the script for your shell:

ht init completion bash >> ~/.bashrc
ht init completion zsh >> ~/.zshrc
ht init completion fish > ~/.config/fish/completions/ht.fish

Restart your shell or source the file, then try ht plugin show <Tab> to list local plugins.

Both ht and harnesstap invocations are supported.

add

Install skills from a remote GitHub repo, Git URL, or local skill-package directory. Discovers skills recursively under skills/ or .agents/skills/, imports the full package into the HarnessTap library, and installs a selected subset to disk.

ht add mattpocock/skills
ht add mattpocock/skills --list
ht add mattpocock/skills --skill caveman,grill-me --global --yes
ht add mattpocock/skills --create-plugin mattpocock-skills --global -y
ht add ./local/skills-repo --project .
FlagPurpose
--skill <names>Install subset (comma-separated)
--allInstall all discovered skills
--harness <slugs>Target harnesses (default: all registered harnesses)
--globalInstall to user home paths
--project [path]Install to project directory (default . when flag present without value)
--method symlink|copyInstallation method (default symlink)
--plugin <name>Attach installed skills to an existing plugin
--create-plugin <name>Create a plugin and attach installed skills
--listDiscover skills only; no import or install
--dry-runShow plan without writing
-y, --yesSkip interactive prompts
--format human|jsonOutput mode

Scope rule: exactly one of --global or --project must be resolved before install (the wizard asks if neither is set). Import to the library always runs on a successful add except with --list or --dry-run.

Project-local verbs

Git-style commands for working in a project directory. Each defaults to the current directory when [path] is omitted.

Commands

  • scan [path] - import resources from a project tree (hash-aware upsert; prompts on content drift when interactive)
  • use - switch to a project-configured profile from apm.yml (ht use --profile <key>, not a positional profile name)
  • mirror [path] - rematerialize other registered harnesses from --from (default first registered)
  • status [path] - show project status with drift summary
  • history [path] - list snapshots for a tracked project
  • revert [snapshot-id] - restore files from a previous snapshot

Apply plugins with top-level apply (not under this group). Onboard from repo-root apm.yml with top-level install (the same loop as apply with no plugin selector). Preview resolved apply targets with targets; compile is the same apply-from-manifest loop under a named entry.

Important options

  • scan --harness <slug> - scan only one harness

  • scan --dry-run - preview imports without writing to the DB

  • scan --overwrite - replace library rows when scan content differs

  • scan --skip-existing - keep existing rows when scan content differs

  • scan --namespace <name> - namespace for imported project resources (default: project; home scan stays empty / global)

  • scan --global - install imported plugin sources into global harness locations

  • scan --harness <slugs> - harness targets for --global plugin installs

  • use --profile <key> - profile key from apm.yml (required unless --list)

  • use --list - list profiles from project config without applying

  • use --dry-run - preview global apply without writing

  • use --force - apply even when the profile is already active and in sync

  • use --no-pull - fail when composition refs are missing locally

  • use --harness <slugs> / --on-conflict <replace|skip|prompt|cancel> / --account <name> / --base-url <url> / --format json

  • mirror --dry-run - preview rematerialize writes

  • mirror --from <slug> - on-disk harness to copy from (--force-shift-reference is a deprecated alias)

  • mirror --reference <strategy> - reference source: disk, plugin, agents, auto (main is a deprecated alias of disk)

  • mirror --format json

  • status --check - exit 1 when drift exists since the last snapshot, or when apm.lock.yaml disagrees with the applied manifest (CI)

  • status --format json - includes a drift object when git-backed

  • history --format json

  • history --show-id - show full snapshot IDs in human tables

  • status shows an Updates row when the last upstream check (plugin check, or the Desktop sidecar) found newer versions; status --format json adds updates: {count, major_count, items}. Status reads the stored result and never calls the network.

Preconditions and side effects

  • history, status --check, harness project set, and harness project status require a git repository with a configured origin remote.
  • apply can write files in non-git directories, but snapshots are only stored when the project has a git origin.
  • revert requires a snapshot ID from history.
  • apply resolves environment values through the cascade: home environment ◂ configured-plugin default (last wins).

install

Project onboarding from repo-root apm.yml. Same loop as apply with no plugin selector: not a second resolver and not Microsoft's apm CLI.

ht install
ht install --project .
ht install --target cursor,claude
ht install --mcp io.github.github/github-mcp-server --target cursor
ht install --harness claude-code,cursor
ht install --dry-run
ht install --update
ht install --force

Reads dependencies.apm (and transitive dependencies.apm on fetched git / catalog / path packages) / dependencies.mcp (including MCP Registry v0.1 identities such as io.github.github/github-mcp-server), compiles local .apm/ primitives, writes apm.lock.yaml, and materializes the resolved target harness directories. Registry strings fetch GET /v0.1/servers/{id}/versions/latest from registry.modelcontextprotocol.io and emit the same native MCP files HT already writes. Self-defined registry: false entries stay inline. --mcp <id> appends the identity to apm.yml then runs install; a failed install rolls the manifest write back. Target resolution: --target / --all / --harness, then targets: in apm.yml, then project/global harness preference, then filesystem auto-detect. Declared targets: wins over preference and folder detection. Fails closed when no target can be resolved. Commit the lockfile plus generated harness output (.claude/, .cursor/, AGENTS.md, and so on). Same project-scope flags as apply. Does not take a plugin selector or --global. See the Use ramp: install a project.

ht install --mcp io.github.github/github-mcp-server --target cursor

mcp

Discover and install MCP Registry v0.1 servers. Same registry and emit path as ht install.

ht mcp search github
ht mcp list
ht mcp show io.github.github/github-mcp-server
ht mcp install io.github.github/github-mcp-server --target cursor

mcp install is an alias of ht install --mcp. Search/list/show call the official registry only. Install uses the same apply-from-manifest loop as ht install (including transitive dependencies.apm).

lock export

Serialize apm.lock.yaml into a CycloneDX 1.5 (default) or SPDX 2.3 SBOM inventory. Reads the lockfile only: no re-resolve, no re-hash, no network. Not a signed attestation and not SLSA. See the Use ramp: export a lockfile SBOM.

ht lock export
ht lock export --format cyclonedx -o sbom.json
ht lock export --format spdx --timestamp 2024-06-01T00:00:00+00:00
ht lock export --project .

Key options:

  • -f, --format <format>: cyclonedx (default) or spdx
  • -o, --output <file>: write a file instead of stdout
  • --project <path>: project directory (default .)
  • -g, --global: read ~/.harnesstap/apm.lock.yaml when that file already exists
  • --timestamp <ts>: pin timezone-aware ISO 8601 for reproducible output (else SOURCE_DATE_EPOCH, then lockfile generated_at)

Declared licenses come from lock declared_license (the dependency manifest license: recorded at apply/install). Undeclared licenses are omitted in CycloneDX and written as NOASSERTION in SPDX.

apply

Top-level apply resolves a plugin (and its dependency graph) and materializes it.

  • Default scope is the project (cwd / --project).
  • Pass --global to materialize into machine home paths (profile plugins also update the active profile pointer when applicable).
  • First human line reports destination (→ project ... or → machine home ...).
  • Flags include --dry-run, --explain, --update, --target, --all, --harness, --strict-plugin-versions, --ignore-plugin-versions, --sync-plugins, and --force (override critical hidden-Unicode findings).
  • Selectors may be local plugin names, catalog identities, a packed bundle directory, a .zip produced by ht pack, or a .ap.json envelope. Packed bundles with pack.bundle_files are rehashed and fail closed on tampering.
  • With no selector, apply is the same loop as ht install: it reads apm.yml. Git entries in dependencies.apm resolve to an exact commit, fetch that SHA, and record repo_url / resolved_commit (plus path when set) in apm.lock.yaml. After each fetched git / catalog / path APM package, apply walks that package’s dependencies.apm and pins those too. Cycles, missing packages, and hash mismatches fail closed; the root manifest wins on name collisions. A later apply without --update replays the lock. See Apply git dependencies and the Use ramp: install a project.
  • With no plugin selector, apply compiles local .apm/ primitives (and root primitive dirs when .apm/ is absent) into the resolved target harness directories via the existing writers. Resolution: --target / --all / --harness, then apm.yml targets / target, then compilation.target, then project/global harness preference, then filesystem auto-detect. Apply-from-manifest fails closed when no target resolves. See the Use ramp: apply to a project.
  • Before writing, apply scans generated files for hidden Unicode. Critical findings block apply unless --force is passed; warnings are printed and apply continues. When apm.lock.yaml already has local_deployed_file_hashes and --update is not set, apply rehashes the generated tree and fails closed on mismatch, extra, or missing files.
  • When executables: is opted in (project block or non-empty policy executables:), unapproved dependency hooks / bin / self-defined MCP are parked. Apply still succeeds and prints ht approve <ref>. The lock records exec_status.

ht layer ... is a hidden deprecated alias for ht plugin ... for one release; prefer ht plugin and top-level ht apply.

MCP servers from an Agent Plugins package keep cwd and an HTTP transport of streamable-http or sse. Apply warns when a harness cannot write cwd, and when sse is written as that harness's HTTP form. ${PLUGIN_ROOT} and ${PLUGIN_DATA} stay as written in the library. Import copies the package to ~/.harnesstap/cache/agent-plugins/<plugin>/<version>/ and records a hash for each file it writes. Host MCP configs expand those variables to that directory and to ~/.harnesstap/plugin-data/<plugin>. A command that starts with ./ is resolved against the package directory and stays one token when the path contains spaces. cwd is written for Claude Code, Codex, Copilot, and Grok. Cursor has no cwd field, so the command path is absolute and apply warns that the working directory is not written. The plugin data directory is created only when it is missing. HarnessTap records that ownership and leaves an existing unowned directory or file in place. An existing unowned file in the package directory is left in place. Owned files that are replaced or removed are backed up.

Set harnessSync.nativeAgentPlugins to true to register Agent Plugins packages for Codex and Copilot instead of extracting their skills and MCP servers. The default is off. Codex entries are [plugins."<name>@harnesstap"] in config.toml. Copilot entries are enabledPlugins keys in .copilot/settings.json. Other keys stay. Turning a package off removes only those @harnesstap keys and the cache files HarnessTap wrote. A config with no @harnesstap keys to add or remove is left as it is, including when the flag is on and the profile does not register a package.

The Cursor and Claude copies of an Agent Plugins package rewrite those variables in the emitted tree only. Cursor writes ${CURSOR_PLUGIN_ROOT} and an absolute plugin data path. Claude writes .claude-plugin/plugin.json, .mcp.json (streamable-http and sse as http, ${CLAUDE_PLUGIN_ROOT} and ${CLAUDE_PLUGIN_DATA}), and copies com.harnesstap commands, agents, and hook JSON into the Claude plugin directories. A file HarnessTap does not own inside a Cursor local plugin is left in place. Owned removals are backed up.

Host MCP configs expand ${PLUGIN_ROOT}, ${PLUGIN_DATA}, and ./ commands for an import, a marketplace pin, a git import, and a local install tree. The library copy stays literal.

Host MCP configs write the POSIX command server on Linux and macOS, and the Windows .cmd server on Windows. A missing or mismatched plugin pin says Run: ht resource sync plugin_pin:<ref>.

compile

Named entry over apply-from-manifest: compile local .apm/ primitives into the resolved target harness directories. Same writers and local_deployed_file_hashes as ht install / ht apply. See the Use ramp: compile for declared targets.

ht compile
ht compile --target cursor
ht compile -t claude,cursor --dry-run
ht compile --all

Resolution: --target / --all / --harness, then targets: in apm.yml, then project/global harness preference, then filesystem auto-detect. Fails closed when no target resolves. Does not take a plugin selector or --global.

targets

Show which apply harness targets resolve for this project, and why. This is not ht harness list.

ht targets
ht targets --json
ht targets --all --json

Same resolution order as ht compile. --json emits one object per canonical target plus the resolved list. --all includes the agent-skills meta-target row.

pack

Pack a project that has apm.yml into an Agent Plugins 1.0 bundle (plugin.json, primitive dirs, embedded apm.lock.yaml). See the Author ramp: pack a bundle.

ht pack
ht pack --archive -o ./dist
ht pack --dry-run --verbose

Key options:

  • -o, --output <dir>: output directory (default build)
  • --archive: write a .zip instead of a directory
  • --dry-run: print the file list without writing
  • --verbose: list every packed file and remapping
  • --project <path>: project directory (default .)
  • --format json

Consumers install the artifact with ht apply <dir-or-zip>. Bundles are target-agnostic. There is no --format apm flag.

audit

Scan a project for hidden Unicode, verify lockfile SHA-256 hashes, and evaluate apm-policy.yml. See the Use ramp: audit a project.

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

Key options:

  • --file <path>: scan one file
  • --ci: fail on critical Unicode, lockfile hash mismatch / extra / missing, blocking policy, or required-executable-untrusted
  • --policy <path>: policy file (default apm-policy.yml)
  • --require-policy: with --ci, fail if no policy file is present
  • --strip: remove critical and warning hidden characters (preserves emoji)
  • --dry-run: preview --strip
  • --project <path>: project directory (default .)
  • --format json

--ci cannot be combined with --strip, --file, or --dry-run. --dry-run requires --strip. --require-policy requires --ci. Required-but-untrusted executables fail --ci with required-executable-untrusted.

approve

Approve executable primitives from dependency packages. Writes project apm.yml executables.allow by default.

ht approve owner/repo
ht approve --user owner/repo
ht approve --pending
ht approve --all
ht approve --recommended
ht approve --list

--user writes ~/.harnesstap/config.jsonc (can only narrow past an org or project deny). Grant keys are owner/repo or owner/repo#version (version-blind in v1).

deny

Block executable primitives. Writes project apm.yml executables.deny by default; --user writes the personal store.

ht deny owner/repo
ht deny --user owner/repo

policy explain

Print the effective executable-trust decision for one package: allowed or blocked per type, deciding layer, and shadowed layers.

ht policy explain owner/repo
ht policy explain owner/repo --format json

plugin (l)

Manage design plugins (resource bundles), composition attachments, portable bundle export/import, and HarnessTap Cloud catalog workflows.

Remote library discovery, install, and publish live on plugin, not auth. Use auth only for authentication and org context.

Commands

  • plugin create <name>

  • plugin list - local plugins plus streamed remote catalog plugins (default); use --local-only for local plugins only

  • plugin show <name>

  • plugin editor [name] - open a plugin definition file in your system editor

  • plugin search [query] - search marketplace catalogs for plugins (name, tags, plugin.json, nested skills/commands)

  • plugin add <ref> - import a GitHub plugin.json package into the library (https://github.com/owner/repo, owner/repo, or gh:owner/repo)

  • plugin add <ref> --to <plugin> - add a dependency to a plugin (ref: local name, org/catalog/name, name@marketplace, or git URL)

  • plugin edit [name] - interactively add/remove attachments, set default environment, or script changes with --add / --remove / --apply / --environment / --clear-environment

  • plugin delete [name]

  • Prefer top-level apply [plugin...] (see above). The old plugin apply / l apply spelling was removed when apply moved to the root.

  • plugin cut <plugin> --version <semver> - cut a new local version from the working head

  • plugin versions <plugin> - list local versions (head + frozen)

  • plugin rollback <plugin> --to <semver> - copy a frozen version onto the working head

  • plugin fork <plugin> - copy an upstream or catalog plugin into an editable authored plugin (default name <plugin>-fork; local authored plugins cannot be forked)

  • plugin pull <selector> - download a remote plugin bundle and import it

  • plugin catalog list - show default catalog, connected orgs/libraries, registered publish catalogs, and cloud base URL

  • plugin catalog - interactive publish-binding wizard (plugin picker → catalog checkboxes)

  • plugin catalog bindings [plugin] - show effective publish targets (non-TTY) or edit bindings (--add, --remove, --clear; --add replaces the full allow list)

  • plugin catalog register org/catalog - register a publish destination

  • plugin catalog unregister org/catalog - remove a publish destination from the registry

  • plugin catalog registered - list registered publish catalogs

  • plugin catalog connect org <slug> - opt into another org's public libraries (saves the org even when it currently has no public plugins; warns, exit 0)

  • plugin catalog disconnect org <slug>

  • plugin catalog connect plugin <org>/<slug> or <org>/<catalog>/<slug> - opt into a single public library

  • plugin catalog disconnect plugin <org>/<slug> or <org>/<catalog>/<slug>

  • plugin publish <plugin> - export bundle and upload to all effective publish targets (registered catalogs, or per-plugin allow list)

  • plugin publish plan <plugin> - dry-run: list effective targets and planned versions

  • plugin diff <left> <right>

  • plugin doctor [name] - validate a plugin without writing to disk

  • plugin check [name] - compare library working heads to marketplace, git, and catalog origins

  • plugin update [name] - update a working head from origin (--all for every outdated syncable head)

  • plugin why <target> - explain why a version was selected or which plugin won a resource (skill:name, plugin name)

  • plugin from-project [name] --project <path>

  • plugin validate <file> - load an Agent Plugins directory, zip, or .ap.json and report skills, MCP servers, skipped entries, and ignored manifest fields (--spec 1.0.0, --format json)

  • plugin publish --strict blocks when export warnings are present (a renamed skill, a secret moved out of mcp.json, or a skipped MCP server). A wrong $schema or an unusable mcp.json always blocks publish.

  • plugin publish --vendor-extensions and migrate export --plugin --vendor-extensions also write Copilot files under com.github.copilot/ and Codex hook settings under extensions["com.openai"]. The flag is off by default. Existing vendor files are left in place. A hook command that points at a file outside the package is copied next to that hooks file and rewritten to a relative path. A hook whose script cannot be read is left out, with a warning.

  • Human migrate export prints a path under your home directory as ~/.... JSON output keeps the absolute path.

  • migrate export --plugin --archive (or a path ending in .zip) writes the Agent Plugins package as a zip. It does not replace a directory.

  • A directory whose root plugin.json uses the Agent Plugins 1.0.0 $schema is an agent plugin. Import keeps author, homepage, repository, and license, and keeps vendor namespace objects and their directories (for example com.openai and com.github.copilot). Path overrides in that manifest are ignored. Root agents, commands, and hooks are still read, with a warning.

Important options

  • plugin create -d, --description <text> - plugin description
  • plugin create --tags <tags> - comma-separated tags
  • plugin create --version <semver> - plugin version (default 1.0.0)
  • plugin create --from <source> - import a skill package (owner/repo, git URL, or local path) and attach selected skills
  • plugin create --skill <names> - comma-separated skills to attach when using --from
  • plugin create --all - attach all discovered skills when using --from
  • plugin create --exclude-category <names> - exclude skill categories (repeatable or comma-separated)
  • plugin create --on-conflict <policy> - when the plugin exists: replace, skip, prompt or cancel (default cancel). merge is plugin import only. Aliases for one release: overwrite -> replace, ignore -> skip, fail -> cancel.
  • plugin create --install - opt-in hub install; requires --global or --project
  • plugin create --dry-run - preview configuration without writing
  • plugin list --format json
  • plugin list --show-id
  • plugin list -s, --search <query> - filter local and remote plugins by name, description, or tags
  • plugin list --local-only - list only local plugins
  • plugin list --remote-only - skip local section; remote-only JSON emits a top-level array
  • plugin list --tag <tag> - filter remote catalog plugins by tag
  • plugin list --account <name> / --base-url <url> - cloud account and base URL for remote listing
  • plugin list --no-interactive - disable TTY browse wizard (streaming print-only)

See Interactive list keyboard reference for TTY browse/search shortcuts.

  • plugin show --format json
  • plugin editor --format json
  • plugin search --refresh - refresh marketplace catalogs before searching
  • plugin search --plugin <name> - attach the selected plugin pin to this plugin (interactive browse picker on TTY)
  • plugin search --format json / --no-interactive
  • plugin add --to <plugin> - required when ref is not a GitHub plugin source (deprecated --layer alias)
  • plugin add --format json
  • plugin edit --type <type> - restrict tables to one attachment type
  • plugin edit --search <query> - pre-fill the interactive search filter
  • plugin edit --show-id
  • plugin edit --all - show every resource per type (default caps at 10)
  • plugin edit --dry-run - preview membership changes without writing
  • plugin edit --format json --no-interactive - read-only membership snapshot
  • plugin edit --add <selector> - add attachment (repeatable; use --type when selector omits prefix). Plugin dependencies use plugin:ref@source (marketplace, local path, git URL, or org/catalog/name); legacy plugin_pin: / plugin: still resolve with a notice
  • plugin edit --remove <selector> - remove attachment (repeatable)
  • plugin edit --apply <file.json> - apply membership from JSON spec
  • plugin edit --version <constraint> - plugin dependencies only (scripting adds)
  • plugin edit --sync - sync an upstream plugin immediately after add (default: lazy)
  • plugin edit --embed - mark plugin dependency as embed-on-export when adding
  • plugin edit --environment <name> - bind a default environment to the configured plugin that apply resolves
  • plugin edit --clear-environment - clear the configured plugin default environment
  • apply --project <path> - target project directory (default .)
  • apply --target <slugs> / --all / --harness <slugs> - APM target slugs or HarnessTap harness slugs (same resolution slot)
  • apply --on-conflict <replace|skip|prompt|cancel> - what to do when it already exists. Non-interactive apply still falls back to replace today; DS-6 default is cancel (W2-12). Aliases: overwrite -> replace, ignore -> skip, fail -> cancel.
  • apply --dry-run - show planned file writes only
  • apply --explain - print the resolution trail (selected versions and every resource decision)
  • apply --update - ignore apm.lock.yaml and re-resolve the dependency graph (including git dependencies.apm refs)
  • apply --strict-plugin-versions / --ignore-plugin-versions / --sync-plugins
  • plugin why --project <path> - project with the lockfile to inspect (default .)
  • plugin why --root <plugin> - resolve against this root instead of the lockfile root
  • plugin why --format json
  • plugin cut --version <semver> - required new version (must differ from the current head)
  • plugin cut --format json
  • plugin versions --format json
  • plugin rollback --to <semver> - frozen version to copy onto the working head
  • plugin rollback --yes - skip confirm (required when non-interactive)
  • plugin fork --as <name> - name for the authored fork (default <plugin>-fork)
  • plugin fork --format json
  • plugin diff --format json
  • plugin doctor --check <name> - run one check (repeatable)
  • plugin doctor --list-checks - list available checks
  • plugin doctor --format json - exits 1 when the plugin is invalid
  • plugin check --refresh - force-fetch origins (otherwise check may use the marketplace refresh cache)
  • plugin check --format json - same rows as the human table; exits 1 when any row is error
  • plugin update --all - update every outdated syncable working head
  • plugin update --force - reapply even when fingerprints match
  • plugin update --yes - skip --all confirmation (required off-TTY)
  • plugin update --format json - exits 1 when any row is failed
  • plugin from-project -d, --description <text>
  • plugin from-project --harness <slug>
  • plugin pull --as <name>
  • plugin pull --org <slug>
  • plugin pull --catalog <slug> - catalog slug when selector omits catalog (default default)
  • plugin pull --version <constraint>
  • plugin pull --account <name>
  • plugin pull --base-url <url>
  • plugin publish org/catalog - one-off publish to a single catalog (does not change bindings)
  • plugin publish --org <slug> --catalog <slug> - one-off override (same as positional org/catalog)
  • plugin publish --account <name>
  • plugin catalog bindings --add org/catalog - replace per-plugin allow list (repeatable; auto-registers missing catalogs)
  • plugin catalog bindings --remove org/catalog - remove one target from the allow list
  • plugin catalog bindings --clear - revert plugin to all registered catalogs
  • plugin catalog register --account <name> - optional account for a registered catalog

plugin pull and plugin list remote discovery query catalog scope plus registered publish catalogs (plugin catalog register). Use plugin catalog connect to add other public orgs or libraries explicitly. Register publish destinations with plugin catalog register before plugin publish when no bindings exist. plugin pull fails on local name conflict instead of overwriting. apply resolves bare catalog names at apply time; use plugin pull to install plugins for offline reuse. Apply resolves nested plugin dependencies as a graph (nearest-to-root resource precedence; equal-depth set-like types use declaration order with a warning).

  • plugin edit <name> --hide <type>:<name> / --unhide <type>:<name> - hide or show an inherited item on a profile that keeps in sync, for example skill:review or plugin:web-search (repeatable)

  • plugin check also checks every upstream link (kept-in-sync and separate-copy profiles, and pulled catalog packages) for newer versions and stores the result, so ht status and Desktop read the same answer without a network call. --format json adds an upstream array with status of current, update, major, unreachable or unpublished. A newer major version shows as major and is never installed automatically.

  • ht plugin auto-update prints how plugin updates are checked; --mode off|notify|install and --frequency hourly|daily|weekly change it (stored under updates in ~/.harnesstap/config.jsonc). Install mode installs minor and patch versions inside the range for pulled catalog plugins, never a major. After the first successful ht plugin update --all that installs something in an interactive terminal, HarnessTap asks once "Keep plugins up to date?" with the same choices; non-interactive runs never ask.

notifications

Local notifications about plugin updates. HarnessTap writes one when a check finds a new version, when a synced profile's parent publishes, when install mode updates a plugin, and when update checks keep failing. The same version is never notified twice.

  • ht notifications lists unread notifications; --all includes read ones, --format json returns {items, unread_count}.
  • ht notifications read <id> marks one as read; ht notifications read --all marks every one.
  • ht notifications prune --older-than 90d deletes read notifications older than the age (h, d or w). It asks first in a terminal and needs --yes otherwise. Unread notifications are never pruned, and nothing is deleted without this command.

auth (a)

Manage HarnessTap Cloud authentication and cloud account state.

Commands

  • auth login [account]
  • auth status
  • auth orgs
  • auth logout

Important options

  • auth login --base-url <url>
  • auth status --account <name> --format json
  • auth orgs --switch <slug>
  • auth orgs --format json: when not logged in, prints [] on stdout and warns on stderr (human mode warns on stdout)
  • auth logout --account <name>

Token refresh runs before remote calls. The CLI does not silently switch accounts or organizations during other commands. There is no --profile flag on auth: use --account.

github

Authenticate with GitHub via the HarnessTap GitHub App device flow. Distinct from auth (HarnessTap Cloud). Stores a user-to-server token in ~/.harnesstap/github-session.json (0600) and uses it for private GitHub marketplace and git reads (Authorization basic x-access-token extraheader, never a token in the clone URL). Private Contents require the App to be installed on the target account or org.

Does not require gh. Client id is public (Iv23liiaeCAUoGKe2uUx; override HARNESSTAP_GITHUB_APP_CLIENT_ID). Never commit a client secret. If token exchange or refresh needs one, set HARNESSTAP_GITHUB_APP_CLIENT_SECRET.

Credential precedence: HARNESSTAP_GITHUB_TOKEN → GH_TOKEN → GITHUB_TOKEN → stored session → gh auth token → ambient Git.

Commands

  • github login
  • github status
  • github logout

Important options

  • github status --format json

profile (p)

Manage profile plugins (plugins tagged profile) and global profile switching. Profiles apply to machine home harness paths; use apply for projects.

Root shorthand: when the first non-option argument is not a known command and matches a local profile plugin name, ht <name> runs profile use <name>, leaving any leading global flags in place (e.g. ht work, ht --no-color work).

Commands

  • profile list / profile ls: list local profile plugins, then stream remote catalog plugins with tag=profile; marks active profile
  • profile show <name>: same detail view as plugin show, plus active profile marker
  • profile status: active profile and whether global harness files are in sync
  • profile use <name>: merge profile stack, apply globally, set active pointer
  • profile create <name>: create profile plugin, promote an existing plugin, or import from --from
  • profile delete <name>: demote a profile plugin and optionally delete the underlying plugin
  • profile pull <selector>: install from catalog (plugin pull alias; warns if not profile-tagged)
  • profile publish <name>: publish with profile validation warnings (plugin publish alias)
  • profile preview [name]: apply preview (home/project/both) without writing. Inherited host-plugin material already on disk is omitted from stack/file deltas; host-native plugin MCP is treated as present.
  • profile switch <name>: switch active profile (restores the previous profile on failure; see --help for conflict flags)
  • profile stash: stash untracked on-disk resources for the active profile
  • profile stash list / profile stash pop / profile stash apply: list, restore-and-remove, or restore stashed profiles
  • Live files: profile add-resource, add-all-resources, commit-resource, remove-resource, restore-file, file-diff: adopt, snapshot, detach, or diff on-disk resources against the profile library (--scope home|project, --project when scope is project)

A cancelled profile use does not list .harnesstap/cache/native-agent-plugins/ files as changes. Apply still writes that cache.

  • profile duplicate <source> [name]: duplicate a profile. By default the copy keeps in sync: it shows the parent's items live, at the newest installed parent version in the same major, and stores only its own additions and hidden items. --copy makes a separate copy instead (the items are copied now; later parent changes do not apply). --to <org>/<catalog> asks Cloud to make and publish the duplicate of a catalog profile instead (--account picks the Cloud account); when Cloud cannot duplicate yet, the copy is made in your Library.
  • profile detach <name>: stop keeping a profile in sync. Its current items (the parent's, minus hidden ones, plus its own) become its own in the Library. Nothing is applied or deleted; the profile still shows where it came from.

Important options

  • profile list --format json
  • profile list -s, --search <query> - filter local and remote profile plugins
  • profile list --local-only - list only local profile plugins
  • profile list --remote-only - skip local section
  • profile list --account <name> / --base-url <url> / --no-interactive
  • profile show --format json
  • profile show --show-id
  • profile status --check - exit 1 when global state is out of sync
  • profile status --harness <slugs> / --format json
  • profile create -d, --description <text>
  • profile create --from <source> - same skill-package options as plugin create --from
  • profile create --use - apply globally and set active after create/promote
  • profile create --use --dry-run - preview global apply
  • profile create -y, --yes - skip the interactive enable prompt
  • profile delete --plugin - also delete the underlying plugin without prompting
  • profile delete -y, --yes - skip the interactive plugin delete prompt
  • profile use --profile <key> - profile key from apm.yml (delegates to project config when set)
  • profile use --project <path> - project directory for apm.yml discovery (default .)
  • profile use --force - apply even when the profile is already active and in sync
  • profile use --dry-run - preview global file writes
  • profile use --harness <slugs> - comma-separated harness slugs (default: global harness preference)
  • profile use --on-conflict <replace|skip|prompt|cancel>
  • profile use --account <name> - cloud account for auto-pull of missing published dependencies
  • profile use --base-url <url>
  • profile use --no-pull - fail when composition refs are missing locally
  • profile use --format json
  • profile pull - same flags as plugin pull (--as, --org, --catalog, --version, --account, --base-url)
  • profile publish --org <slug> / --catalog <slug> / --account <name> / --format json
  • profile preview --scope <home|project|both> - preview scope (default home)
  • profile preview --project <path> / --harness <slugs> / --format json
  • profile switch - same apply flags as profile use (--dry-run, --harness, --on-conflict, --no-pull, --account, --base-url, --format json)
  • profile stash - --dry-run, --harness, --on-conflict, --format json
  • profile stash pop / profile stash apply - same pull/apply flags as profile use
  • profile add-resource <name> --selector <type:name> --scope <home|project> - adopt one untracked on-disk resource
  • profile add-all-resources <name> --scope <home|project> - adopt every untracked material resource in the scope
  • profile commit-resource <name> --path <path> or --selector <type:name> - snapshot live disk into the profile library (skills as 1:1 files; MCP, settings, and hooks JSON as all resources in that file)
  • profile remove-resource <name> --selector <type:name> - detach a material resource from the profile stack
  • profile restore-file <name> --path <path> - overwrite the live managed file with the profile snapshot
  • profile file-diff <name> --path <path> - unified diff of live content vs after-apply snapshot

profile use auto-pulls missing published plugin composition refs by default. If the profile plugin defines default_environment_id, the home active environment pointer is updated on switch.

resource (r)

Manage individual imported resources such as instructions, skills, rules, or agents.

Commands

  • resource list
  • resource show <selector>: name, type:name, type:name@namespace, or ULID
  • resource sync [selector]: refresh marketplace_link definitions and sync plugin resources from install roots
  • resource delete [resource]
  • resource directories list|add|remove|rescan: manage directories scanned into the resource library

Important options

  • resource list --type <type>
  • resource list --search <query>

See Interactive list keyboard reference for TTY browse/search shortcuts.

  • resource list --show-id
  • resource show --format json
  • resource show --show-id
  • resource show --all-fields
  • resource sync --overwrite
  • resource sync --on-conflict <replace|skip|prompt|cancel> - default cancel. Aliases for one release: overwrite -> replace, ignore -> skip, fail -> cancel.
  • resource sync --force
  • resource sync --dry-run
  • resource directories list --format json
  • resource directories add <path> - track a directory and import resources (skip existing)
  • resource directories remove <path> - stop tracking a directory (library resources stay)
  • resource directories rescan - re-scan home defaults and every tracked directory
  • resource list shows material resources plus plugin resources; plugin composition refs are hidden by default
  • resource list --all - show every resource per type (default caps at 10 per type)
  • plugin edit selectors accept type:name@namespace for compose-safe resolution
  • Host plugin pins are plugin resources; use resource sync, plugin show, plugin doctor, plugin fork, and apply --strict-plugin-versions for pin workflows

environment (e)

Manage named environment bundles (env vars, model config, permissions, and secret references) and global or per-terminal active-environment pointers.

Environment values are the runtime how configuration that plugins satisfy through needs[] contracts and MCP env keys. They are distinct from toolkit configuration (harness_preferences, config.jsonc).

Commands

  • environment create <name>: blank (default), from project (--from-project), or from configured plugin requirements (--from-plugin); interactive wizard on TTY when no mode flags are set
  • environment edit [name]: interactively edit values, or use scripting flags for non-interactive updates
  • environment list
  • environment show <name>: values, secret refs, reverse references; --plugin analyzes requirement gaps for a configured plugin
  • environment delete [name]
  • environment use <name>: set the global active environment; --local applies only to this terminal session
  • environment status: show active environment and terminal env var drift

Important options

  • environment create --blank: create an empty environment (default when no mode flag is set)
  • environment create --from-project <path>: import scoped project values required by the plugin stack
  • environment create --from-plugin <selector>: seed from configured plugin needs[], MCP env keys, and model metadata (repeatable or comma-separated)
  • environment create --refresh: update an existing environment (--from-project only)
  • environment create --bind: bind the new environment as the configured plugin default (--from-plugin only)
  • environment create --plugins <selectors>: configured plugin scope for --from-project (default: project's last-applied plugins)
  • environment create --strict: exit non-zero when required keys are missing
  • environment create --include-permissions: include scanned permission resources (--from-project only)
  • environment create --description <text>
  • environment create --dry-run: preview without persisting
  • environment create --interactive / -y, --yes
  • environment create --format json
  • environment edit --var KEY=VALUE / --unset-var KEY: scripting mode env var updates
  • environment edit --model <name> / --model-provider <provider> / --unset-model
  • environment edit --permission action:pattern / --unset-permission <selector>
  • environment edit --secret KEY:provider:ref / --unset-secret KEY
  • environment edit --format json: read-only edit snapshot (non-TTY)
  • environment edit --interactive / -y, --yes
  • environment list --format json
  • environment show --plugin <selector>: compare environment values against a configured plugin's requirements
  • environment show --format json: includes requirement_gaps when --plugin is set
  • environment delete --force: delete even when referenced
  • environment delete --interactive / -y, --yes
  • environment use --local: session-scoped active environment without changing global pointer
  • environment status --plugins <selectors>: include configured plugin default environments in expected values
  • environment status --check: exit non-zero when terminal env vars drift from expected values
  • environment status --format json

harness (h)

Manage global harness preferences and git-backed project overrides.

Commands

  • harness list
  • harness set
  • harness status
  • harness sync
  • harness project set
  • harness project status

Important options

  • harness list --supported - only harnesses HarnessTap can serialize natively
  • harness list --format json
  • harness set --harnesses <slugs>
  • harness sync - union registered harnesses (home) with last-write conflicts, including Claude/Cursor host plugin trees and .agents materialization for OpenCode-like harnesses; --plugin-resources symlink|copy|clone; --project for a repo; --dry-run
  • harness project set --project <path>
  • harness project set --materialization-strategy <symlink-preferred|copy>
  • harness project status --format json

migrate (m)

Offline sharing for workspace archives, individual plugins, or single resources: without publishing to the cloud catalog.

Use migrate when:

  • setting up a new laptop from an existing HarnessTap install (full workspace)
  • sharing a curated plugin or resource with a teammate offline
  • backing up your local workspace before a reinstall

For multiplayer distribution, use plugin publish / plugin pull via HarnessTap Cloud.

Commands

  • migrate export [file]: export workspace, plugin, or resource as an Agent Plugins package (or workspace archive); interactive when [file] omitted on a TTY
  • migrate import [file]: import a package directory, .ap.json envelope, or .tar.gz workspace archive (auto-detects scope)
  • migrate resolve-order: pin last-applied resource winners as overrides where current resolution would pick a different plugin

Important options

  • migrate export --workspace: full workspace archive (.tar.gz)
  • migrate export --plugin <name>: Agent Plugins package directory (comma-separated for multi-plugin); accepts name (working head) or name@version (frozen snapshot). Refuses dirty working heads: cut first (plugin cut)
  • migrate export --resource <selector>: single-resource package (wraps the resource in a one-resource plugin)
  • migrate export --single-file: write a .ap.json envelope instead of a package directory
  • migrate export -o, --file <path>: output path (overrides positional)
  • migrate export --include-plugins / --embed-plugins: embed plugin trees (workspace and plugin scope)
  • migrate import --workspace / --plugin / --resource: force import scope
  • migrate export --format json / migrate import --format json: machine-readable summary (CLI output format, not transport)
  • migrate resolve-order --dry-run: report planned override writes without changing plugins
  • migrate resolve-order --format json

--environment is removed on both export and import: environments are machine-local secret references. Include them in a --workspace archive instead.

Workspace archives include Agent Plugins packages, named environments (secret refs only), harness preferences, config, and active-profile.json when present. They do not include tracked project records, project snapshots, or cloud accounts.

See Scenario 28 and Scenario 17.