Skip to content

feat: trimkit-symlink command for worktree setup #31

Description

@josephfung

Idea

Ship a trimkit-symlink CLI command that replaces the inline shell loop currently used to symlink gitignored files from a main checkout into a worktree. Instead of Claude generating shell constructs with variable assignments, semicolons, and for loops, the command would be:

trimkit-symlink /path/to/main /path/to/worktree .env .env.local data/

Goal

Eliminate the entire class of problems around the current symlink pattern:

  • Permission bypass risk: The current inline loop uses semicolons (or newlines) which can chain arbitrary commands after an auto-approved prefix. A dedicated command means the permission rule is just Bash(trimkit-symlink:*) — flat, unambiguous, no shell constructs.
  • Ordering gotcha: Today MAIN= must come first in the command so it matches Bash(MAIN=:*). A named command removes this fragile dependency.
  • Circular symlink risk: The CLAUDE.md has a CRITICAL warning about cd not persisting and relative paths creating circular symlinks. The command can enforce this internally.
  • Documentation burden: The current CLAUDE.md devotes multiple paragraphs and caveats to explaining the symlink pattern. This shrinks to one line.

Built-in safety checks

The command should:

  • Refuse to create a circular symlink (source and destination resolve to the same path)
  • Validate both directories exist before starting
  • Refuse to overwrite non-symlink files (protect against clobbering real files in the worktree)
  • Warn (not fail silently) when a requested item doesn't exist in the source directory

Acceptance criteria

  • trimkit-symlink <main-dir> <worktree-dir> <item>... creates symlinks for each item
  • Exits non-zero with a clear message if source or destination directory doesn't exist
  • Exits non-zero if a symlink would be circular (source == destination after resolution)
  • Skips (with warning to stderr) items that don't exist in the source
  • Refuses to overwrite a non-symlink file in the destination (exits non-zero with message)
  • Overwrites an existing symlink in the destination (re-pointing is safe)
  • Has tests covering all of the above
  • install.sh places it in ~/.trimkit/bin/
  • CLAUDE.md template updated to use the new command instead of the inline loop
  • Permission rule Bash(trimkit-symlink:*) added to settings template

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions