Skip to content
Draft
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
82 changes: 82 additions & 0 deletions .claude/skills/generate-commit-message/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
name: generate-commit-message
description: Use git diff to analyze changes and generate a conventional commit message following this project's conventions from AGENTS.md
disable-model-invocation: true
allowed-tools: Bash(git diff *) Bash(git status) Bash(git log *)
---

Generate a commit message for the current changes by following these steps:

## 1. Parse arguments

`$ARGUMENTS` may contain additional context for the commit message.

## 2. Gather context

- Run `git status` to see what files are staged vs unstaged.
- Run `git diff --cached` to see staged changes. If nothing is staged, inform the user that nothing is staged and stop — do not fall back to unstaged changes.
- Run `git log --oneline -10` to see recent commit messages for style reference.

## 3. Analyze the changes

Identify the **type** based on the nature of the change. This project uses both standard Conventional Commit types and module-level types:

**Standard types:** `feat`, `fix`, `refactor`, `test`, `docs`, `ci`, `chore`, `perf`, `style`, `build`

**Module-level types** — used when the change is entirely within one of these subsystems:
- `run_script` — changes scoped to `tools/run_script.py` or the run_script workflow
- `eval` — changes to the gatekeeper evaluation/benchmark system

Identify the **scope** from the area of the codebase affected. Use these established scopes:

| Scope | When to use |
|-------|------------|
| `ssh` | `connection/ssh.py` or SSH-related logic |
| `run_script` | `tools/run_script.py` (use as scope with `fix`/`feat`, or as standalone type) |
| `deps` | dependency version bumps (`chore(deps)`) |
| `ci` | CI/CD workflows in `.github/` |
| `scripts` | utility scripts in `scripts/` |
| `functional` | functional/integration tests in `tests/functional/` |
| `storage` | `tools/storage.py` or storage-related tools |
| `models` | `models.py` data model changes |
| `validation` | `utils/validation.py` input validation |
| `mcp-apps(ui)` | React UI in `mcp-app/` (nested scope) |

**Scope rules:**
- Omit scope when the change spans multiple areas or no established scope fits.
- When using a module-level type like `run_script:` or `eval:`, do not add a redundant scope.
- For dependency updates, always use `chore(deps):`.

## 4. Generate the commit message

Follow the [Conventional Commits](https://www.conventionalcommits.org/) format:

```
type(scope): short imperative description
```

Or for module-level types:

```
type: short imperative description
```

**Subject line rules:**
- Imperative mood, lowercase start, no period at the end.
- Under 72 characters total.
- Focus on **why** or **what changed**, not how.
- If there is a `$ARGUMENTS` value, use it as additional context for the message.

**Body** (optional — only when the subject line alone doesn't capture the reasoning):
```

Motivation and context behind the change.
Wrap at 72 characters per line.
```

## 5. Present the result

Show the generated commit message in a code block so the user can review it. Ask the user if they'd like to:
1. Use the message as-is (run `git commit` with it)
2. Edit it before committing
3. Regenerate with different emphasis
92 changes: 92 additions & 0 deletions .claude/skills/prepare-for-pull-request/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
---
name: prepare-for-pull-request
description: Run make verify, then summarize changes since a given commit SHA into a PR description
disable-model-invocation: true
allowed-tools: Bash(make *) Bash(git diff *) Bash(git log *) Bash(git status) Bash(git rev-parse *) Bash(git reflog *)
argument-hint: "[base-commit-sha]"
---

Prepare a pull request description by verifying the code and summarizing all changes since a base commit.

## Step 0: Determine the base ref

If `$ARGUMENTS` is provided (e.g. a SHA, `main`, `HEAD~3`), use it as the base ref.

If `$ARGUMENTS` is empty, auto-detect the branch point:

1. Get the current branch name: `git rev-parse --abbrev-ref HEAD`
2. Find where this branch was created from using reflog: `git reflog show <current-branch> --format='%H %gs'`
3. Look for the entry with `branch: Created from` in the reflog output — the SHA on that line is where the branch was born.
4. Use that SHA as the base ref. Tell the user which base ref was auto-detected so they can confirm.

If the reflog doesn't contain a `Created from` entry (e.g. the reflog was pruned), fall back to asking the user for the base ref.

## Step 1: Run verification

Run `make verify` to sync dependencies and execute all CI checks (lint, format, types, tests).

- If it passes, proceed to step 2.
- If it fails, stop and show the user the errors. Offer to help fix them before continuing. Do NOT proceed to PR description generation until verification passes.

## Step 2: Gather change information

Run these commands to understand the full scope of changes:

- `git log --oneline $ARGUMENTS..HEAD` — list all commits being included.
- `git log --format="### %s%n%n%b" $ARGUMENTS..HEAD` — get full commit messages with bodies.
- `git diff --stat $ARGUMENTS..HEAD` — file-level summary of what changed.
- `git diff $ARGUMENTS..HEAD` — full diff for detailed analysis.

**Uncommitted changes:** By default, only include committed changes in the PR description. Ignore uncommitted (staged or unstaged) files unless the user explicitly mentions or asks to include them.

## Step 3: Analyze and categorize

Review all commits and the diff to understand:

- **The problem or gap that motivated this work** — what was missing, broken, or insufficient before this PR? Derive this from commit messages, code comments, and the nature of the changes themselves.
- What features were added, bugs fixed, or refactors made.
- Which project components were affected — map changes to the project architecture:
- **Tools** (`tools/*.py`) — which MCP tools were added or modified?
- **Parsers/Formatters** (`parsers.py`, `formatters.py`) — output parsing or display changes?
- **Connection** (`connection/ssh.py`) — SSH or remote execution changes?
- **Models** (`models.py`) — data model changes?
- **Config** (`config.py`) — new env vars or configuration options?
- **Gatekeeper** (`gatekeeper/`) — script validation changes?
- **MCP App** (`mcp-app/`) — UI changes?
- **Tests** (`tests/`) — new or modified test coverage?
- **CI/Docs/Scripts** — infrastructure changes?
- Any breaking changes, new dependencies, or new `LINUX_MCP_*` configuration variables.

## Step 4: Generate the PR description

Produce a PR description in this format:

```markdown
## Motivation
<!-- 1-3 sentences explaining the problem, gap, or motivation that drove this PR. Answer: what was the situation before, and why was it insufficient? Do NOT describe what the code does here — focus on the reason the work was needed. -->

## Summary
<!-- 1-3 bullet points describing the high-level approach taken to address the problem above -->

## Changes
<!-- Bulleted list of specific changes, grouped by affected project area (e.g. Tools, Parsers, Models, Config, Tests, CI, Docs). Use the project's component names, not generic categories. -->

## Test plan
<!-- How the changes were verified — reference make verify passing, plus any manual testing or specific test cases added -->

🤖 Generated with [Claude Code](https://claude.com/claude-code)
```

Rules:
- **"Motivation" comes first** and must answer "what problem does this solve?" — not "what does this PR do?"
- Keep the summary concise — focus on the approach, not a line-by-line rehash.
- In the Changes section, group by project component (Tools, Connection, Models, Config, Tests, etc.) rather than generic categories.
- Call out breaking changes, migration steps, or new `LINUX_MCP_*` env vars prominently.
- Mention new dependencies or changes to `pyproject.toml` if applicable.

## Step 5: Present the result

Show the generated PR description in a code block. Ask the user if they'd like to:
1. Create the PR now using `gh pr create` with this description
2. Edit the description first
3. Regenerate with different emphasis
182 changes: 182 additions & 0 deletions .claude/skills/review-pr/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
---
name: review-pr
description: Review a pull request by URL for code format, types, semantic correctness, readability, redundant logic, bugs, and security concerns
disable-model-invocation: true
allowed-tools: Bash(gh pr *) Bash(gh api *) Bash(git diff *) Bash(git log *) Bash(git status) Bash(git fetch *) Bash(git checkout *) Bash(git rev-parse *) Bash(git merge-base *) Bash(make lint) Bash(make format) Bash(make types) Bash(make test) Read
argument-hint: "<pr-url>"
---

Review a pull request for code quality issues across six dimensions: format, types, semantic correctness, readability, redundant logic, and bugs/security.

## Step 0: Fetch PR information

`$ARGUMENTS` must be a GitHub PR URL (e.g. `https://github.com/owner/repo/pull/123`).

If `$ARGUMENTS` is empty, ask the user for the PR URL. Do not proceed without it.

1. Extract the PR number from the URL.
2. Run `gh pr view <pr-url> --json number,title,baseRefName,headRefName,commits,files` to get PR metadata.
3. Fetch the PR branch locally:
- `git fetch origin pull/<number>/head:pr-<number>` to create a local ref for the PR.
- Determine the merge base: `git merge-base origin/<baseRefName> pr-<number>`
4. Use the merge base as the base ref for all diff commands.

Tell the user which PR you're reviewing (number, title, head branch, base branch).

## Step 1: Gather changes

Run these commands to understand the full scope of changes:

- `git log --oneline <merge-base>..pr-<number>` — list all commits in the PR.
- `git diff --stat <merge-base>..pr-<number>` — file-level summary of what changed.
- `git diff <merge-base>..pr-<number>` — full diff for detailed analysis.

Read every changed file in full (from the PR branch) so you can evaluate changes in their surrounding context, not just the diff hunks in isolation. Use `git show pr-<number>:<file-path>` to read files from the PR branch without switching branches.

## Step 2: Format check

Run `make lint` and `make format` against the PR branch to check for formatting and linting violations.

To do this without modifying the current working tree:
- Check out the PR branch: `git checkout pr-<number>`
- Run `make lint` and `make format`.
- After the review is complete (Step 8), check out the original branch.

Report results:
- **Pass** — no issues found.
- **Fail** — list every violation with file path, line number, and the rule ID. Group by file.

Do NOT auto-fix. Only report.

## Step 3: Type check

Run `make types` to run pyright on the PR branch.

Report results:
- **Pass** — no type errors.
- **Fail** — list every error with file path, line number, and the pyright message. Group by file.

For the `mcp-app/` TypeScript code, if any `.ts` or `.tsx` files are in the diff, note that TypeScript type checking should be run separately inside `mcp-app/` if a tsconfig and type-check script exist there.

## Step 4: Semantic review

Analyze every changed file for semantic correctness. For each file, check:

1. **Behavioral changes** — Does the change alter existing behavior? Is that intentional or an accidental regression? Look for:
- Changed return values, error handling, or control flow.
- Modified default values or function signatures.
- Altered query/filter logic.

2. **Edge cases** — Are there inputs or states the new code doesn't handle?
- Empty/null/zero-length inputs.
- Boundary values (off-by-one, max int, empty string vs None).
- Concurrent or async race conditions.

3. **API contract consistency** — Do changes to models, tool signatures, or config stay consistent across:
- `models.py` ↔ `parsers.py` ↔ `formatters.py`
- `commands.py` ↔ `tools/*.py`
- `config.py` env var names ↔ documentation

4. **Test coverage** — Are new code paths covered by tests? Flag any added logic that lacks a corresponding test case.

Report each finding with:
- File path and line number(s).
- What the issue is.
- Severity: **critical** (likely bug/regression), **warning** (potential issue), or **info** (suggestion).

## Step 5: Readability and redundancy review

Evaluate the changed code for maintainability:

1. **Readability issues:**
- Overly complex expressions that should be broken up.
- Unclear variable or function names.
- Deeply nested logic (3+ levels) that could be flattened with early returns or guard clauses.
- Magic numbers or strings that should be named constants.
- Functions doing too many things (violating single responsibility).

2. **Redundant logic:**
- Duplicate code across the diff or between the diff and existing code.
- Conditions that are always true/false.
- Unnecessary intermediate variables or re-assignments.
- Dead code (unreachable branches, unused imports, unused variables).
- Over-engineered abstractions for simple operations.

Report each finding with file path, line number(s), what the issue is, and a concrete suggestion for improvement.

## Step 6: Bug and security review

Scan changes for bugs and security concerns, with special attention to this project's security model (read-only tools, SSH key auth, input validation):

1. **Bugs:**
- Incorrect exception handling (swallowing errors, catching too broadly).
- Resource leaks (unclosed connections, file handles).
- Async issues (missing `await`, unawaited coroutines).
- Incorrect use of mutable default arguments.

2. **Security (OWASP + project-specific):**
- **Command injection** — Any user input reaching shell commands without validation. Check against the project's `commands.py` allowlist pattern.
- **Path traversal** — File path parameters that aren't validated against allowlists (see `ALLOWED_LOG_PATHS`, `MAX_FILE_READ_BYTES`).
- **Information disclosure** — Sensitive data in logs, error messages, or tool outputs. Check that `audit.py` redaction covers new fields.
- **SSH security** — Any weakening of host key verification, key-based auth, or connection pooling.
- **Read-only violation** — Any tool missing `readOnlyHint=True` or performing writes without going through the gatekeeper.
- **Input validation** — Missing or insufficient validation on tool parameters (see `utils/validation.py`).
- **Dependency risks** — New dependencies that are unmaintained, have known CVEs, or pull in excessive transitive deps.

Rate each finding:
- **critical** — Exploitable vulnerability or guaranteed bug. Must fix before merge.
- **warning** — Potential issue depending on context. Should fix or explicitly justify.
- **info** — Defense-in-depth suggestion or minor hardening opportunity.

## Step 7: Run tests

Run `make test` on the PR branch to verify all tests pass.

Report results:
- **Pass** — all tests green, with coverage summary if printed.
- **Fail** — list failing tests with their error messages. Note whether failures are related to the PR changes or pre-existing.

## Step 8: Restore original branch and present summary

Check out the original branch that was active before the review began.

Present the full review in this format:

```
## PR Review: #<number> — <title>
**Branch:** <head> → <base>

### Format & Lint
<results from Step 2>

### Type Check
<results from Step 3>

### Tests
<results from Step 7>

### Semantic Issues
<findings from Step 4, ordered by severity>

### Readability & Redundancy
<findings from Step 5>

### Bugs & Security
<findings from Step 6, ordered by severity>

### Verdict

**<APPROVE | REQUEST CHANGES | NEEDS DISCUSSION>**

<1-3 sentence summary of the overall state of the PR. Call out the most important finding if any.>
```

Verdict criteria:
- **APPROVE** — No critical or warning findings. All checks pass.
- **REQUEST CHANGES** — Any critical finding, or 3+ warnings.
- **NEEDS DISCUSSION** — Warnings that involve design decisions or tradeoffs the author should weigh in on.

After presenting the review, ask the user if they'd like to:
1. Fix the reported issues (offer to help with specific fixes).
2. Re-run the review after making changes.
3. Discuss any specific finding in more detail.
Loading