CLIConcepts

Projects

Repositories where HarnessTap scans, applies, mirrors, and tracks harness configuration.

A project is a repository (or directory tree) where HarnessTap materializes harness configuration. Project workflows center on scan, apply, mirror, drift detection, and snapshot revert — all scoped to the working tree rather than machine-wide home paths.

Repo-scoped apply

layer apply is the canonical write path for project baselines:

ht layer apply my-setup --project . --harness claude-code,codex,cursor --dry-run
ht layer apply my-setup --project . --harness claude-code,codex,cursor
ht status .

Stack multiple layers in one command (see Scenario 25). layer apply resolves bare catalog names at apply time, so public baselines work without a prior layer pull:

ht layer apply engineering-foundation --project .

Plugin-version policy when the layer carries plugin pins:

ht layer apply my-setup --strict-plugin-versions   # exit 2 on pin violation
ht layer apply my-setup --ignore-plugin-versions   # skip validation
ht layer apply my-setup --sync-plugins             # refresh plugin resources first

Applying a layer writes a known baseline onto disk. It is distinct from mirror, which syncs alias harness outputs from the current on-disk main harness without re-specifying the layer.

Scan and track

Discover existing configuration before composing layers:

ht scan .
ht resource list
ht layer from-project inferred-stack --project .

When the target repository has a git origin, layer apply stores a snapshot of tracked generated files before writing. Snapshots power history, drift detection, and revert.

CommandGit requirement
historyGit-backed project with origin
status --checkGit-backed project
layer apply (with snapshot)Git origin on target project
revertSnapshot ID from history
harness project set / harness project statusGit-backed project

layer apply can write files outside git, but snapshot and history support only works when the target project has a git origin.

Mirror

mirror propagates configuration from the main harness to alias harnesses in the same repository — useful after manual edits to the primary harness files:

ht mirror .
ht mirror . --force-shift-reference codex
ht mirror . --dry-run

Mirror compares and shifts references between harness-specific file layouts. It does not re-resolve layer composition; use layer apply when you need a fresh baseline from the library.

See Scenario 27 for the cross-harness mirror walkthrough and Scenario 33 for plugin fallback behavior.

Drift and revert

After apply, teammates may edit generated files directly. HarnessTap tracks drift against the last apply or mirror snapshot:

ht status . --check
ht status . --check --format json   # exit 1 when drift exists
ht history .
ht revert <snapshot-id>

status --check compares the current working tree against the latest apply/mirror snapshot. Exit code 1 means actionable drift was found — useful in CI guardrails.

See Scenario 21.

Project harness preferences

Per-project harness settings (main and aliases for this repo) are separate from global harness set:

ht harness project status .
ht harness project set --main claude-code --aliases cursor

These require a git-backed project and influence which harnesses layer apply and mirror target by default.

Snapshots in practice

Typical lifecycle:

  1. ht layer apply team-baseline --project . — writes files, stores snapshot (when git origin exists)
  2. Developer edits .cursor/rules/foo.mdc by hand
  3. ht status . --check — reports divergence from snapshot
  4. Either re-apply the layer, mirror from main, or ht revert <id> to restore

Preview before writing:

ht layer apply team-baseline --project . --dry-run

See Scenario 7.

Profiles vs projects

ProfilesProjects
ScopeMachine home harness pathsRepository working tree
Primary commandprofile uselayer apply
Typical useWork/personal machine presetsTeam repo baselines
Drift / revertNot trackedstatus --check / revert

Use Profiles for machine-wide defaults and projects for repository-specific configuration.

Project profile config

Repositories can declare named profiles in .harnesstap/config.toml. This file maps profile keys to local layers, catalog selectors, or inline layer tables — plus optional project-scoped environments.

Example:

schema = "urn:harnesstap:project:v1"
version = 1
default_profile = "dev"
default_environment = "shared"

[[profiles]]
name = "dev"
source = "local"
selector = "team-stack"

[[profiles]]
name = "prod"
source = "catalog"
selector = "acme/platform/frontend@1.0.0"

[[profiles]]
name = "custom"
source = "inline"
layer = "embedded-layer"

[[environments]]
name = "shared"

[environments.values]
REGION = "us"

[[layers]]
name = "embedded-layer"
description = "Small inline layer bundled with the repo"

Inspect and validate the resolved config:

ht config show
ht config show --format json
ht config validate --project .
ht config validate --format json   # exit 1 when invalid

Create a starter config from local profile layers:

ht config init
ht config init --profile work --profile personal --default work
ht config init --force   # overwrite an existing file

config init maps each selected profile layer to a source = "local" entry and sets default_profile.

Switch to a configured profile with ht use:

ht use                        # interactive picker when multiple profiles exist
ht use --profile dev          # apply the dev profile directly
ht use --list                 # list profiles without applying

Project profiles reuse the same layer sources as machine-wide Profiles, but apply through ht use in the repository instead of profile use at home paths.