Trunk VS Code Extension

Trunk is an extensible, fast, meta code checker and formatter with
extraordinary features like caching, preexisting issue detection, a daemon, a language server, and
githook management. It's managed completely via config-as-code, so you can easily pin your repo to
specific versions of your linters, formatters, and static analyzers.
Don't install a dozen different linter and formatting plugins, just use Trunk. Level up your code
quality and consistency today.
Trunk currently runs on OSX, Linux, and WSL2, with Windows support coming soon!

Get Started
Before using the Trunk VSCode extension you need to initialize trunk in your repo. The linters
enabled for your repo, their versions, and the version of trunk itself, are all stored in your
repo's .trunk/trunk.yaml
file.
Press the 'Initialize Trunk' button in the Trunk side panel, to get started

Or, you can initialize via the command line: Just install the Trunk CLI and
run trunk init
in your repo.
- Install Trunk →
curl https://get.trunk.io -fsSL | bash
(docs)
- Setup Trunk in your repo →
trunk init
(docs)
- See and fix issues as you code in VSCode → You're in the right place 👍
We integrate new linters every release. Stop by on slack and let us know
what you'd like next!
Official docs: here
Language |
Linters |
All |
codespell , cspell , gitleaks , git-diff-check |
Ansible |
ansible-lint |
Bash |
shellcheck , shfmt |
Bazel, Starlark |
buildifier |
C, C++, Protobuf |
clang-format , clang-tidy , include-what-you-use |
Cloudformation |
cfnlint |
CSS, SCSS |
stylelint |
Cue |
cue-fmt |
Docker |
hadolint |
Dotenv |
dotenv-linter |
GitHub |
actionlint |
Go |
gofmt , golangci-lint , semgrep , goimports |
HAML |
haml-lint |
Java |
semgrep |
JavaScript, TypeScript, YAML, JSON |
eslint , prettier , semgrep |
Kotlin |
detekt 1, detekt-explicit 1, detekt-gradle 1, ktlint |
Markdown |
markdownlint |
Protobuf |
buf-breaking , buf-lint |
Python |
autopep8 , bandit , black , flake8 , isort , mypy , pylint , semgrep , yapf |
Ruby |
brakeman , rubocop , rufo , semgrep , standardrb |
Rust |
clippy , rustfmt |
Scala |
scalafmt |
SQL |
sql-formatter , sqlfluff |
SVG |
svgo |
Terraform |
terraform (validate and fmt ), tflint 2 |
TOML |
taplo |
YAML |
prettier , semgrep , yamllint |
Support for Detekt is under active development; see its docs for more
details.
Module inspection, deep Checking, and setting variables are not currently supported.
How it works
Trunk downloads everything it needs to run on demand and caches it in ~/.cache/trunk
. We run
linters in parallel, in the background, and provide a
language server interface to show results
from VSCode via the Trunk VSCode Extension.
- Autoformat every file. Every file.
- Every file in your repo should have at least one tool checking its validity
- You should always get the same results locally as on CI
Features
Initialization
Trunk manages all configuration as code in your repo's .trunk/trunk.yaml
file. When you first
start trunk you'll get a button to initialize it. This scans your repo for which linters and
formatters are applicable to you and sets up an initial .trunk/trunk.yaml
file for you to use. See
the docs for more details.

Trunk Side Panel
On the side bar to the left you'll the Trunk icon, which you can use to open the side panel to view
issues. By default, issues are populated for every file you open as well as any modified files.

Trunk also shows Trunk Check Issues in a panel in the File Explorer, but you can hide it if you
wish:

Ever hit one of these problems?
- A formatter plugin doesn't actually install the formatter for you
- Devs on your team all get slightly different formatting results because you're running different
versions of the formatters as vscode plugins
- Your formatting doesn't match what your CI lint job is expecting because you're running a
different version of a formatter locally
- Your team mostly uses vscode with a committed workspace config w/ formatters, but some people
don't use it, leaving your codebase inconsistent
That's what formatting via Trunk solves. Everyone on your team only has to install one plugin,
they're guaranteed to get the same results and run the same version of each formatter/linter, and
guaranteed to get the same results as your CI lint job (use the
Trunk GitHub Action!).
Configuration
None required! But, if you have multiple VSCode plugins installed which act as formatters, you can
choose which filetypes to set Trunk as the default formatter for by right clicking and selecting
'Format Document With...'
Then 'Configure Default Formatter' and select 'Trunk'
Or, you can configure which formatter to prefer by editing your json settings (either user settings
or workspace settings) with:
"[markdown]": {
"editor.defaultFormatter": "trunk.io"
},
Issue code documentation links
For many linters we support links to their docs per-issue in the tooltips for each issue:

Ignoring Issues
Trunk supports a special syntax to ignore issues from any linter. See below for the format of
trunk-ignore
comments.

- Install Trunk CLI →
curl https://get.trunk.io -fsSL | bash
(docs)
- Locally check your changes for issues →
trunk check
(docs)
- Locally format your changes →
trunk fmt
(docs)
- Protect lint and format issues from leaking into main →
Trunk GitHub Action
Prereqs
None! Trunk manages linters and formatters for you via pinned versions in your repo's
.trunk/trunk.yaml
file. You don't need to install any linters or configure the extension in any
way. We cache linters, formatters, and runtimes in ~/.cache/trunk
. Using a linter distributed as a
go module but you're not a go user? Don't worry about it, we handle it all 😉.
How versioning works
After you trunk init
, trunk.yaml
will contain a pinned version of Trunk to use for your repo.
When you run trunk, it will automatically detect which version you should be running for a
particular repo and, if needed, download it, then run it. The trunk VSCode extension works the same
way: regardless of what repo you're in, the underlying version of trunk it runs is based on the
pinned version in your trunk.yaml
file. Config-as-code 👍.
This means that everyone working in a repo, using the trunk
cli, the VSCode extension, or when
running on CI, all get the same results because they're running the same version of trunk and the
same versions of all the linters/formatters. No more "doesn't happen on my machine". When you want
to upgrade to a newer version, just run trunk upgrade
and commit the updated trunk.yaml
.
Suppressing Issues
Sometimes we want to deliberately tell a linter that, yes, I know what I'm doing, and yes, in any
other situation I should not do this, but in this specific case it's fine. Maybe there's a
stand-in private key you're using for a test stack, or fixing the lint issue will actually make your
code less readable: whatever it is, you now need to figure out how to suppress a given lint issue.
trunk
provides a simple, standardized mechanism to do this, saving you from having to look up the
linter-specific syntax for doing so:
struct FooBar {
// trunk-ignore(clang-tidy/modernize-use-nullptr): this is a load-bearing NULL, see ISSUE-832
void *ptr = NULL;
};
This tells trunk
that the clang-tidy
linter found a modernize-use-nullptr
issue on the
highlighted line and that trunk
should suppress this linter issue.
Comments are obviously not required:
struct FooBar {
// trunk-ignore(clang-tidy/modernize-use-nullptr)
void *ptr = NULL;
};
You can also omit the name of the check to simply tell trunk
that all issues from a given linter
on a specific line should be suppressed:
struct FooBar {
// trunk-ignore(clang-tidy)
void *ptr = NULL;
};
trunk-ignore
directives can also be placed at the end of the line on which they're suppressing
lint issues:
struct FooBar {
void *ptr1 = NULL; // trunk-ignore(clang-tidy/modernize-use-nullptr)
void *ptr2 = NULL; // trunk-ignore(clang-tidy)
};
If you need to suppress issues from multiple linters, trunk-ignore
supports that too:
struct FooBar {
// trunk-ignore(clang-tidy): ISSUE-914 explains why the `void *` type is needed
// trunk-ignore(gitleaks,my-custom-linter/do-not-hardcode-passwords): see ISSUE-915
void *super_secret_password = (void *)("915dr~S$Pzqod~oR*CrQ$/SQ@hbtQBked:CL@z!y]");
};
Supressing all issues in a file:
// trunk-ignore-all(clang-tidy)
struct FooBar {
void *ptr1 = NULL;
void *ptr2 = NULL;
};
Supressing all issues in block of code:
struct FooBar {
// trunk-ignore-begin(clang-tidy)
void *ptr1 = NULL;
void *ptr2 = NULL;
// trunk-ignore-end(clang-tidy)
};
Notice that a trunk-ignore
directive applies not to the next line, but the next non-trunk-ignore
line (this only works for preceding directives, not trailing directives), and that you can use a
single directive for suppressing multiple checks.
Specification
The syntax of a trunk-ignore directive is as follows:
<trunk-ignore> ::= "trunk-ignore(" <check-ids> ")" <optional-comment>
<check-ids> ::= <check-id> <optional-check-id>
<optional-check-id> ::= "," <check-id>
<check-id> ::= <linter-id> <optional-rule-id>
<optional-rule-id> ::= "/" <rule-id>
<optional-comment> ::= ": " <comment>
Configuration
trunk.inlineDecorators: boolean
– allows to disable inline decorators for diagnostics.
trunk.inlineDecoratorsForAllExtensions: boolean
– allows to render inline decorators only for
diagnostics
trunk.showPreexistingIssues: boolean
- allows to show/hide pre-existing issues.
trunk.showBelowThresholdIssues: boolean
- allows to show/hide below-threshold issues
Advanced
trunk.autoInit: boolean
- sets whether to auto-initialize trunk
in non-trunk repositories
trunk.trunkPath: string
- absolute or workspace-relative path to Trunk
trunk.languageServerArguments: array
: - allows modifying the arguments to start the trunk LSP.
By default, this is just ["lsp-proxy"]
. It is unlikely this is needed, unless to submit a debug
report, in which case you might set it to be
["lsp-proxy", "--log-level=debug", "--log-file=/tmp/lsp-log.txt]
.
Multi-root workspace support
The trunk
extension supports
multi-root workspaces, although
it does not currently run trunk simultaneously in multiple repositories.
The default behavior for the extension is to run in the first listed trunk-initialized folder. If
none are trunk-initialized, the extension will initialize and run in the first git-initialized
folder.
This behavior can be overriden with the trunk.workspaceFolderName
setting, which will run the
trunk
extension in the workspace folder with the matching name.
Feature Requests & Bug Reports
Looking for another feature? Submit a request on Canny!
Hit a bug? 🐛 Let us know on Slack!
Feedback
Join the Trunk Community Slack. ❤️