Write once,
guide everywhere.

Gather compiles your AI coding instructions into native formats for Cursor and Claude Code — from a single source of truth.

gather compile cursor — and your entire team's knowledge flows into every tool.

One command. All sources. Every tool. Shared catalog + project overrides. Drift detection built in.

Up and running in three steps

1

Install

One command. Resolves and installs the latest release via uv.

curl -fsSL https://gather-home.sandbox.arbor.engineering/install.sh | sh
Manual install (specific version, or main)

Prefer to inspect the script first, pin a specific tag, or install straight from main? Use uv directly:

# SSH (recommended)
uv tool install "gather-cli @ git+ssh://git@github.com/arbor-education/devx.gather.git@main#subdirectory=gather-cli"

# or HTTPS
uv tool install "gather-cli @ git+https://github.com/arbor-education/devx.gather.git@main#subdirectory=gather-cli"
What is uv?

uv is a fast Python package manager from Astral. It replaces pip, pipx, and virtualenv in a single tool. The install script above installs it automatically if missing; to install it yourself:

# macOS / Linux
curl -LsSf https://astral.sh/uv/install.sh | sh

# macOS via Homebrew
brew install uv

# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"

Gather requires Python ≥ 3.13. Check with python3 --version.

2

Initialize

Pick shared packs from the org catalog.

cd your-project
gather init
3

Compile

One command writes everything your tool needs.

gather compile cursor
# or: gather compile claude

That's it. One compile fetched your org's shared instructions, merged your project rules, and wrote everything into Cursor's native format.

gather init
Terminal recording showing gather init with an interactive catalog picker for selecting shared instruction packs

One compile. Everything merges.

arbor-education/knowledge

  • Shared instructions
  • Company skills
  • Team agents

your project's .gather/

  • Project rules
  • Local agents
  • Custom skills

gather compile
Cursor .cursor/rules/
.cursor/skills/<source>:<skill>/
.cursor/agents/
Claude Code .claude/rules/
.claude/skills/<source>:<skill>/
CLAUDE.md

One source of truth. One command per tool. Project content always wins. Shared skills are namespaced as <source>:<skill> on macOS/Linux (__ on Windows) so the same skill name from different sources does not collide.

gather compile cursor
Terminal recording showing gather compile cursor fetching shared instructions and writing Cursor output files

Install from a branch or another repo

Pull skills, agents, and instructions from any branch or GitHub repo. Edit gather.yaml directly, or use gather.local.yaml to experiment without changing committed config.

Feature branch in the catalog

- name: knowledge-branch
  repo: arbor-education/knowledge
  ref: art  # branch name
  folders: [my-stuff]

Different repo entirely

- name: personal-skills
  repo: wodor/knowledge
  ref: art
  folders: [stuff]

Root-level skills + name matching

- name: filtered-skills
  repo: wodor/knowledge
  ref: art
  match: behave.*  # regex filter
  folders:
    - skills: /  # root = skills dir

Tip: gather.local.yaml sources are appended to gather.yaml — use a unique name so they don't conflict. If the same name appears in both files, gather compile exits with an error.

Do I need to recompile?

Run gather status to check. If everything is Clean, you're up to date.

What changed What to do
Someone updated the org catalog gather compile cursor
You edited files in .gather/ gather compile cursor
You changed gather.yaml sources gather compile cursor
Teammate already compiled & pushed Nothing — outputs are in the repo
You tweaked a generated file gather status → then decide
gather status
Terminal recording showing gather status detecting drifted files, then recompiling to return to clean state

Common questions

Why is CLAUDE.md gitignored?

CLAUDE.md, .cursor/rules/, and the other tool output files are generated artifacts — Gather writes them fresh on every compile. They belong in .gitignore for the same reason compiled code does: the source of truth lives in .gather/instructions/.

Already have a CLAUDE.md with project knowledge? Move its content into .gather/instructions/your-file.md (any name except CLAUDE.md), then run gather compile claude. Gather regenerates CLAUDE.md from your source files. Your .gather/instructions/ files are committed — that is where your repo knowledge belongs.

How do I move my existing skills, rules, or agents into Gather?

Copy your files into the appropriate subdirectory under .gather/ in your repo:

# existing rule or instruction (e.g. from CLAUDE.md or .cursor/rules/)
.gather/instructions/your-rule.md

# existing agent definition
.gather/agents/your-agent.md

# existing skill (keep the SKILL.md + supporting files)
.gather/skills/your-skill/SKILL.md

Then run gather compile cursor (or claude). Gather merges your project's .gather/ content with the org catalog and writes fresh output files. Your committed .gather/ files are the source — the output files in .cursor/, CLAUDE.md, etc. are regenerated from them.

You can use gather import to copy existing .cursor/rules/ or CLAUDE.local.md files into .gather/instructions/_imported/ automatically.

Will Gather overwrite my project-specific content?

No — as long as your content lives in .gather/. Gather reads .gather/instructions/, .gather/agents/, .gather/skills/, and .gather/hooks/ as source, not output. It never modifies anything inside .gather/.

The output files (CLAUDE.md, .cursor/rules/, etc.) are rewritten on each compile — but those are derived from your source. If you have a file like .gather/instructions/developer-guide.md, it will always be included in the output.

If a path conflicts with the org catalog (same relative path under instructions/), your project's copy wins. You always have the final say.

Why do compiled skill folders use colons?

When multiple sources in gather.yaml contribute a skill with the same name, Gather writes each copy under a flat namespace directory so Cursor and Claude never load the wrong file:

.cursor/skills/arbor:pr/SKILL.md
.claude/skills/knowledge:pr/SKILL.md

On Windows, : is invalid in paths, so Gather uses __ instead (e.g. arbor__pr). Both targets use the same layout.

After upgrading gather-cli, run gather compile <target> . once. Compile removes tracked outputs from older nested or legacy three-segment layouts and updates state.json.

Can I share team skills across repos?

Yes. Add a folder to the arbor-education/knowledge repo under your team's namespace (e.g. teams/frontend/) and populate it with instructions/, agents/, or skills/. Any repo that subscribes to that folder via gather init will pull it in automatically on compile.

For content that is only relevant to a single repo (not worth sharing), keep it in that repo's .gather/ directory instead.

All the commands

gather init interactive setup with catalog picker
Opens a full-screen catalog picker showing available instruction packs from arbor-education/knowledge. Select packs with Space, save with Ctrl+S. Creates .gather/gather.yaml, instructions/, agents/, and skills/ directories. Also writes a .gitignore block that excludes generated output files.
gather init
gather init --batch non-interactive setup for CI/scripts
Skips the interactive picker. Specify folders directly with --folders, or omit it to create the .gather/ structure with no catalog subscriptions.
gather init --batch --folders company,devops
gather init --batch # just create .gather/ with no packs
gather init --user personal catalog overlay in ~/.config/gather.yaml
Same catalog picker as gather init, but writes the sources entry to ~/.config/gather.yaml (personal overlay) instead of the project's .gather/gather.yaml. Does not create project .gather/ directories or touch .gitignore. The entry is saved under a distinct name (e.g. arbor-personal) so it compiles alongside a project's catalog source — the same source name in more than one config layer is a compile error. Combine with --batch --folders for scripting. ~/.config/gather.yaml is global, not per-project; a later --batch --user overwrites the personal folder selection.
gather init --user
gather init --batch --user --folders teams/qe/skills/manual-test-cases
gather compile cursor|claude fetch, merge, compile, write
The main command. Fetches all configured sources, merges with your project's .gather/ content, sends to the compiler, and writes native output files. Each compile is a full refresh — no incremental state to worry about.
gather compile cursor
gather compile claude --keep-tmp # keep .gather-tmp for debugging
gather compile cursor --verbose # show full file tree
Custom sources install from a branch or another repo
Pull skills, agents, and instructions from any branch or any GitHub repo you have access to. Edit gather.yaml directly, or use gather.local.yaml to experiment without changing committed config.
# Feature branch in the catalog repo (unique name per source)
- name: knowledge-branch
  repo: arbor-education/knowledge
  ref: art  # branch name
  folders: [my-stuff]

# Different repo entirely
- name: personal-skills
  repo: wodor/knowledge
  ref: art
  folders: [stuff]

# Root-level skills + regex name matching
- name: filtered-skills
  repo: wodor/knowledge
  ref: art
  match: behave.*  # filter by pattern
  folders:
    - skills: /  # root = skills dir
gather status clean / drifted / missing check
Compares generated files on disk against recorded state. Shows per-target breakdown with Clean, Drifted, Missing, and Untracked counts. Exit code 0 if everything matches.
gather status
gather promote save local edits back to .gather/
If you tweaked a generated file (e.g. edited a rule in .cursor/rules/), promote syncs that change back into .gather/ so it survives the next compile.
gather promote
gather promote --target cursor # only from Cursor files
gather import bring existing rules into .gather/
Already have .cursor/rules/ or CLAUDE.local.md? Import copies them into .gather/instructions/_imported/ so they become part of your canonical source.
gather import
gather import --dry-run # preview without writing
gather doctor validate config, auth, compiler
Runs a full diagnostic: checks your .gather/ directory, validates gather.yaml, tests GitHub auth, verifies the compiler service is reachable.
gather doctor
gather retract remove all generated files
Removes all generated artifacts that were recorded in local state. Useful for a clean slate before switching targets or cleaning up a repo.
gather retract

Locally-modified outputs are preserved by default. If you have edited a compiled file directly, Gather detects that its content no longer matches the recorded checksum and skips deleting it — so your edits are not silently lost. The skipped paths are listed in the output.

To delete locally-modified outputs as well, pass -f/--delete-modified:

gather retract -f

The same protection applies during gather compile: locally-modified outputs cause compile to exit with an error listing the conflicts. Pass -s/--skip-modified to keep local versions, -o/--overwrite-modified to replace them, or -f/--delete-modified to discard local changes before compile:

gather compile cursor -f