Skip to content

chore(skills): centralize AI assistant config via symlinks#9951

Open
grauJavier wants to merge 3 commits intoprowler-cloud:masterfrom
grauJavier:chore/improve-ai-skills-setup
Open

chore(skills): centralize AI assistant config via symlinks#9951
grauJavier wants to merge 3 commits intoprowler-cloud:masterfrom
grauJavier:chore/improve-ai-skills-setup

Conversation

@grauJavier
Copy link

Context

Currently, developers using different AI assistants (Claude, Gemini, etc.) end up with duplicated skill files and assistant configurations. This creates maintenance friction, as the root AGENTS.md and skills/ directory should be the single source of truth, but generated files can easily drift out of sync.

Description

Updated skills/setup.sh to use ALWAYS symbolic links instead of copying files.

  • Keeps .claude/skills, .gemini/skills, etc., as symlinks pointing to the root skills/ directory.
  • Configures provider-specific markdown files (e.g., CLAUDE.md) as symlinks pointing to AGENTS.md.
  • Automatically adds generated files to .gitignore to maintain a clean environment when different developers use different assistants.
  • Ensures that any change to the source of truth is immediately reflected across all configured assistants without re-running the setup script.
  • Keeps the workspace cleaner by avoiding duplicate files.

Steps to review

  1. Run ./skills/setup.sh locally.
  2. Select an assistant (e.g., Option 1 for Claude).
  3. Verify that the created directory .claude/skills is a symlink pointing to .../skills.
  4. Verify that .claude/CLAUDE.md is a symlink pointing to .../AGENTS.md.

@github-actions github-actions bot added the community Opened by the Community label Feb 3, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Feb 3, 2026

Conflict Markers Resolved

All conflict markers have been successfully resolved in this pull request.

@danibarranqueroo
Copy link
Member

Hello @grauJavier! Thanks for this, we'll review it as soon as possible! 🙌

Copy link
Contributor

@Alan-TheGentleman Alan-TheGentleman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for this pr !!

Love to see some love over the skills architecture, thanks a lot again.

I'll review it in a little bit!!

Copy link
Contributor

@Alan-TheGentleman Alan-TheGentleman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of centralizing with symlinks is great 👏

I tested the script locally and it works, the symlinks are created correctly. However, I found some issues that need to be fixed before merging:

🔴 Bugs

1. setup_copilot() - Symlink with absolute path

ln -sf "$REPO_ROOT/AGENTS.md" "$target"

This creates a symlink with an absolute path (/Users/javier/prowler/AGENTS.md). If another dev clones the repo in a different location, the symlink points to a path that doesn't exist.

Fix:

ln -sf "../AGENTS.md" "$target"

2. link_agents_md() - cd without protection

cd "$agents_dir" && ln -sf "$(basename "$agents_file")" "$target_name" && cd "$SCRIPT_DIR"

If ln -sf fails, the script never returns to $SCRIPT_DIR and subsequent iterations run from the wrong directory.

Fix: Use a subshell:

(cd "$agents_dir" && ln -sf "$(basename "$agents_file")" "$target_name")

3. Missing .codex/ in gitignore

setup_claude() and setup_gemini() add to gitignore, but setup_codex() doesn't:

setup_codex() {
    # ... 
    # Missing: add_to_gitignore ".codex/"
}

🟡 Minor

4. Tests don't validate symlinks

Tests use assert_file_exists which passes for both files and symlinks. They should be updated to use assert_symlink_exists to explicitly validate the new behavior. Also rename the section from "Copy tests" to "Link tests".

5. Header comments outdated

Line 4 says CLAUDE.md copies but now they're symlinks.


Once these are fixed, the PR is ready to merge!

@grauJavier
Copy link
Author

Thanks for the detailed review! I've addressed all the points:

🔴 Fixed

  • Absolute Paths: Changed setup_copilot to use a relative symlink (../AGENTS.md) so it works regardless of where the repo is cloned.
  • Unsafe cd: Wrapped the directory change loop in a subshell (...) to ensure the script doesn't get stuck in the wrong directory if a command fails.
  • Gitignore: Added .codex/ rules. Also refined all ignores to target the specific symlinks (e.g., .claude/skills) rather than the entire parent directory, so we don't accidentally ignore other files in those folders.

🟡 Improvements

  • Tests: Updated setup_test.sh to explicitly check for symlinks using assert_symlink_exists instead of just file existence.
  • Docs: Updated the header comments to correctly reflect that we are linking files, not copying them.
  • Organization: Renamed the test section to "Link tests" as requested.

Verified locally, all 19 tests passed! ✅

@jfagoagas jfagoagas added the status/waiting-for-revision Waiting for maintainer's revision label Mar 9, 2026
Copy link
Contributor

@Alan-TheGentleman Alan-TheGentleman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the late reply on this one, Javier.

All three bugs from the first review are properly fixed — the relative path for copilot, the subshell wrapper, and the codex gitignore. Tests updated correctly too. Solid work.

Three minor things I noticed, curious what you think:

  1. Header line 7 still says "copy"# - GitHub Copilot: .github/copilot-instructions.md copy but setup_copilot() now uses ln -sf. Should probably say "symlink" for consistency with lines 4-5.

  2. Unused variable in link_agents_md()local target_path="$agents_dir/$target_name" is declared but never referenced. Looks like leftover from the refactor.

  3. Summary message on line 305"AGENTS.md is the source of truth - edit it, then re-run this script." With symlinks, the whole point is you don't need to re-run. Something like "AGENTS.md is the source of truth - changes are reflected automatically via symlinks." would be more accurate.

None of these are blockers — let me know if you agree or if there's a reason I'm missing.

- Update copilot header comment from 'copy' to 'symlink'
- Remove unused target_path variable in link_agents_md()
- Update summary message to reflect symlinks auto-propagate changes
- Use assert_symlink_exists in idempotent test for CLAUDE.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

community Opened by the Community status/waiting-for-revision Waiting for maintainer's revision

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants