Share a team baseline
Your platform team keeps its skills, agents and rules in acme/agent-kit.
Every service should have the same set, at the same version, for Claude Code and Codex.
One person sets it up once. Everyone else clones, and it works.
When you finish, a teammate’s fresh clone passes palm check without a single palm command before it:
$ cd ~/teammate && ls -a .claude .agents.agents:...skills
.claude:...agentsrulesskills$ cd ~/teammate && palm check✓ manifest and lock agree✓ palm.yaml targets match the lock✓ every entry is rendered✓ every entry is on all its targets✓ generated files match the lock✓ no stray file in a folder palm owns- applied files outside the lock: skipped (global scope only)✓ in-repo sources match the lock✓ no generated path lies inside a source✓ every program palm installed is trusted✓ no foreign command in the hook files palm manages✓ no foreign stdio server in the MCP files palm manages✓ every hook script exists✓ no literal secret in generated files✓ every variable the servers need is set✓ generated files are committed✓ every source is declared✓ no link leaves the scope✓ no hidden Unicode in generated files✓ no harness loads an entity twice✓ no two agents or commands share a name in a harness folder✓ every skill an agent preloads is installed✓ instruction files are within harness limitsno problems$ cd ~/teammate && palm install3 unchanged.Before you start
Section titled “Before you start”- The team’s repository is reachable over git from every laptop and from CI.
- The project has
targets:inpalm.yaml, frompalm init --target claude,codex.
Set it up once
Section titled “Set it up once”-
Install the team’s entities by name.
Terminal window palm install acme/agent-kit ci-watch ci-watcher typescriptpalm declares
acme/agent-kitinpalm.yamlwith a range on its newest tag, so later releases within1.xarrive throughpalm update. -
Commit everything palm wrote, in one commit.
~/project $ palm install acme/agent-kit ci-watch ci-watcher typescripti ref ^1.0 saved to palm.yaml (latest tag v1.0.0); edit ref: to track main+ skill ci-watch .agents/skills/ci-watch/, .claude/skills/ci-watch/ 2 files from acme/agent-kit v1.0.0 (claude gets its own copy in .claude/skills)+ agent ci-watcher .claude/agents/ci-watcher.md, .codex/agents/ci-watcher.toml 2 files from acme/agent-kit v1.0.0.claude/agents/ci-watcher.md: dropped model (fast) (not supported by Claude Code).claude/agents/ci-watcher.md: readonly: true written as tools: Read, Grep, Glob, WebFetch, WebSearch.codex/agents/ci-watcher.toml: dropped model (fast) (not supported by Codex).codex/agents/ci-watcher.toml: readonly: true written as sandbox_mode = "read-only"+ instruction typescript .claude/rules/typescript.md, AGENTS.md 1 file +1 merged from acme/agent-kit v1.0.03 installed. Commit palm.yaml, palm.lock.yaml, .agents/, .claude/, .codex/ and AGENTS.md together.$ git add -A && git commit -qm "Add the team agent setup" && git show --stat --format=%s HEADAdd the team agent setup.agents/skills/ci-watch/SKILL.md | 8 +++++++.claude/agents/ci-watcher.md | 7 +++++++.claude/rules/typescript.md | 7 +++++++.claude/skills/ci-watch/SKILL.md | 8 +++++++.codex/agents/ci-watcher.toml | 6 ++++++.gitignore | 2 ++AGENTS.md | 5 +++++palm.lock.yaml | 45 ++++++++++++++++++++++++++++++++++++++++palm.yaml | 7 +++++++9 files changed, 95 insertions(+)The commit holds
palm.yaml, the lock and every generated file. Reviewers see the skill text, the agent and the rule block inAGENTS.md, exactly as the harnesses will read them.
What a teammate does
Section titled “What a teammate does”Nothing palm-specific. git clone delivers the files, and the harnesses read them.
palm is only needed to change the setup, and to prove it in CI.
A bare palm install on the clone counts every entry as unchanged and writes nothing.
If a hook is part of the baseline, the lock already holds the team’s consent, so the clone installs it silently. Consent explains the hash that makes this safe.
Take an update
Section titled “Take an update”The team tags v1.1.0 of acme/agent-kit.
One person moves the project to it and opens a pull request.
$ palm update --dry-runUpdate plan (project scope)acme/agent-kit ^1.0 v1.0.0 (0fc9803) → v1.1.0 (edcbf2e)~ updated skill ci-watch acme/agent-kit v1.0.0 (0fc9803) → v1.1.0 (edcbf2e)= 2 re-pinned (same content)dry run: nothing written.$ palm update --yesUpdate plan (project scope)acme/agent-kit ^1.0 v1.0.0 (0fc9803) → v1.1.0 (edcbf2e)~ updated skill ci-watch acme/agent-kit v1.0.0 (0fc9803) → v1.1.0 (edcbf2e)= 2 re-pinned (same content)~ skill ci-watch .agents/skills/ci-watch/, .claude/skills/ci-watch/ 2 files (claude gets its own copy in .claude/skills)1 updated, 2 unchanged. M .agents/skills/ci-watch/SKILL.md M .claude/skills/ci-watch/SKILL.md M palm.lock.yaml$ git status --short M .agents/skills/ci-watch/SKILL.md M .claude/skills/ci-watch/SKILL.md M palm.lock.yaml--dry-run prints the plan and writes nothing.
--yes applies it without a prompt, and palm prints the diff stat.
The pull request shows the new skill text and the moved commit in the lock, and review decides.
The plan lists every entry of a source whose commit moves, including those whose files stay the same, so review sees each re-pin. For a source pinned to an exact tag, the plan prints the latest tag, so a pin never hides a newer release.
A changed or new hook is never covered by --yes. It needs a fresh consent, shown with d as a diff against what the team trusted.
A hook or MCP server that a plugin starts to ship appears as i new program available, and nothing installs it until someone names it.
To leave the range, move it explicitly.
palm update acme/agent-kit --to ^2Remove something for everyone
Section titled “Remove something for everyone”$ palm remove ci-watcher- agent ci-watcher .claude/agents/ci-watcher.md, .codex/agents/ci-watcher.toml 2 files1 removed.$ git status --short D .claude/agents/ci-watcher.md D .codex/agents/ci-watcher.toml M palm.lock.yaml M palm.yamlThe removal is two deleted files and two edited ones.
Commit them, and every teammate’s next git pull removes the agent. No one has to run palm.
Personal additions
Section titled “Personal additions”A teammate who wants an extra skill only for themselves installs it with -g, into their home directory.
palm install mattpocock/skills tdd -gpalm cannot switch off a committed entry for one person, because git tracks the file.
Use the harness’s own switch instead, such as .claude/settings.local.json for Claude Code or a [[skills.config]] entry in ~/.codex/config.toml for Codex.
Removing the entry with palm remove removes it for the whole team.
palm 0.3 adds palm.local.yaml for personal targets, sources and entries in one checkout, ignored by git, and per-person disable with it.
--local prints that and changes nothing until then.
Protect the files that run programs
Section titled “Protect the files that run programs”The lock records that someone consented to a hook’s hash, not who did.
Make review of those files mandatory with a CODEOWNERS file, so a consent always passes through someone you chose.
palm.lock.yaml @acme/platform.palm/assets/** @acme/platform.claude/settings.json @acme/platform.codex/hooks.json @acme/platform.github/hooks/ @acme/platform.cursor/hooks.json @acme/platform.gemini/settings.json @acme/platformagent-kit/ @acme/platformList the hook files of your targets only, and every in-repo source, such as agent-kit/.
A change to a hook’s script, its command or its trust: hash then needs that team’s approval.
Next steps
Section titled “Next steps”- Run
palm checkon every pull request. See Check the setup in CI. - Publish the team’s own repository. See Publish your own source.
- Understand what the lock records. See palm.yaml and palm.lock.yaml.