topiary
Universal code formatter leveraging Tree-sitter queries. Use when formatting code in languages without dedicated formatters, writing custom .scm query files, or configuring Topiary via languages.ncl.
What this skill does
# Topiary
Topiary is a universal code formatter that uses Tree-sitter grammars and queries to define formatting rules. Rather than implementing language-specific formatting logic, Topiary uses declarative Tree-sitter query files (.scm) to specify how code should be formatted.
## When to Use This Skill
Activate this skill when:
- Formatting code in languages without dedicated formatters (JSON, TOML, Bash, Nickel, OCaml, OCamllex, CSS, OpenSCAD, SDML, WIT, or custom languages)
- Writing or debugging Tree-sitter query files (.scm)
- Configuring Topiary via languages.ncl for custom languages or indentation settings
- Setting up Topiary as part of a development workflow or CI/CD pipeline
- Learning Tree-sitter query syntax for code analysis
## Key Concepts
### Tree-Sitter Queries
Tree-sitter is a parser generator that creates language parsers from grammar definitions. Topiary uses Tree-sitter queries to analyze code structures and apply formatting rules. Queries match patterns in the syntax tree using S-expression syntax and decorate matched nodes with capture names (prefixed with `@`) that describe formatting actions.
### Query Files and Capture Names
Language formatting is defined in `.scm` (Scheme) query files. Each capture name instructs Topiary how to format the matched node:
- **Line breaks**: `@prepend_hardline`, `@append_hardline` (always insert newline), `@prepend_empty_softline`, `@append_empty_softline` (newline or nothing), `@prepend_spaced_softline`, `@append_spaced_softline` (newline or space)
- **Indentation**: `@prepend_indent_start`, `@append_indent_start`, `@prepend_indent_end`, `@append_indent_end` (mark indentation scopes)
- **Spacing**: `@prepend_space`, `@append_space` (add single space)
- **Control**: `@delete` (remove matched node), `@do_nothing` (suppress default behavior), `@leaf` (prevent formatting within node)
- **Input-aware**: `@prepend_input_softline`, `@append_input_softline` (preserve original line break presence)
### Idempotency
Topiary formatting is idempotent—running the formatter repeatedly on already-formatted code produces identical output. This guarantee allows safe integration into version control hooks and CI pipelines.
### Author Intent Preservation
Topiary respects the structural intent of code by preserving language-specific semantics. It focuses on whitespace, indentation, and line breaks rather than restructuring code. This approach works especially well with languages whose semantics are simple and whitespace-independent.
## Installation
### Via Mise
Add Topiary to your `mise.toml`:
```toml
[tools]
topiary = "latest"
[tasks]
fmt = "topiary fmt"
fmt:check = "topiary fmt --check"
```
### Via Cargo
Install directly from crates.io:
```bash
cargo install topiary-cli
```
### Verify Installation
Check the installed version and available languages:
```bash
topiary --version
topiary config show-sources
```
## CLI Usage
### Format Files
Format files in place by detected file extension:
```bash
topiary fmt src/main.ml
topiary fmt config.json
topiary fmt *.toml
```
Add `--check` to verify formatting without modifications:
```bash
topiary fmt --check src/
```
### Format Standard Input
Format piped input by specifying language and optional query file:
```bash
echo '{"name":"example"}' | topiary format --language json
cat script.sh | topiary format --language bash
```
### Visualize Parse Trees
Use `visualise` to debug queries by inspecting the syntax tree:
```bash
topiary visualise script.json
topiary visualise --language bash script.sh
```
This outputs the Tree-sitter parse tree, useful for understanding node structure when writing `.scm` queries.
### Query Configuration
Override the default query file for a language:
```bash
topiary fmt --language nickel --query custom.scm script.ncl
```
### Show Current Configuration
Display the active configuration including registered languages and indentation settings:
```bash
topiary config show-sources
```
## Configuration
### languages.ncl Format
Create a `.topiary/languages.ncl` file in your project root to customize language registration, indentation, and grammar sources. This file uses Nickel syntax:
```nickel
{
languages = {
json = {
extensions = ["json"],
indent = " ",
},
bash = {
extensions = ["sh", "bash"],
indent = " ",
}
}
}
```
### Configuration Search Order
Topiary searches for configuration in this order (first found wins):
1. `--configuration` CLI argument
2. `.topiary/languages.ncl` in current directory or parent directories
3. User configuration directory (OS-specific): `~/.config/topiary/languages.ncl` (Linux), `~/Library/Application Support/topiary/languages.ncl` (macOS), `%APPDATA%\topiary\languages.ncl` (Windows)
4. Built-in defaults compiled into Topiary
### Custom Grammar Sources
Register custom Tree-sitter grammars by specifying Git source or local path:
```nickel
{
languages = {
my-lang = {
extensions = ["ml"],
grammar.source.git = {
git = "https://github.com/example/tree-sitter-my-lang",
rev = "abc123def456"
}
}
}
}
```
Or reference a pre-compiled grammar on disk:
```nickel
{
languages = {
my-lang = {
extensions = ["ml"],
grammar.source.path = "./grammars/my-lang.so"
}
}
}
```
## Adding Custom Languages
Add formatting support for new languages by following these steps:
### Step 1: Register the Grammar
Create `.topiary/languages.ncl` in your project with the grammar source:
```nickel
{
languages = {
my-lang = {
extensions = ["ml"],
indent = " ",
grammar.source.git = {
git = "https://github.com/my-org/tree-sitter-my-lang",
rev = "main"
}
}
}
}
```
Verify the grammar source URL points to a valid Tree-sitter grammar repository.
### Step 2: Create Query File
Create `.topiary/queries/my-lang.scm` with formatting rules. Start minimal:
```scm
; Format binary operators with surrounding spaces
((binary_op) @op
(#match? @op "^(+|-|=)$"))
@prepend_space
@append_space
; Hard line after statements
((statement) @stmt)
@append_hardline
```
Use `topiary visualise` to inspect the parse tree and understand node names and structure.
### Step 3: Test Formatting
Test the formatter on sample files:
```bash
topiary fmt --language my-lang test-file.ml
topiary visualise --language my-lang test-file.ml
```
Iterate on the query file until formatting behaves as expected. Run `topiary fmt` on actual code to verify formatting is idempotent (run twice, should produce identical output).
## Writing Formatting Queries
### Query Syntax Overview
Tree-sitter queries use S-expression syntax. A basic query matches nodes and captures them:
```scm
; Match a function definition and capture its name
(function_def
name: (identifier) @func-name)
```
The `@func-name` is a capture; `function_def`, `name`, and `identifier` are node types. Field names like `name:` link to specific children.
### Common Capture Patterns
Format operators with spaces on both sides:
```scm
((binary_op operator: _ @op))
@prepend_space
@append_space
```
Indent function bodies:
```scm
(function_def
body: (block) @body)
@append_indent_start
@prepend_indent_end
```
Insert line breaks between statements:
```scm
((statement) @stmt)
@append_hardline
```
Preserve input line breaks (single line or multi-line lists):
```scm
(list
"[" @open
_ @item
"]" @close)
@append_spaced_softline
```
### Predicates and Matching
Use predicates to refine matches:
```scm
; Match only specific operators
((binary_op operator: _ @op)
(#match? @op "^(=|==|!=)$"))
@prepend_space
@append_space
; Match nodes that are NOT in comments
((statement) @stmt
(#not-eq? @stmt comment))
```
Available predicates: `#match?` (regex), `#eq?` (equality), `#not-eq?` (inequality).
## Supported Languages
### Official Languages
Topiary actively maintains formatting for:
- **Bash** - Shell scripting
- **JSON**Related in Writing & Docs
jax-development
IncludedUse this skill when the user is writing, debugging, profiling, refactoring, reviewing, benchmarking, parallelising, exporting, or explaining JAX code, or when they mention JAX, jax.numpy, jit, grad, value_and_grad, vmap, scan, lax, random keys, pytrees, jax.Array, sharding, Mesh, PartitionSpec, NamedSharding, pmap, shard_map, Pallas, XLA, StableHLO, checkify, profiler, or the JAX repo. It helps turn NumPy or PyTorch-style code into pure functional JAX, fix tracer/control-flow/shape/PRNG bugs, remove recompiles and host-device syncs, choose transforms and sharding strategies, inspect jaxpr/lowering/IR, and benchmark compiled code correctly.
nature-article-writer
IncludedDrafts, rewrites, diagnostically critiques, and style-calibrates primary research manuscripts for Nature and Nature Portfolio journals. Use when the user wants a Nature-style title, summary paragraph or abstract, introduction, results, discussion, methods, figure legends, presubmission enquiry, cover letter, reviewer response, or when a scientific draft sounds generic, jargon-heavy, structurally weak, or AI-ish and needs precise, broad-reader-friendly prose without inventing data, analyses, or references. Best for primary research articles and letters rather than reviews or press releases unless explicitly adapting one.
deckrd
IncludedDocument-driven framework that derives requirements, specifications, implementation plans, and executable tasks from goals through structured AI dialogue. Use when user says "write requirements", "create spec", "plan implementation", "derive tasks", "structure this feature", "break down into tasks", or "document this module". Also use for reverse engineering existing code into docs (/deckrd rev). Do NOT use for direct code writing — use /deckrd-coder after tasks are generated. Do NOT use when the user only wants to run or fix existing code without planning.
clinical-decision-support
IncludedGenerate professional clinical decision support (CDS) documents for pharmaceutical and clinical research settings, including patient cohort analyses (biomarker-stratified with outcomes) and treatment recommendation reports (evidence-based guidelines with decision algorithms). Supports GRADE evidence grading, statistical analysis (hazard ratios, survival curves, waterfall plots), biomarker integration, and regulatory compliance. Outputs publication-ready LaTeX/PDF format optimized for drug development, clinical research, and evidence synthesis.
handling-sf-data
IncludedSalesforce data operations with 130-point scoring. Use this skill to create, update, delete, bulk import/export, generate test data, and clean up org records using sf CLI and anonymous Apex. TRIGGER when: user creates test data, performs bulk import/export, uses sf data CLI commands, needs data factory patterns for Apex tests, or needs to seed/clean records in a Salesforce org. DO NOT TRIGGER when: SOQL query writing only (use querying-soql), Apex test execution (use running-apex-tests), or metadata deployment (use deploying-metadata).
accelint-ac-to-playwright
IncludedConvert and validate acceptance criteria for Playwright test automation. Use when user asks to (1) review/evaluate/check if AC are ready for automation, (2) assess if AC can be converted as-is, (3) validate AC quality for Playwright, (4) turn AC into tests, (5) generate tests from acceptance criteria, (6) convert .md bullets or .feature Gherkin files to Playwright specs, (7) create test automation from requirements. Handles both bullet-style markdown and Gherkin syntax with JSON test plan generation and validation.