A local-first control center for AI extensions.
Use, review, and discover Skills, Agents, MCP servers, slash commands, hooks, and CLI tools across agent harnesses.
AI extensions are scattered across harness-specific folders, MCP config files, slash command locations, and marketplace sources. Harness Asset Manager provides a single local control surface for managing, reviewing, and discovering extensions across all your AI coding tools and agent frameworks.
- Edit Once, Active Everywhere: For file-based extensions (Skills and Agents), Harness Asset Manager uses managed symlinks to a single canonical store. Edit an asset in any enabled harness or in the shared store, and the changes are immediately active across every harness sharing the link.
- Drift Detection & One-Click Sync: For native config-based and rendered extensions (MCP Servers, Slash Commands, Hooks, and Security Permissions), Harness Asset Manager actively monitors local harness state. When you edit a native config in one harness, Harness Asset Manager detects the drift, flags it for review, and lets you adopt or sync the changes across all your other harnesses in one step.
- Safe Conflict Isolation: If multiple harnesses edit the same asset independently, Harness Asset Manager preserves both versions, prevents silent data loss, and lets you resolve conflicts safely.
| Asset Family | What Harness Asset Manager does |
|---|---|
| Skills | Adopt local Skill folders into one shared inventory, then enable or disable them per harness using managed symlinks. |
| Agents | Store subagents as Markdown files with YAML frontmatter, symlinked (or rendered for Codex) across harnesses with automated drift repair and safe conflict resolution. |
| MCP Servers | Manage normalized MCP server configurations and translate them into native harness shapes (JSON, TOML, YAML). |
| Slash Commands | Maintain a single reusable prompt library and sync rendered command files into supported harness formats. |
| Hooks | Configure normalized event and tool category hook records, synced into native harness settings with drift detection and review for unmanaged entries. |
| Permissions | Enforce strict denylists across supported harnesses (Claude Code, Codex, Antigravity, and Cursor) to restrict shell commands, file paths, web domains, and MCP tools in a unified view. |
| Snapshots & Audit | Capture native config snapshots across all 7 supported harnesses with automatic drift detection, SHA-256 deduplication, and secret redaction, backed by an append-only JSON Lines audit journal. |
| Marketplace | Discover and preview Skills, MCP servers, and external CLI tools from marketplace hubs. |
| Headless / CLI | Drive all features headlessly via CLI commands with --json output—ideal for VPS environments, containers, or Linux sandboxes with no browser required. |
- In use: Harness Asset Manager controls the item and enables or disables it across harnesses.
- Needs review: Harness Asset Manager found local state differences, unmanaged items, or configuration drift that requires your decision.
- Discover: Browse marketplaces and preview external tools.
Harness Asset Manager supports 7 AI agent harnesses across 6 asset families:
|
Claude Code Docs |
Codex CLI Docs |
Antigravity (agy) Docs |
Cursor Docs |
OpenCode Docs |
Hermes Agent Docs |
Factory Droid Docs |
Harnesses appear in this canonical order everywhere in the app—Settings and every resource matrix. The order is declared in SUPPORTED_HARNESS_DEFINITIONS (harness_asset_manager/harness/catalog.py). Disabling a harness in Settings drops its column across all matrices.
| Harness | Skills | Agents | MCP Servers | Slash Commands | Hooks | Permissions |
|---|---|---|---|---|---|---|
| Claude Code | Yes | Yes | Yes | Yes | Yes | Yes (Denylist) |
| Codex CLI | Yes | Yes | Yes | Yes | Yes | Yes (Denylist) |
| Antigravity (agy) | Yes | Yes | Yes | Yes | Partial | Yes (Denylist) |
| Cursor | Yes | Yes | Yes | Yes | Yes | Yes (Denylist) |
| OpenCode | Yes | Yes | Yes | Yes | Partial | No |
| Hermes Agent | Yes | Best effort¹ | Yes | Yes² (Provisional) | Not Yet | No |
| Factory Droid | Yes | Yes | Yes | Yes | Not Yet | No |
$HERMES_HOME/agents/ for separate Hermes-side support or other tooling; Hermes will not consume them automatically.² Hermes slash-command support is provisional. Its command directory (
~/.hermes/commands, frontmatter Markdown) follows common conventions but is not yet verified against a shipping Hermes build.Factory Droid hooks and permissions are not currently mapped because its hook scopes and command policy do not match HAM's global hook and denylist contracts.
Factory Droid support is currently best-effort and targets the personal/global
configuration under ~/.factory. See Factory Droid support
for the supported asset paths, project-scope boundaries, and documentation basis.
brew tap execsumo/tap
brew install harness-asset-manager
harnessam startbrew install harnessam also works as an alias for the same formula.
If harnessam: command not found appears after installing, Homebrew's bin directory isn't on your PATH yet — run eval "$(brew shellenv)" and add that line to your shell profile (~/.zprofile or ~/.bash_profile).
git clone https://github.com/execsumo/harness-asset-manager.git
cd harness-asset-manager
scripts/install-dev.shLaunch the background daemon and open the browser interface:
harnessam startOr run the server directly in the foreground (for containers, systemd, or remote setups):
harnessam serve --no-open-browser --host 127.0.0.1 --port 8000Every asset family managed by the Web UI is also accessible via the CLI:
# Matrix Overview
harnessam skills list # skills × harness matrix
harnessam agents list # agents × harness matrix
harnessam mcp list # mcp servers × harness matrix
harnessam hooks list # hooks × harness matrix
harnessam permissions list # permissions × harness matrix
harnessam commands list # slash commands list
# Management & Binding
harnessam agents enable release-bot --harness claude
harnessam skills set-harnesses lint-rule --target enabled
harnessam commands sync deploy --target claude --target codex
harnessam hooks set-harnesses lint-gate --target enabled
# Permissions
harnessam permissions create --id no-force-push \
--decision deny --scope shell --pattern 'git push --force'
# Marketplace Installation
harnessam mcp install exa
# Snapshots & Settings
harnessam snapshots capture
harnessam settings showAll CLI commands accept --json for script integration:
harnessam skills list --json | jq -r '.rows[] | select(.displayStatus=="Unmanaged") | .skillRef'Start with the whole extension portfolio: what is in use, what needs review, what can be discovered, and where extensions are active.
Use Skills as shared local packages instead of maintaining separate copies per harness.
Typical flow:
- Review a Skill found in a harness or install one from the marketplace.
- Adopt it into the Harness Asset Manager inventory.
- Enable it only where it should be available.
- Update, remove, or delete it from one place.
Use MCP servers as one normalized config that can be written into each harness shape.
Typical flow:
- Review an MCP server found in a harness or install one from the marketplace.
- Adopt it into the Harness Asset Manager inventory.
- Enable it where the server should be available.
- Resolve config differences, disable harness bindings, or uninstall it from one place.
Use slash commands as one shared prompt library instead of rewriting the same command in each harness-specific format.
Typical flow:
- Create a slash command with a name, description, and prompt.
- Use
$ARGUMENTSwhere runtime input should be inserted. - Sync it to supported harnesses.
- Review existing harness command files and adopt them into the shared library when needed.
Subagents you keep in one place instead of copy-pasting between harnesses.
Typical flow:
- Write an agent — a name, a description, and a system prompt — or adopt one Harness Asset Manager found in a harness.
- Turn it on for the harnesses that should have it.
- Review agents discovered in harness directories and adopt the ones worth keeping.
If a harness later edits an agent out from under Harness Asset Manager — some editors replace the link with their own copy — that edit is folded back in automatically, but only when it is provably the only edit. Conflicting edits are always left for you to resolve. See Agents below.
Marketplace is the discovery surface:
- Skills Marketplace: browse and install Skills.
- MCP Marketplace: browse and install MCP servers.
- CLI Marketplace: preview external CLI tools from CLIs.dev. This is display-only; Harness Asset Manager does not install or manage CLIs.
Harness Asset Manager keeps a flat store under its data directory: skills/ holds one directory per skill, agents/ holds one <slug>.md per agent, and each family's manifests sit alongside. Every binding into a harness points back here, so a resource is edited once and every harness that has it enabled follows.
Two earlier layouts are migrated one-time on first start — the pre-package shared/ directory and the later packages/local/ structure both fold into skills/ and agents/. The migration is locked, idempotent, and skipped once the flat layout exists.
Before adoption, each harness points at its own local skill folder. After adoption, Harness Asset Manager keeps one canonical package in its shared local store and exposes it to selected harnesses with local links. Disabling a harness removes that harness binding without deleting the package.
Harness Asset Manager treats managed Skills as portable by default: once a Skill is adopted into the shared store, it can be enabled for any supported harness. originHarness is retained only as provenance.
Hermes Agent Skills use the categorized Hermes layout under ~/.hermes/skills/<category>/<skill>/SKILL.md. Shared Skills enabled for Hermes are linked under the harnessam category by default. The legacy harness-asset-manager category remains readable so existing links continue to work. Harness Asset Manager excludes bundled Skills tracked by .bundled_manifest and official/builtin optional Skills recorded in Hermes hub provenance. Other valid Hermes Skill directories—including local or self-learned Skills with no .hub/lock.json entry—are surfaced as unmanaged and can be adopted; external hub provenance is retained when available. Hermes-owned bundled and official optional folders remain untouched until explicitly adopted or managed.
MCP servers are stored as normalized Harness Asset Manager records, then translated into the config shape each harness expects:
- Codex uses TOML under
mcp_servers. - Claude Code and Cursor use
mcpServersJSON entries. - OpenCode uses typed local/remote MCP entries.
- Antigravity (agy) uses
mcpServersJSON entries withserverUrlfor HTTP transports andcommand/args/envfor stdio. - Hermes Agent uses YAML under
mcp_serversin~/.hermes/config.yaml(or$HERMES_HOME/config.yaml). - Factory Droid uses JSON under
mcpServersin~/.factory/mcp.json.
When Harness Asset Manager finds different configs for the same MCP server, it asks you to resolve the source of truth first.
Slash commands are stored as TOML records under Harness Asset Manager app storage, then rendered into each supported harness format:
- Claude Code writes Markdown command files under
~/.claude/commandsand invokes them with/. - Codex writes prompt files under
~/.codex/promptsand invokes them with/prompts:. - Cursor writes plain text command files under
~/.cursor/commandsand invokes them with/. - OpenCode writes Markdown command files under
~/.config/opencode/commandsand invokes them with/. - Antigravity (agy) writes Markdown command files under
~/.gemini/antigravity-cli/commandsand invokes them with/. - Factory Droid writes Markdown command files under
~/.factory/commandsand invokes them with/.
Disabling a harness in Settings removes its column here immediately, without a restart. Command files already written to that harness and their sync records are left alone — re-enabling it restores the column and its sync state unchanged.
Harness Asset Manager tracks target ownership with sync state and content hashes. With slash-command auto-adoption enabled, it adopts only equivalent unmanaged command files and never overwrites their contents. Otherwise it reports unmanaged, changed, or missing files for review. Review actions let you adopt unmanaged commands, restore managed content, adopt a changed harness command as the new source, or remove a broken binding while leaving the harness file untouched.
Hooks are stored as normalized Harness Asset Manager records using canonical events (pre_tool_use, post_tool_use, user_prompt_submit, session_start, stop, pre_compact) and canonical tool categories (shell, file_read, file_write, mcp, web, any). Each harness codec translates a canonical record into that harness's native event names and config shape, and merges it into the harness's hook config:
- Claude Code writes hook entries into
~/.claude/settings.jsonunder thehookskey. - Codex writes inline
[hooks]tables into~/.codex/config.toml(same event schema as Claude). - Cursor writes
~/.cursor/hooks.json, expressing each tool category as its dedicated event (beforeShellExecution,afterFileEdit,beforeMCPExecution, and so on). - OpenCode writes
experimental.hookentries inopencode.json— limited tofile_edited(post-edit on write) andsession_completed(stop), so coverage is partial. - Antigravity (agy) writes a name-keyed
~/.gemini/config/hooks.json(discovering entries across user-level~/.gemini/*/hooks.jsonand project-level.agents/hooks.json), matching against tool names (run_command,view_file, …); it covers tool, stop, and (viaPreInvocation) prompt-submit hooks, so coverage is partial. - Factory Droid hooks are not currently managed. Droid has user, project, enterprise, and legacy hook scopes with lifecycle and matcher semantics that do not map safely to HAM's canonical hook model.
Because harnesses differ, not every canonical event maps to every harness. Harness Asset Manager exposes a representability matrix showing where each hook can sync and where it cannot, including caveats — for example, an Antigravity user_prompt_submit hook maps to PreInvocation, which fires before every model invocation rather than only on prompt submit.
Harness Asset Manager owns only the specific hook entries it writes. It merges into each harness's config without disturbing hooks or other keys it does not manage, and it tracks ownership with content hashes. When a managed hook is edited outside Harness Asset Manager it is reported as drifted, and hooks found in a harness that Harness Asset Manager does not manage are reported as unmanaged for review.
Agents are Markdown files with YAML frontmatter and the system prompt as the body. They live in Harness Asset Manager's store; enabling one for a harness symlinks it into that harness's agents directory, so editing the agent once updates it everywhere it is enabled.
Harness Asset Manager reads name, description, and tools, and leaves every other frontmatter key alone. Harness agents routinely carry settings we have no business interpreting — Claude's model, permissionMode, maxTurns, hooks; Cursor's readonly and is_background; Codex's sandbox_mode — so an edit merges into the original frontmatter rather than re-rendering it, and unrecognized keys survive untouched. The detail view lists them verbatim under Configuration, which means a new harness field shows up without any code change here. The only keys dropped on write are capabilities: and harnesses: from the retired compile model, which nothing reads.
The agents matrix shows the same harnesses as every other family — whichever you have enabled in Settings:
| Harness | Location | How it is installed |
|---|---|---|
| Claude Code | ~/.claude/agents/ |
symlink |
| Cursor | ~/.cursor/agents/ |
symlink |
| Antigravity | ~/.gemini/antigravity-cli/agents/ |
symlink |
| OpenCode | $XDG_CONFIG_HOME/opencode/agents/ |
symlink |
| Codex | ~/.codex/agents/ |
rendered TOML |
| Hermes | $HERMES_HOME/agents/ (normally ~/.hermes/agents/) |
symlink; best effort¹ |
| Factory Droid | ~/.factory/droids/ |
symlink |
Most harnesses read the same Markdown format the store holds, so enabling one symlinks the store file into place — edit the agent once and every harness it is enabled for follows. Codex is the exception: it reads TOML with different keys (name, description, developer_instructions), so Harness Asset Manager renders a real file marked # harness-asset-manager:generated. Local edits to a rendered file are reported but never adopted — re-enabling overwrites them. Hermes is best effort: HAM can manage the files in its conventional agents directory, but Hermes does not consume them automatically without separate Hermes-side support.
Harness Asset Manager only ever removes files it owns — a symlink into its store, or a file carrying its generated marker. Anything else in a harness's agents directory is reported as unmanaged for review, never overwritten. Adopting one moves it into the store (converting Codex TOML to Markdown) and installs it back. If the name is already taken in the store, Harness Asset Manager refuses to guess and asks which version to keep.
Some editors save a file by writing a temporary file and renaming it over the target. Renaming over a symlink replaces the symlink with a regular file, so a harness that edits an agent through its own UI can silently turn a binding into an ordinary copy — and from then on the two versions drift apart. (Skills are immune to this: they bind as directory symlinks, and renaming a directory over one fails at the kernel.)
Harness Asset Manager records every binding it makes in bindings.json: which agent went to which harness, and what the store held at that moment. That record is what makes the difference between "a harness broke our link" and "an unrelated file happens to share this name" decidable — without it, the two are the same observation. The record is a cache, never a source of truth; if it disagrees with the filesystem, the filesystem wins. Deleting it costs you the automation, never your content.
On the next inventory load, each broken binding is classified and handled:
| What is found | What happens |
|---|---|
| The copy is identical to the store | The link is restored. There is no content decision to make. |
| The copy was edited, and the store has not changed since it was linked | That copy holds the only edit in existence, so it is adopted into the store and every binding for that agent is restored. |
| The copy was edited and the store changed too | Nothing. Both sides hold work; choosing either discards the other. Reported for you to resolve. |
| Several harnesses were edited differently | Nothing is adopted and nothing is deleted. Each version is preserved under agents/conflicts/, with one issue naming every side. |
| There is no record of a binding here | Nothing. This is an ordinary name collision, and you are asked, as before. |
Newest-file-wins is deliberately not a rule here — it silently discards the other harness's work, which is the exact failure this exists to prevent. Codex is excluded from automatic adoption entirely, because converting its TOML back to Markdown drops keys Harness Asset Manager does not model.
Every automatic action is appended to the Activity audit log: repair you cannot see is nearly as bad as breakage you cannot see. Agent-specific repairs are also shown as Recent automatic repairs on the agents review page. Each family has its own setting, and turning one off takes effect on the next load, not the next restart.
Denylist rules strictly restrict shell commands, file paths, web domains, and MCP tools across supported harnesses in a single unified view. --scope values include shell, file_read, file_write, web, mcp, any, and --pattern matches according to scope (shell → git push, file_* → ~/.zshrc, web → api.example.com, mcp → server/tool). Only --decision deny binds to harnesses today — Harness Asset Manager is denylist-only. Enabling the first rule for a harness also selects that harness's no-prompt execution mode, so unlisted actions proceed and only recorded deny rules are blocked; disabling the last rule restores the native default. Codex's native config currently supports HAM's file and web deny rules, but not shell-command or MCP deny rules.
Cursor has a mapper implemented against ~/.cursor/cli-config.json (Shell(), Read(), Write(), WebFetch(), Mcp() deny tokens — multi-token shell patterns and bare-server MCP patterns are correctly reported unsupported, since Cursor's own tokens can't express either). Enabling a Cursor rule writes approvalMode = "unrestricted" and disabling the final rule cleans it up. Only Cursor's separate CLI (cursor-agent) is targetable at all — its IDE Agent reads an entirely different permissions.json that is allowlist-only, with no deny/enforcement surface, so it stays permanently out of scope for this model. The capability matrix keeps Cursor as Planned until this is verified against an installed cursor-agent rather than documentation alone.
Capture and back up Native Config Snapshots across all 7 supported harnesses (~/.harnessam/configs/) with automatic drift detection, SHA-256 deduplication, secret redaction, Web UI controls, and harnessam snapshot CLI support. Droid snapshots cover the selected global MCP file; project-level .factory/ files remain outside HAM's managed boundary.
Trace every Web UI, API, and CLI mutation in an append-only JSON Lines journal, including the operation, outcome, and filesystem paths changed—without recording prompts, config payloads, or secrets.
Harness Asset Manager is a local configuration-management tool. It runs on your machine and reads or writes local harness extension state.
Actions that can change local state include:
- adopting a local skill folder
- enabling or disabling a skill for a harness
- updating a source-backed skill
- removing or deleting a skill
- installing an MCP server into a selected harness config
- adopting an existing MCP config
- enabling, disabling, resolving, or uninstalling an MCP server
- creating, updating, syncing, importing, or deleting a slash command
- creating, enabling, disabling, resolving, or deleting a hook binding
- changing harness support settings
- repairing a drifted agent binding, which can move an edit out of a harness file and into the store
Automatic adoption is opt-in per asset family, except for the existing safe Agent repair default. It is limited to equivalent observations or cases where a harness copy is provably the only edit, and every action is recorded in the Activity audit log.
| Family | Default | Automatic behavior when enabled |
|---|---|---|
| Agents | On | Repair provable drift; conflicting edits remain for review. |
| Skills | Off | Adopt new, equivalent unmanaged local directories and replace them with store links. |
| Slash commands | Off | Register equivalent unmanaged files without overwriting their contents. |
| MCP, Hooks, Permissions | Off | Promote equivalent unmanaged observations without choosing between conflicting configurations. |
These checks run while reading the relevant inventory or detail view, so a setting change takes effect on the next read; there is no background watcher. Codex rendered-agent adoption remains excluded because its TOML-to-Markdown conversion is not lossless. When the UI is closed, run harnessam refresh for one read and reconciliation pass across all asset families; use harnessam refresh --json for automation.
App-owned files live under ~/.harnessam on macOS and Linux. Existing XDG harnessam and harness-asset-manager stores are migrated automatically and retained as compatibility aliases.
Every asset family the Web UI manages is also available as a CLI command. Nothing needs to be running first: the CLI builds the same backend the server does and talks to the same stores, so it works on a VPS, in a container, or in a Linux sandbox with no browser and no daemon.
Every command takes --json and --state-dir. --harness names a harness id (claude, codex, agy, cursor, opencode, hermes, droid), and set-harnesses --target enabled|disabled applies one state to every interactive cell in that row. Run harnessam <group> <verb> --help for the full flag list.
skills — Skills inventory and the skills marketplace.
| Command | What it does |
|---|---|
skills list |
The skills × harness matrix, plus a managed/unmanaged count |
skills show <ref> |
Detail: status, per-harness cells, on-disk locations |
skills enable|disable <ref> --harness <h> |
Bind or unbind one harness |
skills set-harnesses <ref> --target <state> |
Apply one state everywhere |
skills manage <ref> / skills manage-all |
Take unmanaged skills into the store |
skills unmanage <ref> |
Stop managing, leaving the files in place |
skills update <ref> |
Re-fetch a managed skill from its source |
skills delete <ref> --yes |
Delete a managed skill and its bindings |
skills search <query> / skills popular |
Browse the marketplace; prints install tokens |
skills install <install-token> |
Install a marketplace skill |
agents — Subagents stored as markdown and symlinked into each harness.
| Command | What it does |
|---|---|
agents list |
The agents × harness matrix, including unmanaged harness copies |
agents show <ref> |
Detail: prompt, tools, per-harness path and install method |
agents create --name --description --prompt|--prompt-file [--tool …] |
Create an agent in the store |
agents update <ref> [--name] [--description] [--prompt] [--tool …] |
Change one or more fields |
agents enable|disable <ref> --harness <h> |
Bind or unbind one harness |
agents set-harnesses <ref> [--harness <h> …] |
Bind to exactly this set; omit all to unbind everywhere |
agents adopt <ref> [--on-conflict keep_store|replace_store] |
Take a harness-owned agent into the store |
agents adopt-all |
Adopt every unmanaged agent |
agents delete <ref> --yes |
Delete an agent and its bindings |
mcp — MCP servers and the MCP marketplace.
| Command | What it does |
|---|---|
mcp list |
The servers × harness matrix |
mcp show <name> |
Detail: transport, command/url, per-harness state |
mcp install <qualified-name> |
Install from the marketplace |
mcp uninstall <name> --yes |
Remove a managed server and its bindings |
mcp enable|disable <name> --harness <h> [--config <json>] |
Bind or unbind one harness |
mcp set-harnesses <name> --target <state> [--config <json>] |
Apply one state everywhere |
mcp check <name> |
Probe availability; exits 1 when unavailable |
mcp unmanaged |
Servers found in harness configs that we do not own |
mcp adopt <name> [--observed-harness <h>] [--harness <h> …] |
Take an unmanaged server into the store |
mcp search <query> / mcp popular |
Browse the marketplace |
--config takes a JSON object, or @file / @- to read one from a file or stdin.
hooks — Normalized hook records synced into harness settings.
| Command | What it does |
|---|---|
hooks list |
The hooks × harness matrix |
hooks show <id> |
Detail: event, command, match, per-harness state and drift |
hooks create --id --event --command [--match] [--timeout] [--description] |
Create a managed hook |
hooks enable|disable <id> --harness <h> |
Bind or unbind one harness |
hooks set-harnesses <id> --target <state> |
Apply one state everywhere |
hooks promote <id> [--observed-harness <h>] |
Take a harness-owned hook into the store |
hooks delete <id> --yes |
Delete a hook and its bindings |
--event is one of pre_tool_use, post_tool_use, user_prompt_submit, session_start, stop, pre_compact. --match is a tool category — any, shell, file_read, file_write, mcp, web — not a harness tool name; each harness maps the category to its own matcher.
permissions — Denylist rules across supported harnesses.
| Command | What it does |
|---|---|
permissions list |
The rules × harness matrix |
permissions show <id> |
Detail: decision, scope, pattern, per-harness state |
permissions create --id --decision --scope [--pattern] [--description] |
Create a managed rule |
permissions enable|disable <id> --harness <h> |
Bind or unbind one harness |
permissions set-harnesses <id> --target <state> |
Apply one state everywhere |
permissions promote <id> [--observed-harness <h>] |
Take a harness-owned rule into the store |
permissions delete <id> --yes |
Delete a rule and its bindings |
commands — Slash commands and their per-target renders.
| Command | What it does |
|---|---|
commands list |
Commands with their synced targets, plus anything needing review |
commands targets |
The available targets and whether each is enabled and available |
commands show <name> |
Detail: per-target sync status, path, and the prompt body |
commands create --name --description --prompt|--prompt-file [--target …] |
Create and sync |
commands update <name> --description --prompt|--prompt-file [--target …] |
Update and re-sync |
commands sync <name> [--target …] |
Re-render into the selected targets |
commands delete <name> --yes |
Delete the command and its renders |
settings, snapshots, health
| Command | What it does |
|---|---|
settings show |
Storage paths, per-harness support and install state, auto-adopt |
settings harness <h> --enable|--disable |
Turn support for a harness on or off |
settings auto-adopt <agents|skills|slash_commands|mcp|hooks|permissions> --enable|--disable |
Control opt-in automatic adoption and repair |
refresh [--sync-all] |
Run inventory pass; --sync-all enforces auto-adoption & drift reconciliation across all asset families |
snapshots list [--harness <h>] |
Captured native config snapshots |
snapshots capture / snapshot |
Capture a snapshot of every native config |
health |
Health summary — app, harness count, home dir; useful as a readiness probe |
--jsonon any command prints the exact payload returned by the corresponding API route — stdout stays clean forjq, while errors go to stderr.- Exit codes:
0success,1a refused or partly-applied mutation,2bad usage. A fan-out likeset-harnessesexits1when any harness rejects the change; checksucceeded/failedin JSON when partial application is acceptable. - Destructive commands (
delete,uninstall) prompt when stdin is a terminal and refuse otherwise — pass--yesin scripts. --state-dirisolates a run, including HAM's store, settings, runtime files, and catalog-resolved harness paths, ensuring CI or throwaway sandboxes do not touch the primary store or native harness configuration. It overridesHOMEand the XDG base directories for that invocation.
harnessam skills list --json | jq -r '.rows[] | select(.displayStatus=="Unmanaged") | .skillRef'
harnessam agents set-harnesses release-bot --harness claude --harness codex --json | jq .failedRunning the CLI while the app is serving is completely safe — stores serialize writes with flock, and the server's read models refresh within a second.
serve runs in the foreground (systemd, Docker, tmux); start daemonizes and records a pid that status and stop read back.
harnessam serve --no-open-browser --host 127.0.0.1 --port 8000A missing frontend/dist is fine — the API serves normally and only the HTML shell is a placeholder. Binding a non-loopback address needs --allow-remote; see Local-first safety first, because the API has no authentication.
On macOS and Linux, app-owned files live under ~/.harnessam. Explicit XDG overrides remain supported for isolated/test runs. Existing harnessam and harness-asset-manager directories are migrated automatically on first use.
Useful macOS paths:
- skills store:
~/.harnessam/skills - agents store:
~/.harnessam/agents - agent binding ledger:
~/.harnessam/bindings.json - agent repair audit log:
~/.harnessam/agents-audit.json - mutation audit journal:
~/.harnessam/audit.log(append-only JSON Lines) - preserved conflicting agent copies:
~/.harnessam/agents/conflicts - MCP manifest:
~/.harnessam/mcp/manifest.json - hooks manifest:
~/.harnessam/hooks/manifest.json - slash command library:
~/.harnessam/slash-commands/commands - slash command sync state:
~/.harnessam/slash-commands/sync-state.json - marketplace cache:
~/.harnessam/marketplace - app settings:
~/.harnessam/settings.json
Useful Linux paths:
- skills store:
~/.harnessam/skills - agents store:
~/.harnessam/agents - agent binding ledger:
~/.harnessam/bindings.json - agent repair audit log:
~/.harnessam/agents-audit.json - mutation audit journal:
~/.harnessam/audit.log - MCP manifest:
~/.harnessam/mcp/manifest.json - hooks manifest:
~/.harnessam/hooks/manifest.json - slash command library:
~/.harnessam/slash-commands/commands - slash command sync state:
~/.harnessam/slash-commands/sync-state.json - marketplace cache:
~/.harnessam/marketplace - app settings:
~/.harnessam/settings.json
If you manage skills in a custom environment, you can override individual skill roots with environment variables:
| Harness | Env var | Default Harness Asset Manager skill root |
|---|---|---|
| Codex | HARNESS_ASSET_MANAGER_CODEX_ROOT |
~/.agents/skills |
| Claude | HARNESS_ASSET_MANAGER_CLAUDE_ROOT |
~/.claude/skills |
| Cursor | HARNESS_ASSET_MANAGER_CURSOR_ROOT |
~/.cursor/skills |
| OpenCode | HARNESS_ASSET_MANAGER_OPENCODE_ROOT |
~/.config/opencode/skills |
| Hermes Agent | HARNESS_ASSET_MANAGER_HERMES_ROOT |
${HERMES_HOME:-~/.hermes}/skills |
| Factory Droid | HARNESS_ASSET_MANAGER_FACTORY_ROOT |
~/.factory/skills |
| Antigravity (agy) | HARNESS_ASSET_MANAGER_AGY_ROOT |
~/.gemini/antigravity-cli/skills |
Note: Legacy SKILL_MANAGER_* env var spellings are still read as fallbacks but are deprecated.
- Python 3.11+
- Node.js 18+
- npm
harness-asset-manager supports Python 3.11+. CI validates backend compatibility on Python 3.11 through 3.14, while packaging and release builds stay pinned to Python 3.11 for determinism.
scripts/install-dev.shscripts/start-dev.shStop the managed local instance:
scripts/stop-dev.shThe split dev flow is available when you want Vite hot reload:
npm run dev
npm run dev:backendDefault local URLs:
- Frontend:
http://127.0.0.1:5173 - Backend:
http://127.0.0.1:8000 - Health:
http://127.0.0.1:8000/api/health
Validation suite:
scripts/install-dev.sh
.venv/bin/ruff check harness_asset_manager tests scripts
.venv/bin/pyright
npm run lint:frontend
npm run typecheck
bash scripts/test_backend.sh
npm test
npm run build- If Marketplace requests fail with
Marketplace is temporarily unavailable, verify your network connection and try again. - If an MCP harness is shown as unavailable, Harness Asset Manager has detected that the local client is missing or does not support the required config surface.
- Hook support
- Slash command support
- Agent personas
- Package-based storage (portable resource bundles)
- Plugin support
Harness Asset Manager collapses many harnesses → one store. The next major piece adds many machines → one store: adopt a Skill on your desktop and have it be there, wired into the right harnesses, on your laptop and in your containers.
The unit of sync is the Harness Asset Manager store, not the harness directories — those hold symlinks, per-harness translations, and config files you also own, none of which survive being copied between machines. Canonical records travel; each machine recomputes its own bindings on arrival, so a machine without Cursor simply does not bind Cursor.
Planned shape:
- a private git remote you own — no accounts, no hosted service, nothing leaves your control
- MCP credential values are never transported; the receiving machine reports which credentials it still needs
- conflicts are preserved and reported, never auto-resolved by timestamp
- one-way
pullfor ephemeral and headless machines (containers, VPS, CI), which should inherit a portfolio and never push back
Design and sequencing: plan-cross-device-sync.md.
- See CONTRIBUTING.md for contribution guidelines.
- See SECURITY.md to report vulnerabilities privately.




