Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .agents/skills/hunk-extensions/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: hunk-extensions
description: Maps the `hunkdiff/extension` authoring surface for Hunk, the terminal diff viewer — hiding or reordering reviewed files, docked panes, alternate file views, commands and key bindings, dialogs, workspace writes, themes, syntax languages, VCS backends, lifecycle events. Use when writing, debugging, or installing a Hunk extension, or when a request asks Hunk itself to behave differently. Not for reviewing a diff in a live session — that is hunk-review.
---

<!-- generated by `hunk skill install` -->

# hunk-extensions

This file is a pointer. The instructions live in the installed `hunk` CLI so they always match its version.

Before anything else, load them and follow them:

```bash
hunk skill show hunk-extensions
```

If `hunk` is not on PATH, ask the user to install Hunk first: https://hunk.dev/docs/start/install/
18 changes: 18 additions & 0 deletions .agents/skills/hunk-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: hunk-review
description: Interacts with live Hunk diff review sessions via CLI. Inspects review focus, navigates files, hunks, and exact lines, reloads session contents, adds inline review comments, and paints attention marks on character ranges. Use when the user has a Hunk session running or wants to review diffs interactively.
---

<!-- generated by `hunk skill install` -->

# hunk-review

This file is a pointer. The instructions live in the installed `hunk` CLI so they always match its version.

Before anything else, load them and follow them:

```bash
hunk skill show hunk-review
```

If `hunk` is not on PATH, ask the user to install Hunk first: https://hunk.dev/docs/start/install/
5 changes: 5 additions & 0 deletions .changeset/light-agent-skills.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"hunkdiff": minor
---

Add `hunk skill install --agent <name>` to teach a coding agent how to drive Hunk in one command. It writes a short pointer `SKILL.md` into the skills directory of Claude Code, Codex, opencode, Cursor, Amp, GitHub Copilot, or any tool reading `.agents/skills`; repeat `--agent` for several, and add `--project` to install into the current repository. The pointer keeps only the skill's name and description and loads the rest through the new `hunk skill show [name]`, so it stays current across Hunk upgrades instead of going stale as a copy. The repository also publishes the same pointer skills under `.agents/skills/`, so `npx skills add modem-dev/hunk -g` installs them through the skills CLI, and the maintainer-only skills are marked internal so that command no longer offers them.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ Watch mode remains continuous. Direct-file and Git-backed reviews normally use f
### Working with agents

1. Open Hunk in another terminal with `hunk diff` or `hunk show`.
2. Tell your agent to add the skill file returned by `hunk skill path`.
3. Ask your agent to use the skill against the live Hunk session.
2. Install the review skill into your agent once: `hunk skill install --agent claude` (also `codex`, `opencode`, `cursor`, `amp`, `copilot`, or `agents`). With Node available, `npx skills add modem-dev/hunk -g` installs the same skill into every agent the [skills CLI](https://github.com/vercel-labs/skills) supports.
3. Ask your agent to review the live Hunk session.

A good generic prompt is:
The installed skill is a short pointer that loads its instructions from `hunk skill show`, so it stays current across Hunk upgrades. Without an installed skill, a good generic prompt is:

```text
Load the Hunk skill and use it for this review. Run `hunk skill path` to get the skill path.
Run `hunk skill show` and follow that skill to review the live Hunk session.
```

For the full live-session and `--agent-context` workflow guide, see [the agent workflow guide](https://github.com/modem-dev/hunk/blob/main/docs/agent-workflows.md). Experimental rich STML note bodies require starting the review with `--experimental`; plain agent notes remain the default.
Expand Down
20 changes: 16 additions & 4 deletions docs/agent-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ Use Hunk with agents in two ways:
## Recommended workflow: steer a live Hunk window

1. Open Hunk in one terminal with a normal review command such as `hunk diff` or `hunk show`.
2. Load the Hunk review skill: [`packages/hunk/skills/hunk-review/SKILL.md`](../packages/hunk/skills/hunk-review/SKILL.md).
3. Ask the agent to use the skill and review the current session.
2. Install the Hunk review skill into your agent once:

A good generic prompt is:
```bash
hunk skill install --agent claude # or codex, opencode, cursor, amp, copilot, agents
```

3. Ask the agent to review the current Hunk session.

The installed file is a short pointer that carries the skill's name and description and loads the
rest with `hunk skill show`, so it never goes stale when Hunk upgrades. Repeat `--agent` to install
into several agents, or add `--project` to write it into the current repository instead of your
home directory. Agents that load or symlink files directly can use `hunk skill path` instead.
With Node available, `npx skills add modem-dev/hunk -g` installs the same pointer through the
[skills CLI](https://github.com/vercel-labs/skills); the repository publishes it under `.agents/skills/`.

Without an installed skill, a good generic prompt is:

```text
Load the Hunk skill and use it for this review. Run `hunk skill path` to get the skill path.
Run `hunk skill show` and follow that skill to review the live Hunk session.
```

That skill teaches the agent how to inspect a live Hunk session, navigate it, reload it, and leave inline comments.
Expand Down
8 changes: 4 additions & 4 deletions packages/hunk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,13 @@ Watch mode remains continuous. Direct-file and Git-backed reviews normally use f
### Working with agents

1. Open Hunk in another terminal with `hunk diff` or `hunk show`.
2. Tell your agent to add the skill file returned by `hunk skill path`.
3. Ask your agent to use the skill against the live Hunk session.
2. Install the review skill into your agent once: `hunk skill install --agent claude` (also `codex`, `opencode`, `cursor`, `amp`, `copilot`, or `agents`). With Node available, `npx skills add modem-dev/hunk -g` installs the same skill into every agent the [skills CLI](https://github.com/vercel-labs/skills) supports.
3. Ask your agent to review the live Hunk session.

A good generic prompt is:
The installed skill is a short pointer that loads its instructions from `hunk skill show`, so it stays current across Hunk upgrades. Without an installed skill, a good generic prompt is:

```text
Load the Hunk skill and use it for this review. Run `hunk skill path` to get the skill path.
Run `hunk skill show` and follow that skill to review the live Hunk session.
```

For the full live-session and `--agent-context` workflow guide, see [the agent workflow guide](https://github.com/modem-dev/hunk/blob/main/docs/agent-workflows.md). Experimental rich STML note bodies require starting the review with `--experimental`; plain agent notes remain the default.
Expand Down
83 changes: 68 additions & 15 deletions packages/hunk/src/app/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
parseCli,
WATCH_OPTION,
} from "./cli";
import { AGENT_SKILL_HOST_IDS } from "../core/install/agentSkills";
import { readBundledSkillDocument } from "../core/run/paths";
import { resolveCliVersion } from "../core/run/version";

const tempDirs: string[] = [];
Expand Down Expand Up @@ -653,22 +655,71 @@ describe("parseCli", () => {
test("prints skill help for hunk skill --help", async () => {
const parsed = await parseCli(["bun", "hunk", "skill", "--help"]);

expect(parsed).toEqual({
kind: "help",
text: [
"Usage: hunk skill path [name]",
"",
"Print a bundled Hunk skill path.",
"Load or symlink that file in your coding agent to keep it in sync across Hunk upgrades.",
"",
"Skills:",
` hunk-review (default, "review") review a live Hunk session with \`hunk session\` commands`,
` hunk-extensions ("extensions") build extensions against the hunkdiff/extension API`,
"",
].join("\n"),
expect(parsed.kind).toBe("help");
if (parsed.kind !== "help") {
throw new Error("Expected skill help output.");
}
expect(parsed.text).toContain(
"hunk skill install --agent <name> [skill] [--project] [--force]",
);
expect(parsed.text).toContain("hunk skill show [skill]");
expect(parsed.text).toContain("hunk skill path [skill]");
expect(parsed.text).toContain(`Agents: ${AGENT_SKILL_HOST_IDS.join(", ")}.`);
expect(parsed.text).toContain(` hunk-review (default, "review")`);
});

test("prints the bundled skill text for hunk skill show", async () => {
const parsed = await parseCli(["bun", "hunk", "skill", "show"]);
expect(parsed).toEqual({ kind: "help", text: readBundledSkillDocument("hunk-review") });

const named = await parseCli(["bun", "hunk", "skill", "show", "extensions"]);
expect(named).toEqual({ kind: "help", text: readBundledSkillDocument("hunk-extensions") });
});

test("parses hunk skill install into agents, scope, and skill", async () => {
expect(await parseCli(["bun", "hunk", "skill", "install", "--agent", "claude"])).toEqual({
kind: "skill-install",
skill: "hunk-review",
agents: ["claude"],
scope: "user",
force: false,
});

expect(
await parseCli([
"bun",
"hunk",
"skill",
"install",
"--agent",
"Claude-Code",
"--agent",
"codex",
"--project",
"--force",
"extensions",
]),
).toEqual({
kind: "skill-install",
skill: "hunk-extensions",
agents: ["claude", "codex"],
scope: "project",
force: true,
});
});

test("rejects hunk skill install without a known agent", async () => {
await expect(parseCli(["bun", "hunk", "skill", "install"])).rejects.toThrow(
"`hunk skill install` requires --agent <name>.",
);
await expect(parseCli(["bun", "hunk", "skill", "install", "--agent", "aider"])).rejects.toThrow(
'Unknown agent "aider". Agents are `claude`, `codex`',
);
await expect(
parseCli(["bun", "hunk", "skill", "install", "--agent", "claude", "bogus"]),
).rejects.toThrow('Unknown skill "bogus".');
});

test("parses the daemon serve command", async () => {
const parsed = await parseCli(["bun", "hunk", "daemon", "serve"]);

Expand Down Expand Up @@ -1941,8 +1992,10 @@ describe("parseCli command help text", () => {

test("renders skill help for both `skill --help` and `skill path --help`", async () => {
const bare = await expectHelp(["skill", "--help"]);
expect(bare).toContain("Usage: hunk skill path");
expect(bare).toContain("hunk skill path [skill]");
expect(await expectHelp(["skill", "path", "--help"])).toBe(bare);
expect(await expectHelp(["skill", "show", "--help"])).toBe(bare);
expect(await expectHelp(["skill", "install", "--help"])).toBe(bare);
});

test("renders the comment overview and per-comment-subcommand help", async () => {
Expand Down Expand Up @@ -2092,7 +2145,7 @@ describe("parseCli argument validation", () => {

test("rejects unknown skill, daemon, stash, and comment subcommands", async () => {
await expect(parseCli(["bun", "hunk", "skill", "bogus"])).rejects.toThrow(
"Only `hunk skill path` is supported.",
"Supported skill subcommands are install, show, and path.",
);
await expect(parseCli(["bun", "hunk", "skill", "path", "bogus"])).rejects.toThrow(
'Unknown skill "bogus". Bundled skills are hunk-review and hunk-extensions.',
Expand Down
Loading
Loading