technicalpickles/homesick
Your home directory is your castle. Don't leave your dotfiles behind.
Healthy across the board
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 3w ago
- ✓13 active contributors
- ✓Distributed ownership (top contributor 48% of recent commits)
Show 3 more →Show less
- ✓MIT licensed
- ✓CI configured
- ✓Tests present
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/technicalpickles/homesick)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/technicalpickles/homesick on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: technicalpickles/homesick
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/technicalpickles/homesick shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 3w ago
- 13 active contributors
- Distributed ownership (top contributor 48% of recent commits)
- MIT licensed
- CI configured
- Tests present
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live technicalpickles/homesick
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/technicalpickles/homesick.
What it runs against: a local clone of technicalpickles/homesick — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in technicalpickles/homesick | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 52 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of technicalpickles/homesick. If you don't
# have one yet, run these first:
#
# git clone https://github.com/technicalpickles/homesick.git
# cd homesick
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of technicalpickles/homesick and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "technicalpickles/homesick(\\.git)?\\b" \\
&& ok "origin remote is technicalpickles/homesick" \\
|| miss "origin remote is not technicalpickles/homesick (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "lib/homesick.rb" \\
&& ok "lib/homesick.rb" \\
|| miss "missing critical file: lib/homesick.rb"
test -f "lib/homesick/cli.rb" \\
&& ok "lib/homesick/cli.rb" \\
|| miss "missing critical file: lib/homesick/cli.rb"
test -f "bin/homesick" \\
&& ok "bin/homesick" \\
|| miss "missing critical file: bin/homesick"
test -f "lib/homesick/actions/git_actions.rb" \\
&& ok "lib/homesick/actions/git_actions.rb" \\
|| miss "missing critical file: lib/homesick/actions/git_actions.rb"
test -f "lib/homesick/actions/file_actions.rb" \\
&& ok "lib/homesick/actions/file_actions.rb" \\
|| miss "missing critical file: lib/homesick/actions/file_actions.rb"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 52 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~22d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/technicalpickles/homesick"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Homesick is a Ruby gem that manages dotfiles by cloning git repositories (called 'castles') into ~/.homesick and symlinking their contents into your home directory. It solves the problem of version-controlling and deploying dotfiles across machines by treating dotfiles as a git repo with a standardized structure (home/ directory containing dot-prefixed files). Single-file CLI gem: bin/homesick is the entry point wrapping lib/homesick/cli.rb (Thor-based command dispatcher). Core logic splits into lib/homesick/actions/file_actions.rb (symlink/unlink), lib/homesick/actions/git_actions.rb (clone/pull/push), lib/homesick/rc.rb (castle .homesickrc execution), and lib/homesick/utils.rb (helpers). Tests in spec/ mirror the CLI and rc behavior.
👥Who it's for
Systems administrators, developers, and power users who maintain consistent dotfiles across multiple machines and want to version-control them in git without cluttering their home directory with a .git folder.
🌱Maturity & risk
Actively maintained and production-ready. The repo has CI/CD via GitHub Actions (ci.yml, mutant-nightly.yml, release.yml), a full test suite (spec/ directory with RSpec), and uses Ruby best practices (.rubocop.yml, .mutant.yml for mutation testing). The project has been stable long enough to establish a clear API and conventions around 'castles'.
Low risk. Single maintainer (technicalpickles) but gem is stable with minimal external dependencies shown. Primary risk is Git-dependent workflows—if git operations fail or repositories become unavailable, castle operations break. No major breaking changes evident in the stable API.
Active areas of work
Unable to determine from file list alone—no recent commit dates visible. CI workflows are configured and active (.github/workflows/). The presence of .mutant.yml suggests ongoing mutation testing investment. Dependabot is enabled (.github/dependabot.yml) indicating dependency maintenance.
🚀Get running
Clone and install: git clone https://github.com/technicalpickles/homesick && cd homesick && bundle install. Run tests: bundle exec rspec. Build and install locally: bundle exec rake install.
Daily commands:
For development: bundle exec homesick --help (or test with bundle exec rspec). The gem is designed to be invoked as a command-line tool after installation, not as a daemon or server.
🗺️Map of the codebase
lib/homesick.rb— Main module entry point that loads all homesick components and establishes the library's public API.lib/homesick/cli.rb— Command-line interface definition using Thor that routes all user commands to appropriate actions.bin/homesick— Executable entry point that invokes the CLI and must be understood to debug command-line invocation issues.lib/homesick/actions/git_actions.rb— Core git operations for cloning and pulling dotfile repositories; critical for the clone/pull workflow.lib/homesick/actions/file_actions.rb— Symlink and file-system manipulation logic that bridges git-cloned dotfiles to the home directory.lib/homesick/rc.rb— Handles loading and executing custom homesick configuration from user's .homesickrc file.lib/homesick/utils.rb— Shared utility functions for file handling, path resolution, and system operations across the codebase.
🧩Components & responsibilities
- CLI (Thor) (Thor, Ruby) — Parse user commands and route to appropriate action handlers; provide user-friendly error messages
- Failure mode: Invalid arguments cause Thor to print usage; network errors in git operations propagate up as exceptions
- GitActions (Git (shell), Ruby Process) — Execute git clone and pull operations to fetch/update castle repositories; manage repository paths
- Failure mode: Network failure or invalid git URI causes clone to fail; pull on missing repo raises exception
- FileActions (Ruby File/Dir, symlink syscall) — Scan castle home/ directory, create symlinks in user's home directory, track and remove stale symlinks
- Failure mode: Existing files block symlink creation; insufficient permissions cause operation to fail partway through
- RC (Configuration) (Ruby eval, File I/O) — Load and execute ~/.homesickrc to allow user customization and hooks
- Failure mode: Syntax errors in .homesickrc halt initialization; eval context is homesick module scope
🔀Data flow
User input (CLI args)→Thor CLI parser— Command name and arguments passed from shellThor CLI→GitActions or FileActions— Routed based on command (clone → GitActions, link → FileActions)GitActions→Filesystem + Git— Git clones/pulls castle into ~/.homesick/repos; returns success/errorFileActions→Filesystem— Reads castle home/ structure; creates symlinks from castle to user's home directory (~)~/.homesickrc→RC loader— User custom configuration executed at gem load time in Homesick module context
🛠️How to make changes
Add a new CLI command
- Define a new public method in the Homesick::CLI class following Thor conventions (
lib/homesick/cli.rb) - Implement the command logic in lib/homesick/actions/* or use existing action classes (
lib/homesick/actions/file_actions.rb) - Add corresponding RSpec tests in spec/homesick_cli_spec.rb (
spec/homesick_cli_spec.rb)
Add a new git operation
- Add a new method to Homesick::Actions::GitActions for the git operation (
lib/homesick/actions/git_actions.rb) - Call the new method from the appropriate CLI command in lib/homesick/cli.rb (
lib/homesick/cli.rb) - Add specs for the new git action (
spec/homesick_cli_spec.rb)
Add a custom initialization hook
- Define a method in the user's ~/.homesickrc file that uses Homesick's public API (
lib/homesick/rc.rb) - The rc file is loaded by Homesick::RC.load and executed in the context of Homesick module (
lib/homesick/rc.rb)
🔧Why these technologies
- Ruby + Thor — Lightweight CLI framework for command-line parsing and task management; minimal dependencies for portable dotfile tool
- Git (shell exec) — Leverages native git for secure cloning and version control; avoids reimplementing VCS logic
- RSpec — Standard Ruby testing framework; enables comprehensive test coverage for file manipulation and git operations
⚖️Trade-offs already made
-
Shell execution for git operations instead of a git library
- Why: Simplicity and reliance on system git; reduces dependency bloat
- Consequence: Requires git to be installed; less fine-grained error handling; platform-dependent behavior
-
Symlinks for dotfile placement instead of copying
- Why: Single source of truth; enables easy updates by pulling from castle; reduces disk space
- Consequence: Symlinks may not work on all filesystems or Windows; breaks if symlink target moves
-
Convention-based castle structure (home/ directory with dotfiles)
- Why: Zero-configuration for users; castles are predictable and organized
- Consequence: Less flexible for non-standard dotfile layouts; users must follow the convention
🚫Non-goals (don't propose these)
- Does not manage dotfiles for Windows/PowerShell (Unix-centric symlink model)
- Does not handle authentication beyond what git provides
- Does not provide conflict resolution UI—only warns and requires manual intervention
- Does not support non-git repositories as castles
📊Code metrics
- Avg cyclomatic complexity: ~2.5 — Codebase is relatively simple; most functions are thin wrappers around shell commands or basic file I/O. No complex state machines, algorithms, or nested logic.
- Largest file:
lib/homesick/cli.rb(180 lines) - Estimated quality issues: ~3 — RuboCop config present; minor issues around exception handling and shell command safety; test coverage is good but integration tests could be more comprehensive
⚠️Anti-patterns to avoid
- Shell command execution without proper escaping (Medium) —
lib/homesick/actions/git_actions.rb: Git operations may pass user-supplied repository URIs directly to shell commands without full validation, risking injection if URIs are malicious - Broad exception handling (Low) —
lib/homesick/cli.rb: CLI methods may rescue generic Exception or StandardError, obscuring specific failure modes and making debugging harder - Manual file tracking via symlinks (Medium) —
lib/homesick/actions/file_actions.rb: Symlink removal and cleanup is manual and fragile; no formal manifest of installed dotfiles makes recovery from partial failures difficult
🔥Performance hotspots
lib/homesick/actions/git_actions.rb(I/O bound (git clone/pull latency)) — Large castle repositories with many files will cause clone/pull to block until git finishes; no parallel or incremental fetchlib/homesick/actions/file_actions.rb(Filesystem I/O (symlink syscalls)) — Symlink creation is synchronous and must iterate all files in home/ directory; no batching or async operations
🪤Traps & gotchas
Castle structure is strict: must have a home/ directory with dot-prefixed files to function. The .homesickrc eval approach is powerful but dangerous—it executes arbitrary Ruby code and symlink creation can silently fail if target files already exist. Git command failures (network, auth, missing remotes) propagate as exceptions. No built-in backup before symlinking, so existing files can be overwritten.
🏗️Architecture
🔗Related repos
anishathalye/dotbot— Alternative dotfiles manager using YAML configuration instead of git castles; Pythonic approach vs Homesick's Ruby + git-native philosophythoughtbot/rcm— Another dotfiles manager (C-based) with tagging and host-specific configs; similar goal but different architecturerobsalasco/dotfiles_template— Popular example castle repository structure for Homesick—shows real-world dotfiles.git patterns users would clonedefunkt/rip— Homesick's acknowledged predecessor/inspiration for package management approach (README explicitly compares to rip)technicalpickles/pickled-vim— Example castle repository maintained by Homesick's creator—reference implementation of the castle standard
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive integration tests for git_actions.rb
The lib/homesick/actions/git_actions.rb file handles critical git operations (cloning, pulling castles) but spec/homesick_cli_spec.rb appears to be the only test file. There are no dedicated tests for git-specific functionality like clone failures, authentication errors, or pull conflicts. This is high-risk code that deserves isolated unit tests.
- [ ] Create spec/homesick/actions/git_actions_spec.rb
- [ ] Add tests for git clone with invalid repos, missing credentials, and network failures
- [ ] Add tests for git pull operations and merge conflict scenarios
- [ ] Mock git commands using a library like allow/expect from RSpec to avoid real git operations
Add tests for file_actions.rb symlink operations
lib/homesick/actions/file_actions.rb likely contains symlink creation and management logic that needs isolated testing. Currently, file operations are tested through the CLI layer. Direct unit tests would catch edge cases like broken symlinks, permission errors, and existing file conflicts without requiring full CLI setup.
- [ ] Create spec/homesick/actions/file_actions_spec.rb
- [ ] Add tests for symlink creation, updates, and removal
- [ ] Test error handling for permission denied, file exists, and broken symlink scenarios
- [ ] Use filesystem mocking (e.g., tmpdir in tests) to avoid polluting user's actual home directory
Add CI workflow for Ruby version matrix testing
The .github/workflows/ci.yml exists but the repo doesn't appear to test against multiple Ruby versions. Since homesick is a distributed gem that users install, it should verify compatibility across supported Ruby versions (2.7, 3.0, 3.1, 3.2+). This prevents compatibility regressions.
- [ ] Update .github/workflows/ci.yml to add a ruby-version matrix strategy
- [ ] Test against Ruby 2.7, 3.0, 3.1, 3.2, and 3.3
- [ ] Verify Gemfile.lock or gemspec dependencies work across all versions
- [ ] Add coverage for both RSpec tests and RuboCop linting on each version
🌿Good first issues
- Add test coverage for symlink collision handling in lib/homesick/actions/file_actions.rb—spec lacks explicit cases for when ~/.vimrc already exists as a file (not symlink)
- Improve error messages in lib/homesick/cli.rb when a castle clone fails or a .homesickrc syntax error occurs—currently errors are raw Ruby exceptions
- Add a --dry-run flag to homesick link and unlink commands to preview what symlinks would be created/removed without mutating the filesystem
⭐Top contributors
Click to expand
Top contributors
📝Recent commits
Click to expand
Recent commits
a81cdd5— Merge pull request #191 from technicalpickles/dependabot/bundler/development-dependencies-4124cc5fc6 (JCook21)bdf0239— Bump rubocop from 1.85.1 to 1.86.0 in the development-dependencies group (dependabot[bot])eeca37e— Merge pull request #187 from JCook21/claude/fix-177-destroy-pretend-T81Cx (JCook21)d0e44f4— Merge pull request #190 from JCook21/ci-v5 (JCook21)7adf550— Add pretend-mode test coverage for all destructive file actions (claude)5447cac— Merge pull request #189 from JCook21/rubocop-before-tests (JCook21)cb631c7— Update Github builds to use v5. (JCook21)a3e2780— Change CI ordering to run RuboCop before tests. (JCook21)7d9907f— Merge pull request #188 from JCook21/claude/fix-65-generate-docs-T81Cx (JCook21)90a8802— Fix #65: document the generate command in README (claude)
🔒Security observations
Homesick is a dotfile management tool with moderate security concerns. The primary risks stem from: (1) potential command injection in git operations, (2) unsafe symlink creation that could allow arbitrary file overwrites, (3) arbitrary code execution via RC file loading, and (4) insufficient input validation on user-supplied arguments. The tool operates with high privilege (home directory manipulation), making these vulnerabilities significant. The codebase demonstrates good CI/CD hygiene with automated testing and dependency scanning, but security hardening in file operations and input validation is needed. Users should be warned about trusting only curated castle repositories.
- High · Potential Command Injection via Git Operations —
lib/homesick/actions/git_actions.rb. The application clones git repositories and manages symlinks in the home directory. The git_actions.rb file likely executes git commands that could be vulnerable to command injection if user input (repository URLs, castle names) is not properly sanitized before being passed to shell commands. Fix: Ensure all git commands use proper argument escaping (e.g., Shellwords.escape or system() with array arguments instead of string interpolation). Validate and sanitize repository URLs and castle names before use. - High · Unsafe File Symlink Operations —
lib/homesick/actions/file_actions.rb. The application creates symlinks from a git repository clone into the user's home directory. If an attacker controls the cloned repository, they could create symlinks that point to sensitive files outside the intended scope, leading to arbitrary file overwrites or information disclosure. Fix: Validate all symlink targets to ensure they remain within expected boundaries. Implement checks to prevent symlinks from pointing outside the castle repository or home directory. Validate symlink safety before creation. - Medium · Arbitrary Code Execution via Ruby File Loading —
lib/homesick/rc.rb. The application appears to load RC files (lib/homesick/rc.rb) which could execute arbitrary Ruby code. If an attacker can control the contents of these RC files, they could achieve remote code execution. Fix: Avoid loading and executing arbitrary Ruby code from user-controlled files. If RC files must be loaded, use a restricted DSL or configuration format (YAML, JSON) instead of Ruby eval/load. Implement strict whitelisting of allowed operations. - Medium · Missing Input Validation on CLI Arguments —
lib/homesick/cli.rb. The CLI (lib/homesick/cli.rb) accepts user input for castle names and git repository URLs without visible validation. This could allow injection attacks or unexpected behavior when processing untrusted input. Fix: Implement comprehensive input validation for all CLI arguments. Validate repository URLs against URL format specifications. Validate castle names to contain only safe characters (alphanumeric, hyphens, underscores). - Medium · Potential Path Traversal in File Operations —
lib/homesick/actions/file_actions.rb. The application manipulates home directory files and creates symlinks. Without proper path validation, an attacker could potentially use path traversal sequences (../) in castle file names to create symlinks outside the intended home directory structure. Fix: Normalize and validate all file paths before operations. Use Ruby's Pathname#expand_path and verify that resolved paths remain within expected boundaries. Reject paths containing '..' sequences. - Low · Dependency Management Best Practices —
Gemfile, Gemfile.lock. No dependency file content was provided for analysis. Homesick likely has Ruby gem dependencies that should be regularly audited for known vulnerabilities. Fix: Regularly run 'bundle audit' to check for vulnerable gem dependencies. Keep dependencies updated to their latest secure versions. Consider using GitHub's Dependabot (already configured in .github/dependabot.yml) and review its alerts regularly. - Low · Missing Security-Focused Documentation —
README.markdown. While the README provides usage instructions, there is no security documentation warning users about the risks of trusting untrusted castle repositories or best practices for castle repository management. Fix: Add a 'Security Considerations' section to the README warning users to only clone castles from trusted sources. Document the risks of symlink injection and the importance of reviewing castle contents before linking.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.