Skip to content
Back to skills

Gritql

ASecurity

Use gritql (grit) for AST-based multi-file code transformations. Use

  • 8 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added September 20, 2026
developmentpythonrustgojavakotlinbashnodeexpressgitapi

Works with

  • cli
  • api

Security analysis

A100/100

Scanned September 20, 2026

npx -y skills add tstapler/dotfiles --skill gritql --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Gritql?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Gritql
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/tstapler-gritql/badge)](https://www.skillsdirectory.com/skills/tstapler-gritql)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: gritql
description: Use gritql (grit) for AST-based multi-file code transformations. Use
  when renaming methods/classes, migrating APIs, or modernizing patterns across a
  codebase. Always preview before applying. Pairs with ast-grep for search-then-transform
  workflows.
---

# gritql: AST-Based Code Transformation

Use `grit` for structural code rewrites. Unlike text-based find/replace, gritql understands code syntax and rewrites safely across all occurrences.

## When to Use

**Use gritql for:**
- Renaming methods, classes, variables across many files
- API migrations (library version upgrades)
- Pattern modernization (legacy → idiomatic code)
- Any change where "find all + replace" needs syntax awareness

**Don't use for:**
- Single-file edits → use `Edit` tool
- Non-code files (YAML, JSON, MD) → use `Edit` tool
- Simple text substitution → use `MultiEdit`
- Code *searching* → use `code-ast-grep` instead

## ⚠️ Kotlin Limitations (v0.1.1)

GritQL's Kotlin support is expression-level only. Know what works before attempting a transform.

### What works ✅
- Function call rewrites: `` `logger.error($msg)` => `logger.warn($msg)` ``
- Method chains: `` `$obj.old($$$args)` => `$obj.new($$$args)` ``
- Import replacements: `` `import old.Pkg` => `import new.Pkg` ``

### What fails ❌
- **`catch` blocks** — `catch (e: Exception) { $body }` → `code 200: Could not find variable` or 0 matches. Kotlin catch clauses are `catch_block` statement nodes in the tree-sitter grammar; GritQL backtick patterns only reach expression nodes.
- **Any statement-level pattern** — `if`, `for`, variable declarations, `try` blocks, `return` statements all fail similarly.
- **`where` clause with `contains`/`not contains`** — parses without error in v0.1.1 but consistently returns 0 matches. Use this as a confirmation guard only after verifying the base pattern matches first.

### No Kotlin stdlib patterns
The GritQL stdlib has patterns for Go, Java, JS, Python, Rust — but **no Kotlin**. Don't search `grit list` expecting Kotlin helpers.

### For Kotlin statement-level transforms
Use `ast-grep` with a YAML rule file, or use the `Edit` tool for targeted single-location changes:

```bash
# ast-grep can match catch blocks:
sg --pattern 'catch ($e: $T) { $$$body }' --lang kotlin kmp/src/

# YAML rule for structural rewrite (sg --rewrite)
```

## ⚠️ stdlib Init Fails (SSH auth error)

`grit init` uses libgit2 to clone `getgrit/stdlib` from GitHub. It ignores git `insteadOf` config and attempts SSH, which fails without an agent:

```
Error: Failed to fetch grit module getgrit/stdlib:
  authentication required but no callback set; class=Ssh (23)
```

### Workaround: symlink the bundled stdlib

The stdlib is bundled inside the npm package. Locate it and symlink it into your project's `.grit/` directory:

```bash
# Find the bundled stdlib (works on macOS + Linux)
GRIT_STDLIB=$(npm root -g)/@getgrit/cli/node_modules/.grit/.gritmodules

mkdir -p .grit
ln -sf "$GRIT_STDLIB" .grit/.gritmodules
```

Run from the project root. This makes `where` clause predicates and named patterns available without SSH.

## ⚠️ Critical: Go Package Prefix Migrations

When adding package prefixes to Go types (e.g., `FooType` → `pkg.FooType`), two things WILL go wrong without guards:

**1. Double-prefix** — GritQL visits sub-nodes of already-rewritten code. Fix with `not within`:

```grit
language go

// WRONG: causes detection.detection.FooType
`FooType` => `detection.FooType`

// CORRECT: use specific not within guard
`FooType` => `detection.FooType` where {
  $_ <: not within `detection.$_`
}
```

**2. Struct field types missed** — Go uses `type_identifier` AST node in struct fields; GritQL backtick patterns compile as `identifier` (different node type) and don't match. Use `gofmt -r` to cover these:

```bash
gofmt -r 'FooType -> detection.FooType' -w ./...
```

Then run `go build ./...` to catch any remaining occurrences.

## Installation

```bash
brew install gritql
```

Verify: `grit --version`

## Mandatory Workflow

### 1. Always Preview First

```bash
grit apply '<pattern>' --dry-run > /tmp/preview.diff
# Review before applying
```

### 2. Apply

```bash
grit apply '<pattern>'
```

### 3. Verify

```bash
# Run build + tests to confirm nothing broke
```

## Pattern Syntax

### Basic Rewrite

```
`old_expression($$$args)` => `new_expression($$$args)`
```

- `` `...` `` — backtick-quoted code pattern
- `$NAME` — matches one AST node
- `$$$NAME` — matches zero or more nodes (variadic/spread)

### Examples

**Rename a method call:**
```bash
grit apply '`$obj.oldMethod($$$args)` => `$obj.newMethod($$$args)`' --dry-run
```

**Update an import:**
```bash
grit apply '`import OldClass from "old-lib"` => `import NewClass from "new-lib"`' --dry-run
```

**Add a parameter to all calls:**
```bash
grit apply '`myFunc($$$args)` => `myFunc($$$args, { version: 2 })`' --dry-run
```

**Rename a class:**
```bash
grit apply '`class OldName` => `class NewName`' --dry-run
```

## Quick Reference

| Task | Pattern |
|------|---------|
| Rename method | `` `$o.old($$$a)` => `$o.new($$$a)` `` |
| Rename class | `` `class Old` => `class New` `` |
| Update import | `` `import old.Cls` => `import new.Cls` `` |
| Wrap expression | `` `unwrapped($$$a)` => `wrapped(unwrapped($$$a))` `` |

## Quality Gates

Before completing any gritql transformation:
- [ ] Dry-run reviewed and all changes are intentional
- [ ] Code formatted after apply
- [ ] Build passes (no compilation errors)
- [ ] Tests passing
- [ ] Git diff reviewed

## Search First, Then Transform

For large codebases, use `code-ast-grep` to understand scope before applying gritql:

```bash
# 1. Find all affected sites
sg --pattern '$obj.oldMethod($$$)' --lang java src/

# 2. Review count and locations
# 3. Apply gritql transform
grit apply '`$obj.oldMethod($$$args)` => `$obj.newMethod($$$args)`' --dry-run
```

## Go Gotchas Quick Reference

| Issue | Cause | Fix |
|-------|-------|-----|
| `detection.detection.FooType` | Pattern matches `FooType` inside already-prefixed `detection.FooType` | Add `where { $_ <: not within \`$_.$_\` }` |
| Struct field types not rewritten | Go uses `type_identifier` node for type positions; may not match backtick pattern | After GritQL, run `go build ./...` and fix with `Edit` |
| Missing `qualified_type` in type context | `pkg.Type` in type vs expression position uses different AST nodes | Use `not within` guards; supplement with manual edits |

## Advanced Patterns Reference

For annotation migration, API migration across versions, multi-step transformations, and Go-specific workarounds, see `reference.md`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…