# Julia-agent-tools: agent directives, ast-grep rules, and a ctags optlib for Julia

**URL:** <https://discourse.julialang.org/t/julia-agent-tools-agent-directives-ast-grep-rules-and-a-ctags-optlib-for-julia/142735>\
**Category:** Tooling\
**Tags:** lint, developer-tools, static-analysis, ai, llm\
**Created:** [November 3, 2026, 2:43pm UTC](https://discourse.julialang.org/t/julia-agent-tools-agent-directives-ast-grep-rules-and-a-ctags-optlib-for-julia/142735 "2026-11-03T14:43:59Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![durantschoon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/durantschoon/32/224940_2.png) [@durantschoon](https://discourse.julialang.org/u/durantschoon)\
**Post date:** [November 3, 2026, 2:44pm UTC](https://discourse.julialang.org/t/julia-agent-tools-agent-directives-ast-grep-rules-and-a-ctags-optlib-for-julia/142735/1 "2026-11-03T14:44:00Z")

</div>

Out of the box, coding agents (Claude Code, Codex, Cursor, Antigravity)  
routinely fall into Julia-specific traps: measuring `@allocated` at top level  
(where it measures global variable boxing instead of the function), defining  
overlapping parametric methods that fail precompilation, or leaving struct  
fields untyped or abstractly typed.

I’ve packaged the directives, structural linters, and developer tooling I use  
to prevent those pitfalls into one repo:  
[GitHub - durantschoon/julia-agent-tools · GitHub](https://github.com/durantschoon/julia-agent-tools) (MIT).

The primary workflow is installing the directives into your Julia project  
(`./bin/julia-agent-tools install-directives /path/to/repo`), which gives your  
agent both the rules and the local gates to check its own edits:

- **Agent directives (`directives/`):** Drop-in `CLAUDE.md`, `AGENTS.md`,  
`.cursorrules`, and `.agents/rules/` configurations encoding type stability,  
zero-allocation hot paths, precompilation hygiene, and how to navigate and  
test a Julia repo. `docs/lessons.md` documents the twelve real-world Julia  
failure modes behind the rules.
- **ast-grep support for Julia (`rules/`):** A tree-sitter build plus a  
catalogue of structural search and linting rules that catch anti-patterns  
(untyped/abstract struct fields, top-level `@allocated`, overlapping  
supertype methods, unchecked type parameters) in milliseconds.
- **`JuliaAgentTools.jl` & CLI:** Wraps the same checks for the REPL, CI, or  
agent verification loops (`audit_allocations`, `is_type_stable`, AST  
scanning, tag generation).
- **Universal Ctags optlib (`ctags.d/julia.ctags`):** Token-free symbol  
navigation for abstract types, structs (mutable and immutable as separate  
kinds), methods, macros, modules, and type aliases (`make install-ctags`).
- **Works with [graphify](https://github.com/Graphify-Labs/graphify):** Pairs  
with graphify (which builds AST knowledge graphs from the same upstream  
`tree-sitter-julia` grammar this repo vendors) so agents query call graphs  
and type hierarchies instead of blind grepping.

All of the structural search, linting, ctags, and audit tools work standalone  
from the CLI, editor, or REPL without an LLM in the loop—for example,  
`./bin/julia-agent-tools run -k where_expression src/` lists every parametric  
method in a tree.

**What changed for me, measured rather than felt:** I gave a headless agent  
the same ten small tasks (a new struct, a hot loop, a parametric type, an  
allocation test, a threaded sum, …) on a bare copy of a package of mine  
and on a copy with the directives installed, each task from a clean  
checkout, scored by these rules and the package’s own tests, three times over.  
Bare: 3, 2 and 1 of 10 tasks introduced a flagged mistake, every one of  
them `@allocated` at top level in a test, copied from the package’s own  
house style, plus one test suite the bare agent broke. Tooled: 1, 0 and 0  
of 10; the one slip was a parametric struct without an inner constructor,  
which the new rule caught, and no broken suites. Three runs is a  
direction with a range, not a precise number; the tasks, scores and  
script are in `docs/ab-measurement.md` so you can run it on your own  
package. The adversarial testing of the rules themselves is in  
`docs/ADVERSARIAL_TESTING.md`.

**What it does not do:** It is not a formatter, not a replacement for  
JET.jl or Aqua.jl (the audits are coarser and faster, meant as a ~10ms gate an  
agent runs on every edit), and the ast-grep rules cover common pitfalls rather  
than the whole language.

Install: install `ast-grep` via Cargo (`cargo install ast-grep --locked`), uv/pipx (`uv tool install ast-grep-cli`), npm (`npm i -g @ast-grep/cli`), Homebrew (`brew install ast-grep`), or your system package manager, then run `make dylib` and `make test-ast` in the repo. Linux and macOS are tested in CI.

If you try it, the most useful thing you can tell me is a Julia idiom the  
rules get wrong. Issues welcome; so are rule contributions—each rule is a  
small YAML file with its own test.

---

<div class="post-metadata">

**Author:** ![Palli](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/palli/32/3380_2.png) [@Palli](https://discourse.julialang.org/u/Palli)\
**Post date:** [November 3, 2026, 3:46pm UTC](https://discourse.julialang.org/t/julia-agent-tools-agent-directives-ast-grep-rules-and-a-ctags-optlib-for-julia/142735/2 "2026-11-03T15:46:44Z")

</div>

Welcome and thank you for your tools!

> [@durantschoon](#):
>
> leaving struct fields untyped

I didn’t notice such a problem at least in my experience with DeepSeek v4.1 which has been extremely good. Maybe this depends on the harness, I use it with opencode (or I use OhMyPy), since it’s still free until token run out, regularly. I always look forward to the next reset since the other model I use that’s always free is inferior…
