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.
$ palm get targetsroot: ~/projecttarget 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 cursortarget 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, .cursorThis 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.
The six targets
Section titled “The six targets”| 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.
Declared once in palm.yaml
Section titled “Declared once in palm.yaml”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.
Narrowed per entry
Section titled “Narrowed per entry”An entry can limit itself to some of the project’s targets with targets:.
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.
One copy per harness
Section titled “One copy per harness”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 withclaudeandcursorpalm writes one copy, in.claude/skills. - With
claudeandcodex, 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.
What a harness does not support
Section titled “What a harness does not support”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.