Skip to content

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:

teammate: ~/teammate
$ cd ~/teammate && ls -a .claude .agents
.agents:
.
..
skills
.claude:
.
..
agents
rules
skills
$ 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 limits
no problems
$ cd ~/teammate && palm install
3 unchanged.
  • The team’s repository is reachable over git from every laptop and from CI.
  • The project has targets: in palm.yaml, from palm init --target claude,codex.
  1. Install the team’s entities by name.

    Terminal window
    palm install acme/agent-kit ci-watch ci-watcher typescript

    palm declares acme/agent-kit in palm.yaml with a range on its newest tag, so later releases within 1.x arrive through palm update.

  2. Commit everything palm wrote, in one commit.

    ~/project
    $ palm install acme/agent-kit ci-watch ci-watcher typescript
    i 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.0
    3 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 HEAD
    Add 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 in AGENTS.md, exactly as the harnesses will read them.

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.

The team tags v1.1.0 of acme/agent-kit. One person moves the project to it and opens a pull request.

~/project
$ palm update --dry-run
Update 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 --yes
Update 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.

Terminal window
palm update acme/agent-kit --to ^2
~/project
$ palm remove ci-watcher
- agent ci-watcher .claude/agents/ci-watcher.md, .codex/agents/ci-watcher.toml 2 files
1 removed.
$ git status --short
D .claude/agents/ci-watcher.md
D .codex/agents/ci-watcher.toml
M palm.lock.yaml
M palm.yaml

The 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.

A teammate who wants an extra skill only for themselves installs it with -g, into their home directory.

Terminal window
palm install mattpocock/skills tdd -g

palm 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.

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.

.github/CODEOWNERS
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/platform
agent-kit/ @acme/platform

List 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.