Skip to content

Targets

A harness is the program that runs a coding agent, such as Claude Code or Codex. A target is palm’s identifier for a harness, such as claude or codex. Flags and palm.yaml use targets. Prose about the tools uses harnesses.

~/project
$ palm get targets
root: ~/project
target harness active config dir
──────── ────────────── ────── ──────────
claude Claude Code yes .claude/
codex Codex no .codex/
copilot GitHub Copilot no .github/
cursor Cursor yes .cursor/
gemini Gemini CLI no .gemini/
opencode OpenCode no .opencode/
$ palm describe target cursor
target cursor (Cursor)
active yes
root ~/project
config dir .cursor/
skill .claude/skills/<name>/
agent .cursor/agents/<name>.md
instruction .cursor/rules/<name>.mdc
hook merged into .cursor/hooks.json
mcp merged into .cursor/mcp.json (mcpServers)
writes to .agents/skills, .claude/skills, .cursor

This project has no targets: yet, so palm detected Claude Code and Cursor from their folders. palm describe target cursor prints where each kind goes for Cursor in this project.

Target Harness Detected in a project by Status
claude Claude Code .claude/ or CLAUDE.md tested
codex Codex .codex/ tested
copilot GitHub Copilot .github/copilot-instructions.md, .github/agents/ or .vscode/mcp.json tested
cursor Cursor .cursor/ tested
gemini Gemini CLI .gemini/ or GEMINI.md unverified
opencode OpenCode .opencode/, opencode.json or opencode.jsonc unverified

An AGENTS.md alone marks no target, because Codex, Cursor, Copilot and OpenCode all read it. For the global scope, palm detects a harness by its home directory, such as ~/.claude or ~/.config/opencode.

The Gemini CLI and OpenCode placements follow each harness’s documentation and source, checked on 2026-09-28. Neither has run against a live CLI in palm’s tests yet. palm 1.0 adds an end-to-end job for all six, and a target that fails it is dropped.

targets: in palm.yaml is the project’s set. When it is missing, the first install that places something writes the detected set and prints one line.

targets: claude (detected from .claude/; change targets: in palm.yaml)

palm init --target claude,codex writes the list before you install anything, and palm init -g --target claude does the same for the global scope. Commit it, and every clone installs for the same harnesses, whatever each machine has.

palm init without --target prints each detected target with its evidence, such as cursor (.cursor/). On a terminal it lets you edit the set before it writes. That, and a global install that detects nothing, are the only places palm asks about targets. Otherwise, with nothing declared and nothing detected, palm stops with E_TARGET and names palm init --target.

To add a harness later, edit targets: and run palm install. The bare install writes the new harness’s files for every entry. To drop one, remove it from targets:, and the next palm install deletes that harness’s files and merged entries.

An entry can limit itself to some of the project’s targets with targets:.

palm.yaml
targets: [claude, codex, cursor]
sources:
acme-kit:
url: https://gitlab.acme.com/platform/agent-kit.git
instructions:
- { name: db-conventions, targets: [claude, codex] }

palm install <source> <name> --targets claude,codex writes the same thing from the command line. An entry can only narrow. A target that is not in the project’s set is a parse error. --targets needs names to narrow: a bare palm install --targets codex is a usage error that points at targets: in palm.yaml.

Several harnesses read the same folders, and palm writes each file once.

  • Codex, Copilot, Gemini CLI and OpenCode read skills from .agents/skills. palm writes that folder once, however many of them are active.
  • Claude Code reads only .claude/skills. Cursor reads both folders and removes duplicates by name, so with claude and cursor palm writes one copy, in .claude/skills.
  • With claude and codex, a skill has two copies, and the lock notes why.

palm check uses the same facts, so it stays quiet about these copies. It warns only where a harness would still load one entity twice, for example an instruction from both AGENTS.md and .cursor/rules.

Some harnesses have no place for a kind at one scope.

Kind Harness Scope What palm does
hook OpenCode both skips it: OpenCode hooks are JavaScript plugins
hook with a matcher that has arguments, such as Bash(git commit*) GitHub Copilot both skips that hook for Copilot: its matchers cannot express arguments
instruction Cursor global skips it: Cursor keeps user rules in its settings

palm prints ⊘ skipped with the reason, records the note in the lock, and writes nothing the harness would ignore. palm describe <name> shows the note later.