Skip to content

#71: Add project symlink install walking skeleton#76

Merged
sandsower merged 2 commits intomainfrom
phase-2-project-symlink-install
May 10, 2026
Merged

#71: Add project symlink install walking skeleton#76
sandsower merged 2 commits intomainfrom
phase-2-project-symlink-install

Conversation

@sandsower
Copy link
Copy Markdown
Owner

@sandsower sandsower commented May 10, 2026

Summary

  • add beislid install project [path] and beislid status project [path]
  • add install.sh --project [path] compatibility routing
  • install all skills by symlink into project-local .agents, .claude, and .codex skill dirs
  • write .beislid/project-install.json with source/version/commit, targets, and counts
  • document symlink-only project install behavior and limitations

Safety

  • repairs dangling symlinks
  • skips foreign live symlinks unless --force
  • never clobbers regular files/directories
  • skips symlinked project host dirs to avoid writing outside the project
  • warns when .beislid/workflow.md is missing

Verification

  • bash -n install.sh bin/beislid scripts/install_lib.sh scripts/test_install.sh
  • python3 scripts/validate_skills.py
  • bash scripts/test_install.sh — 49 passed, 0 failed
  • python3 tests/agent-smoke/run.py gate ship-it --hosts claude,codex --timeout 900 --changed-only — passed on claude and codex

Closes #71.

Summary by CodeRabbit

  • New Features

    • Project-scoped installs: beislid install project [path] and beislid status project [path]; --project and --force support; project installs create project-local symlinked skill layout and manifest.
  • Documentation

    • Updated README and docs to describe project install/state behavior, commands, flags, and recommended workflow steps.
  • Tests

    • Added integration tests covering project install/status behaviors, edge cases, and CLI compatibility.
  • Chores

    • Updated .gitignore to ignore plans/ and .beislid/project-install.json.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 10, 2026

📝 Walkthrough

Walkthrough

This PR implements project-level symlink installation for Beislið skills. It adds beislid install project [path] and beislid status project [path] CLI commands, extends install.sh --project support, creates project-local skill directories (.agents/.claude/.codex/skills), writes a per-project manifest (.beislid/project-install.json), and includes comprehensive tests and documentation for this capability.

Changes

Project-Level Symlink Install

Layer / File(s) Summary
Ignore Patterns & CLI Contract
.gitignore, bin/beislid, README.md
Adds .beislid/project-install.json and plans/ to .gitignore and documents beislid install project [path] / beislid status project [path] in CLI usage.
CLI Dispatcher
bin/beislid
Adds _parse_project_install_flags() parser, validates project-install flags, and routes install project to beislid_install_project; extends status to accept project target.
Installer Script Wiring
install.sh
Adds --project [path] flag parsing, guards against invalid flag combinations, and branches the install flow to call beislid_install_project when project mode is enabled.
Project Helpers
scripts/install_lib.sh
Implements project target resolution, manifest path computation, JSON manifest writer, link-counting wrapper, and project directory validation/creation helpers.
Install & Status Functions
scripts/install_lib.sh
Adds beislid_install_project() to symlink repo skills into project-local directories and optionally write the manifest; adds beislid_status_project() to report manifest presence, expected host skill dirs, and installed-skill counts.
Tests & Documentation
scripts/test_install.sh, README.md, docs/configuration.md, docs/how-to-use.md
Adds test helpers and ~14 integration tests covering explicit targets, git-root detection, install.sh compatibility, symlink edge cases (dangling, foreign, repoint-with---force), manifest format/presence, status reporting, and documents CLI flags, machine state, and project directory layout.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

  • sandsower/beislid#71: This PR implements the Phase 2 walking skeleton for project-level symlink install (CLI commands, git-root/default target rules, symlink-only installs, manifest, and minimal status).

Possibly related PRs

Poem

🐰 I hopped through repo roots and planted tiny links,
Manifests tucked in .beislid where each project thinks,
Symlinks sprout in projects, tidy and small,
Status checks to count them — I celebrate them all!
🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically identifies the main change as implementing a project symlink install walking skeleton for issue #71, which matches the scope of changes across CLI, installation logic, and documentation.
Linked Issues check ✅ Passed All primary objectives from issue #71 are met: project install/status commands implemented, safe symlink rules applied, manifest written, project dirs created, default path logic implemented, soft warnings for missing workflow.md, and all acceptance criteria satisfied per test coverage.
Out of Scope Changes check ✅ Passed All changes align with #71 scope; out-of-scope items (copy mode, ownership markers, gitignore writes, strict mode, deep validation, Windows, Homebrew) are not introduced; .gitignore changes are limited to ignoring project manifest only.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch phase-2-project-symlink-install

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
scripts/install_lib.sh (1)

533-546: ⚡ Quick win

This status metric is counting links, not skills.

_count_project_skill_links increments once per host directory, so a healthy install reports 3 * <skill count> in installed_skill_links. If that is intentional, the field/docs should say “link count”; otherwise dedupe per skill so project status matches the promised installed-skill count.

Also applies to: 594-595

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/install_lib.sh` around lines 533 - 546, _count_project_skill_links
currently increments for each host directory (dir) that contains a symlink,
causing triple-counting; change it to count unique skills only by tracking seen
skill names (e.g., a local associative array/set keyed by skill) so each skill
basename (variable skill found from skill_dir) is counted once even if symlinked
in multiple host dirs; update the loop using skill_dir/skill/expected to mark
seen skills and only increment when a skill is first observed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/install_lib.sh`:
- Around line 489-497: The missing-workflow warning is skipped when
_ensure_project_metadata_dir sets manifest_active=0 for a file/symlink .beislid;
change the conditional that prints the note so it checks the actual presence of
"$project/.beislid/workflow.md" regardless of manifest_active. Concretely,
update the if that now reads `if [[ "$manifest_active" == 1 && ! -f
"$project/.beislid/workflow.md" ]]; then` to a check that only tests the absence
of the workflow file (e.g., `if [[ ! -f "$project/.beislid/workflow.md" ]];
then`) so the note about missing workflow is always emitted when the workflow
file is unavailable while leaving _ensure_project_metadata_dir and
manifest_active semantics elsewhere unchanged.

---

Nitpick comments:
In `@scripts/install_lib.sh`:
- Around line 533-546: _count_project_skill_links currently increments for each
host directory (dir) that contains a symlink, causing triple-counting; change it
to count unique skills only by tracking seen skill names (e.g., a local
associative array/set keyed by skill) so each skill basename (variable skill
found from skill_dir) is counted once even if symlinked in multiple host dirs;
update the loop using skill_dir/skill/expected to mark seen skills and only
increment when a skill is first observed.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7b8af616-0456-4676-b3c4-9830a3e6a5d8

📥 Commits

Reviewing files that changed from the base of the PR and between 6f612a3 and e36f3a8.

📒 Files selected for processing (8)
  • .gitignore
  • README.md
  • bin/beislid
  • docs/configuration.md
  • docs/how-to-use.md
  • install.sh
  • scripts/install_lib.sh
  • scripts/test_install.sh

Comment thread scripts/install_lib.sh
@sandsower
Copy link
Copy Markdown
Owner Author

Also fixed the status-count nit: project status now reports unique installed skills (installed_skills) instead of counting each host link. Covered by the updated status tests in a5c67c6.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
scripts/install_lib.sh (1)

557-557: 💤 Low value

Consider splitting declaration and assignment (SC2155).

Shellcheck flags this because local masks the return value of the command substitution. While _project_manifest_path is just a printf that effectively can't fail, separating declaration and assignment is defensive against future refactoring.

♻️ Proposed fix
+  local manifest
+  manifest="$(_project_manifest_path "$project")"
-  local manifest="$(_project_manifest_path "$project")"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/install_lib.sh` at line 557, ShellCheck SC2155 warns about combining
`local` with command substitution; modify the code in the install script so you
declare then assign `manifest` separately: replace `local
manifest="$(_project_manifest_path "$project")"` with a two-step sequence `local
manifest` followed by `manifest="$(_project_manifest_path "$project")"`,
referencing the `_project_manifest_path` command substitution and the `manifest`
variable to avoid masking the command's return value.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@scripts/install_lib.sh`:
- Line 557: ShellCheck SC2155 warns about combining `local` with command
substitution; modify the code in the install script so you declare then assign
`manifest` separately: replace `local manifest="$(_project_manifest_path
"$project")"` with a two-step sequence `local manifest` followed by
`manifest="$(_project_manifest_path "$project")"`, referencing the
`_project_manifest_path` command substitution and the `manifest` variable to
avoid masking the command's return value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a4b3c89f-e766-4f8d-9545-d13e773cd25b

📥 Commits

Reviewing files that changed from the base of the PR and between e36f3a8 and a5c67c6.

📒 Files selected for processing (2)
  • scripts/install_lib.sh
  • scripts/test_install.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • scripts/test_install.sh

@sandsower sandsower merged commit 3339219 into main May 10, 2026
7 checks passed
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.

[#51 Phase 2] Add project symlink install walking skeleton

1 participant