Add hunk skill install to teach agents how to drive Hunk - #1093
Add hunk skill install to teach agents how to drive Hunk#1093benvinegar wants to merge 5 commits into
hunk skill install to teach agents how to drive Hunk#1093Conversation
`hunk skill install --agent <name>` writes a thin pointer SKILL.md into a coding agent's skills directory (Claude Code, Codex, opencode, Cursor, Amp, GitHub Copilot, or the shared `.agents/skills` convention). The pointer carries only the bundled skill's name and description and tells the agent to run the new `hunk skill show`, so the installed Hunk binary stays the single owner of the skill text and upgrades never leave a stale copy behind. - `--agent` repeats for several hosts; shared directories are written once. - `--project` targets the current directory instead of the home directory. - Hunk rewrites its own earlier pointer but refuses a hand-written SKILL.md unless `--force` is passed, and checks every target before writing any. - Docs, README, agent workflow guide, and the generated CLI reference now lead with the install command. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PqAUQp8FqVcDxcMHXV3ci
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
`check:pack` requires packages/hunk/README.md to match the root README, which now leads the agent section with `hunk skill install`. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PqAUQp8FqVcDxcMHXV3ci
Greptile SummaryThis PR adds
Confidence Score: 3/5This PR is not safe to merge until project-scoped installs reject symlink escapes and the explicit repository requirements are satisfied. A malicious checkout can redirect the new project-scoped write outside the repository because the implementation follows symlinked targets and ancestors; the new module also violates applicable filename and environment-access requirements. Files Needing Attention: packages/hunk/src/core/install/agentSkills.ts, packages/hunk/src/core/install/agentSkills.test.ts
|
| Filename | Overview |
|---|---|
| packages/hunk/src/core/install/agentSkills.ts | Implements host resolution, pointer rendering, conflict checks, and installation, but project writes can escape through symlinks and two repository rules are violated. |
| packages/hunk/src/app/cli.ts | Adds parsing, validation, help, and reference metadata for the new install and show subcommands. |
| packages/hunk/src/app/startup.ts | Routes parsed skill installations into a headless startup plan. |
| packages/hunk/src/main.tsx | Executes the new installation plan and forwards command output to stdout. |
| packages/hunk/src/core/install/agentSkills.test.ts | Covers host resolution, target planning, frontmatter rendering, deduplication, and conflict handling, but not real-filesystem symlink behavior. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[hunk skill install] --> B[Parse agents, skill, scope, and force]
B --> C[Read bundled skill frontmatter]
C --> D[Resolve host skill directories]
D --> E[Deduplicate target paths]
E --> F[Precheck existing SKILL.md files]
F -->|Conflict without force| G[Abort before writes]
F -->|Allowed| H[Create target directories]
H --> I[Write pointer SKILL.md]
I --> J[Agent loads pointer]
J --> K[hunk skill show]
K --> L[Full bundled instructions]
Prompt To Fix All With AI
### Issue 1
packages/hunk/src/core/install/agentSkills.ts:273-275
**Project Writes Follow Symlinks**
When `--project` is run in a checkout containing a symlinked `SKILL.md` or parent directory, `mkdirSync` and `writeFileSync` follow that repository-controlled link without checking that the resolved path remains in the checkout. This can overwrite or create a user-writable file outside the repository. Reject symlinked targets and ancestors before writing, as the existing workspace write guard does.
**How this was verified:** The target is rooted at the current checkout, while the final `mkdirSync` and `writeFileSync` calls perform no `lstat` or canonical-path containment check and therefore follow repository-provided links.
### Issue 2
packages/hunk/src/core/install/agentSkills.ts:1
**New Files Violate Naming**
The new `agentSkills.ts` source and `agentSkills.test.ts` test use camel-cased filenames. The repository directive requires dash-case for `.ts` and `.tsx` files, so these must be renamed to `agent-skills.ts` and `agent-skills.test.ts` and their imports updated before merging.
### Issue 3
packages/hunk/src/core/install/agentSkills.ts:288
**Package Reads Environment Directly**
This package-level command falls back directly to `process.env`. The repository directive prohibits direct `process.env` access and requires validated environment values to be passed from the application, so the command should receive them through its existing IO boundary before merging.
### Issue 4
packages/hunk/src/core/install/agentSkills.ts:302
**Marker Can Misidentify Ownership**
The unrestricted substring check treats any file containing the public HTML marker as Hunk-generated. A hand-written or modified skill that quotes this marker will therefore be silently overwritten without `--force`, contrary to the documented promise to preserve hand-written skills. Validate the complete generated-file structure or use stronger ownership metadata to avoid losing user content.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (1): Last reviewed commit: "feat(cli): add `hunk skill install --age..." | Re-trigger Greptile
…shape `hunk skill install --project` writes under repository content, so a checkout could redirect `.claude/skills` (or the SKILL.md itself) through a symlink into the user's home. Walk each component below the repository root with lstat and refuse the first link, stopping at the first missing component; user-scoped installs stay unchecked because those directories are the user's own and are often symlinked into dotfiles on purpose. Ownership of an existing SKILL.md now requires the exact generated shape (frontmatter, blank line, marker) rather than the marker appearing anywhere, so a hand-written skill that quotes it is not overwritten without --force. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PqAUQp8FqVcDxcMHXV3ci
The skills CLI scans a repository's root `skills/` and `.agents/skills/` but not `packages/hunk/skills/`, so `npx skills add modem-dev/hunk` offered only the maintainer-only release and video skills. Generate the same pointer stub `hunk skill install` writes into `.agents/skills/<name>/` for each bundled skill, and mark the maintainer skills `metadata.internal` so the CLI hides them. A test keeps the checked-in pointers in sync with the renderer; `bun run generate:skill` regenerates them. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PqAUQp8FqVcDxcMHXV3ci
…65if1 # Conflicts: # packages/hunk/src/app/cli.ts
Adds
hunk skill install --agent <name>command to install pointer skills into coding agents' skill directories. This replaces the manual workflow of locating and loading skill files.Summary
The installed pointer skill is deliberately minimal: it carries only the bundled skill's name and description in frontmatter, then directs the agent to run
hunk skill showfor the full instructions. This keeps the installed Hunk binary as the single owner of skill text, ensuring pointer skills never go stale across Hunk upgrades.Key changes
agentSkills.tsmodule defines agent host configurations (Claude Code, Codex, opencode, Cursor, Amp, GitHub Copilot, and the shared.agents/skillsconvention), resolves user-supplied agent names and aliases, and implements the install command logicnameanddescription) from bundled skills and wraps them in a stub that defers tohunk skill showfor the real instructions--agentcan repeat; when multiple agents share a skills directory (e.g., Codex, Amp, and the generic host all read.agents/skills), the pointer is written once--projectflag to write under the current directory instead of the home directoryhunk skill show(prints bundled skill text) andhunk skill installsubcommands; updated help text and documentationImplementation details
$XDG_CONFIG_HOME,$HOME, and agent-specific environment variables (e.g.,$CLAUDE_CONFIG_DIR) to locate skills directories<!-- generated by \hunk skill install` -->`) so reinstalls can distinguish Hunk-generated files from hand-written oneshttps://claude.ai/code/session_018PqAUQp8FqVcDxcMHXV3ci