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 firstApplying 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.
| Command | Git requirement |
|---|---|
history | Git-backed project with origin |
status --check | Git-backed project |
layer apply (with snapshot) | Git origin on target project |
revert | Snapshot ID from history |
harness project set / harness project status | Git-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-runMirror 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 cursorThese require a git-backed project and influence which harnesses layer apply and mirror target by default.
Snapshots in practice
Typical lifecycle:
ht layer apply team-baseline --project .— writes files, stores snapshot (when gitoriginexists)- Developer edits
.cursor/rules/foo.mdcby hand ht status . --check— reports divergence from snapshot- Either re-apply the layer, mirror from main, or
ht revert <id>to restore
Preview before writing:
ht layer apply team-baseline --project . --dry-runSee Scenario 7.
Profiles vs projects
| Profiles | Projects | |
|---|---|---|
| Scope | Machine home harness paths | Repository working tree |
| Primary command | profile use | layer apply |
| Typical use | Work/personal machine presets | Team repo baselines |
| Drift / revert | Not tracked | status --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 invalidCreate 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 fileconfig 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 applyingProject 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.
Related
- Layers — what you apply
- Resources — what scan imports
- Profiles — machine-wide apply
- Portability limits — cross-harness mirror caveats
- Command reference —
scan,mirror,status,history,revert, andlayer apply - Scenario 7 — preview and apply
- Scenario 21 — detect drift
- Scenario 27 — mirror