Zeek Workshop CERN 2026 | Geneva | March 25–26 Register Now

Whether you’re extending Zeek’s functionality or integrating it into a larger NDR stack, your work probably involves some form of source code. While that code is ultimately a means to an end, I like code to be neat: fit for the task, to the point, understandable, and maintainable.

I want my tools to meet the same standard. Good tools produce good code, so over the last 20+ years I’ve personalized my editor to give me exactly the experience I’m after. However, when I first opened a Zeek script I was greeted with an out-of-the-box experience like this:

A very old school editor experience

My editor’s default experience was pretty bare-bones and not like what I knew from other languages:

  • No syntax highlighting to guide my eye (can you spot which parts are commented out?)
  • No alerts when I introduced errors
  • Manual code formatting
  • Getting context required grepping around in share/zeek/base/, which felt disruptive

This post covers syntax highlighting plugins, code formatters, linters, and language servers that work across editors – whether you’re using Neovim like me, VS Code, Emacs, Vim, or Sublime. If you want to skip straight to setting up VS Code, jump right to the last section.

Syntax highlighting

The first thing I looked for was syntax highlighting to improve my code reading experience. The Zeek Project maintains syntax highlighting plugins for Emacs, Vim and Sublime1 which provide basic highlighting. All these plugins use a regex-based approach to syntax highlighting which means they capture little to no semantic information (a is a const vs a is a function argument), but I find the experience still much better than working with unhighlighted code.

Syntax highlight in Vim

Since much of my work deals with Spicy code I wrote a Vim syntax highlighter for Spicy code as well.

For Visual Studio Code there was an existing, but unmaintained syntax highlighter for Zeek so I created a maintained Zeek integration which even provides semantic information. I also published a regexp-based syntax highlighter for Spicy.

1 GitHub also relies on Sublime grammars for syntax highlighting when displaying code and the same grammar powers their highlighting of Zeek code.

Source code formatting

With my code reading experience under control the next thing on my mind was automated code formatting. I care about this since

  • when writing code I get less distracted by making code look pretty, and
  • it removes a big part of personal preferences from shared code so that code reviews can concentrate on changes to business logic, and no matter who the author is, code looks familiar.

The Zeek project publishes a formatter for Zeek code2, and I also created a formatter for Spicy. Both tools are installable with Python pip/pipx:

$ pipx install zeekscript
  installed package zeekscript 1.3.2, installed using Python 3.14.0
  These apps are now globally available
    - zeek-format
    - zeek-script
done! ✨ 🌟 ✨

$ pipx install git+https://github.com/bbannier/spicy-format
  installed package spicy-format 0.27.2, installed using Python 3.14.0
  These apps are now globally available
    - spicy-format
done! ✨ 🌟 ✨

 

Both zeek-format and spicy-format are opinionated about formatting, so they provide no knobs for tuning. Both my Vim plugin for Spicy3 as well as my Visual Studio Code extensions integrate with these formatters.

While these formatters allow anyone using them to produce well-formatted code, they can only do their work if they are actually used, but forgetting (or refusing) to use them can still introduce inconsistently formatted code into a shared code base. One way to deal with that is running formatters in CI as well. In the Zeek project we use pre-commit to solve our linting needs. pre-commit manages a set of Git hooks which are run locally when e.g., committing changes, but can also be run in CI. Both zeek-format and spicy-format can integrate with pre-commit by adding them to .pre-commit-config.yaml.

repos:

- repo: https://github.com/zeek/zeekscript
  rev: 'v1.3.2'
  hooks:
  - id: zeek-format

- repo: https://github.com/bbannier/spicy-format
  rev: '0.27.2'
  hooks:
  - id: spicy-format

 

With that any change to a `*.zeek` or `*.spicy` file in the repository will reject unformatted code, and automatically reformat it. To run all configured pre-commit hooks in CI with GitHub actions we use a workflow like this:

name: pre-commit

on:
  pull_request:
  push:
    branches: [master]

jobs:
  pre-commit:
    runs-on: ubuntu-24.04
    steps:
    - uses: actions/checkout@v6
    - uses: actions/setup-python@v6
    - uses: pre-commit/action@v3.0.1

 

If code is not formatted this will provide a diff which the commit author could apply by hand.

2 While zeek-format often works well enough, it has a number of open issues and help would be much welcome. This is a pure Python project.

3 spicy.vim will make a fix action available to ALE when spicy-format is found in PATH, and a buffer can be formatted with :ALEFix.

Linting

In addition to formatting source code we also want to ensure that code passes tests and is free of errors. One way to ensure that is running Zeek package tests in CI, and the Zeek project publishes the zeek/action-zkg-install action which does just that for GitHub actions.

For immediate feedback while editing Vim’s ALE plugin comes with builtin support for syntax checking Zeek code, and spicy.vim will register a Spicy syntax checker with ALE if it is detected.

Linting for style issues requires defining potentially side-specific rules and then performing semantic code analysis. I have published sample integrations for ast-grep for both Zeek and Spicy which you can extend for your specific needs. If you have developed a rule which might be more generally applicable and which you would like to contribute, please feel free to open PRs against these repositories.

IDE-like experience for working with Zeek code

The previous sections have shown how to address some common tasks one might come across when editing source code. Much of that involved editor-specific setup, so you might be out of luck if your editor does not have one plugin for a particular task; at the same time this situation also is challenging for plugin editors since the same functionality needs to be implemented again and again for the next editor so it ultimately does not scale. The Language Server Protocol (LSP) addresses this by defining a protocol which both editors and tools can implement so functionality like highlighting, formatting or checks can be implemented once and shared across different editors. It also defines interfaces for common IDE features like auto complete, go to definition, hover, or snippets.

The Visual Studio code extensions for Zeek and Spicy I mentioned above in fact are both language servers for Zeek and Spicy, respectively. This means that they can be used with any editor which understands the LSP, e.g., there exist a number plugins for Emacs or Vim4. With that even users of e.g., Visual Studio Code can have as a good a Zeek script editing IDE experience as I have in my customized Neovim 😜 with proper go to definition, completion, hover and more.

Devcontainers take the integrated nature of an IDE one step further by shipping a full development environment (editor, extensions, platform dependencies). I have created a devcontainer for developing Zeek and Spicy code which allows developing even on user systems without a Zeek installation, e.g., Windows machines, either by running the container locally or by running it in the cloud with GitHub Codespaces. I have used it with some success in trainings.

Zeek IDE running in the cloud

4 I personally use coc.nvim to integrate them into my Neovim setup.

Conclusion

Working with Zeek code doesn’t have to mean working without modern tooling. These tools bring syntax highlighting, automated formatting, linting, and IDE features to Zeek and Spicy development.

Most of these tools are implemented in Python, Rust, TypeScript, or editor-specific languages – which means they’re accessible to contributors who don’t work on Zeek’s C++ core. If you run into rough edges or have ideas for improvements, contributions are welcome.

What’s your experience working with Zeek scripts? Are these tools helpful, or is there something missing from your workflow? Please let us know in Slack or Discourse.

Author

  • Benjamin Bannier

    Benjamin Bannier works as a Senior Open Source Developer at Corelight where he spends most of his time maintaining and evolving Spicy and its integration into the Zeek ecosystem.

    View all posts

Discover more from Zeek

Subscribe now to keep reading and get access to the full archive.

Continue reading