Skip to content

Refactor install to use centralized symlink-based approach#3

Closed
ibrahimkteish wants to merge 9 commits intopointfreeco:mainfrom
ibrahimkteish:feature/symlink-based-install
Closed

Refactor install to use centralized symlink-based approach#3
ibrahimkteish wants to merge 9 commits intopointfreeco:mainfrom
ibrahimkteish:feature/symlink-based-install

Conversation

@ibrahimkteish
Copy link
Copy Markdown
Contributor

@ibrahimkteish ibrahimkteish commented Jan 25, 2026

Summary

  • Introduces centralized skills storage (~/.pfw/skills/ or .pfw/skills/) with symlinks to each AI tool's expected location
  • Adds --local flag for project-specific storage that can be committed to git
  • Adds --workspace flag for project-level symlinks
  • Supports multiple AI tools: Codex, Claude, Cursor, Copilot, Kiro, Gemini, Antigravity
  • Interactive tool selection when no flags provided
  • Proper error handling with exit codes when symlinks fail

Why symlinks?

Instead of duplicating skills for each AI tool, this approach:

  • Single source of truth - update once, propagates everywhere
  • Supports both global (user-level) and workspace (project-level) configurations
  • --local automatically enables --workspace to avoid conflicts between projects

Test plan

  • Unit tests pass (28 tests)
  • Manual testing with --local, --workspace, --all flags
  • Verified symlinks resolve correctly
  • pfw status shows correct symlink status for both global and workspace

- Remove destructive file deletion - all installs now merge files
- Add support for --path . or --path current to install into current directory
- Add path validation for ALL custom paths to ensure they're in .codex/skills or .claude/skills
- Add helpful error messages with usage examples when validation fails
- Add user confirmation prompt when installing to custom paths
- Fix extraction to place skills directly in target path, not in nested skills/skills folder
- Update help text to document current directory option

This change ensures users never lose existing work when installing skills, and prevents installations to arbitrary directories outside the expected skills folders.
- Add test target to Package.swift
- Refactor Install.swift to extract testable helper functions:
  - isCurrentDirectoryPath: Detects if path is current directory
  - validateInstallPath: Validates path contains expected tool pattern
  - resolveInstallURL: Resolves final install URL based on inputs
- Create comprehensive test suite with 21 tests using @test syntax:
  - Path validation tests (valid/invalid paths, tool matching)
  - Current directory detection tests
  - Install URL resolution tests
  - Tool default path tests
  - Edge cases (whitespace, case sensitivity, trailing slashes)
- All tests passing with Swift Testing framework (macOS 15+)
- Remove 'current' keyword support to avoid conflicts with actual directory names
- Make path validation flexible to support different naming conventions (.github, .copilot, .claude)
- Update validation to only require '/skills' in path instead of tool-specific pattern
- Update tests to reflect new validation logic
- Add centralized skills storage (~/.pfw/skills or .pfw/skills)
- Create symlinks from each AI tool's expected location to central storage
- Support global vs local storage (--local flag)
- Support global vs workspace symlinks (--workspace flag)
- Add multi-tool support: cursor, claude, codex, kiro, gemini, antigravity
- Add interactive tool selection prompt
- Update Status command to show symlink status
- Add comprehensive tests for new functionality
- Track symlink failures and exit with error code if any fail
- Show proper completion message based on success/failure
- Implement workspace symlink status in Status command
- Refactor Status to extract duplicated symlink checking logic
- Simplify .gitignore comments (detailed docs are in README)
- Implement directory creation for tool skills before symlink creation
- Retrieve and create symlinks for all skill folders from the central skills directory
- Improve error handling and output messages for symlink creation failures
- Ensure existing symlinks are removed before creating new ones
@mbrandonw
Copy link
Copy Markdown
Member

Hey @ibrahimkteish, thanks for exploring all of this. This all sounds interesting, but it also is a bit much all at once. Can you instead open a PR that is focused on just a single topic?

Also, once #5 is merged we'd like all PRs to have some test coverage too, when possible.

@ibrahimkteish
Copy link
Copy Markdown
Contributor Author

Thanks for the feedback @mbrandonw ! I understand - this PR does cover a lot of ground at once.

I can break this into smaller, focused PRs. Here's how I'm thinking of splitting it:

  1. Core symlink-based centralized storage (~/.pfw/skills/ with symlinks to tool locations)
  2. --local flag for project-specific storage
  3. --workspace flag for project-level symlinks
  4. Additional AI tool support (Copilot, Kiro, Gemini, Antigravity)
  5. Interactive tool selection when no flags provided

Should I close this PR and start fresh with smaller ones after #5 is merged?

@mbrandonw
Copy link
Copy Markdown
Member

Hi @ibrahimkteish, yep most of that sounds good to me. Here is some specific feedback:

  • Let's do these in the order of 1, 4, 5 first.

  • For 1, something has come up during our alpha period that may complicate this, and want to get your opinion on it. Stephen and I have mostly been using codex for testing this, and in codex it was fine to put skills in ~/.codex/skills/the-point-free-way/skills. That extra nesting of "the-point-free-way" was not a problem for Codex. But apparently Claude (and maybe others?) require that all skill directories be placed directly in ~/.codex/claude.

    So, I like your symlink idea, but how do you envision it work for this scenario? I'm about to open a PR against my tests branch that changes things to copy each skill directory directly to ~/.{tool}/skills and prefixes each directory name with "pfw-" so that it doesn't conflict. Do you think for symlinking it would just be a matter of creating many symlinks, one for each skill directory?

  • Let's hold off on 2 and 3 for now. Currently these skill docs are meant for the particular user that downloaded them, and not meant to be shared.

Should I close this PR and start fresh with smaller ones after #5 is merged?

Yeah that would be great. Will let you know once #5 is merged. I built support for symlinks into the FileSystem interface so it should be possible to get test coverage on all of this.

Thanks again for looking into this!

@ibrahimkteish
Copy link
Copy Markdown
Contributor Author

ibrahimkteish commented Jan 26, 2026

@mbrandonw

According to my tests, yes Claude Code reads skills from ~/.claude/skills/{skill-name}/SKILL.md, or at the project level from .claude/skills/{skill-name}}/SKILL.md.

also their docs mention it:

Screenshot 2026-01-26 at 20 01 58

So, I like your symlink idea, but how do you envision it work for this scenario? I'm about to open a PR against my tests branch that changes things to copy each skill directory directly to ~/.{tool}/skills and prefixes each directory name with "pfw-" so that it doesn't conflict. Do you think for symlinking it would just be a matter of creating many symlinks, one for each skill directory?

Yes, 100%. For each PFW skill, we’ll end up with a symbolic link like ~/.{tool}/skills/pfw-composable-architecture, ~/.{tool}/skills/pfw-swift-dependencies, and so on.

NB: You might already know this, but it’s not always ~/.{tool}. For Antigravity, for example, the path is ~/.gemini/antigravity/global_skills

@mbrandonw
Copy link
Copy Markdown
Member

Yes, 100%. For each PFW skill, we’ll end up with a symbolic link like ~/.{tool}/skills/pfw-composable-architecture, ~/.{tool}/skills/pfw-swift-dependencies, and so on.

Great, that all sounds good to me then. Will let you know once we merging everything.

NB: You might already know this, but it’s not always ~/.{tool}. For Antigravity, for example, the path is ~/.gemini/antigravity/global_skills

Yep that's fine! Was just using a shorthand, but whatever is necessary for each tool will be used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants