# \[ANN\] CodeComplexity.jl – Cyclomatic complexity for Julia

**URL:** <https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549>\
**Category:** Package Announcements\
**Tags:** package\
**Created:** [February 10, 2026, 4:08am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549 "2026-02-10T04:08:17Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![charleskawczynski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charleskawczynski/32/13783_2.png) [@charleskawczynski](https://discourse.julialang.org/u/charleskawczynski)\
**Post date:** [February 10, 2026, 4:08am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/1 "2026-02-10T04:08:18Z")

</div>

**[ANN] CodeComplexity.jl – Cyclomatic complexity for Julia**

I’ve released **CodeComplexity.jl** , a small package to measure **cyclomatic complexity** of Julia code. It helps find overly complex functions, set complexity limits in tests or CI, and scan files, directories, or whole packages.

**What it does**

- **Per-function complexity** – Counts decision points (if/elseif, for/while, try/catch, short-circuit `&&`/`||`, ternary, `@goto`) plus one.

- **Scopes** – Single expression, code string, file, directory (recursive), or package (by name or loaded module).

- **CI-friendly** – `check_complexity(pkg; max_complexity=10)` throws if any function exceeds the limit, so you can fail tests or CI when complexity gets too high.

- **Pairs well with LLMs** – When using AI coding assistants, complexity metrics give you a concrete threshold to enforce: reject or refactor generated code that exceeds your limit, and use per-function reports to prompt “simplify this” where it matters.

**Quick start**

```julia

using Pkg; Pkg.add("CodeComplexity")

using CodeComplexity

# Per-function report from a file

fc = file_complexity("src/MyModule.jl")

# Scan a package and enforce a limit (e.g. in tests)

using MyPackage

check_complexity(MyPackage; max_complexity=10)

```

**Links**

- **Repo:** [GitHub - charleskawczynski/CodeComplexity.jl: A package for estimating code complexity in Julia](https://github.com/charleskawczynski/CodeComplexity.jl)

- **Install:** `Pkg.add("CodeComplexity")`

- **Compatibility:** Julia 1.6+, no required dependencies; test suite uses Aqua.jl.

If you care about keeping functions understandable and testable, or want a single check to gate complexity in CI, CodeComplexity.jl is there. Feedback and contributions welcome.

---

<div class="post-metadata">

**Author:** ![tecosaur](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tecosaur/32/23206_2.png) [@tecosaur](https://discourse.julialang.org/u/tecosaur)\
**Post date:** [February 10, 2026, 8:35am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/2 "2026-02-10T08:35:29Z")

</div>

Nice! A quick question, have you considered using JuliaSyntax.jl over `Meta.parseall`?

---

<div class="post-metadata">

**Author:** ![charleskawczynski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charleskawczynski/32/13783_2.png) [@charleskawczynski](https://discourse.julialang.org/u/charleskawczynski)\
**Post date:** [February 10, 2026, 11:10pm UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/3 "2026-02-10T23:10:52Z")

</div>

Yeah, that’d probably be better. Honestly, I had looked at the implementation in [complex-structure (C901) | Ruff](https://docs.astral.sh/ruff/rules/complex-structure/) ([source](https://github.com/astral-sh/ruff/blob/main/crates%2Fruff_linter%2Fsrc%2Frules%2Fmccabe%2Frules%2Ffunction_is_too_complex.rs#L50)), and just asked Opus 4.6 to do this. It was able to one-shot a solution, but took an extra iteration to process Julia Base–and there are some pretty complex functions in there!

```julia-auto
CodeComplexity.directory_complexity("../julia/base"; max_complexity=100)
2-element Vector{FileComplexity}:
 FileComplexity("../julia/base/precompilation.jl", FunctionComplexity[FunctionComplexity("_precompilepkgs", complexity=176 (line 578))], 176)
 FileComplexity("../julia/base/show.jl", FunctionComplexity[FunctionComplexity("show_unquoted", complexity=272 (line 1916))], 272)

```

I’m too busy to sink much time into this, but I might be able to ask Opus to see if there’s refactoring opportunity with JuliaSyntax. If you don’t see something in the next month, feel free to open a PR!

---

<div class="post-metadata">

**Author:** ![charleskawczynski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/charleskawczynski/32/13783_2.png) [@charleskawczynski](https://discourse.julialang.org/u/charleskawczynski)\
**Post date:** [February 10, 2026, 11:21pm UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/4 "2026-02-10T23:21:57Z")

</div>

That was easy, [commit](https://github.com/charleskawczynski/CodeComplexity.jl/commit/26df93302cef81662911e631a4fc94aaaf6f91a4)

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [July 18, 2026, 9:20am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/5 "2026-07-18T09:20:38Z")

</div>

Wondering if people have used this against against Agent (e.g. Claude) generated code. Any experiences to share? Setup tips?

---

<div class="post-metadata">

**Author:** ![dwannetts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dwannetts/32/219012_2.png) [@dwannetts](https://discourse.julialang.org/u/dwannetts)\
**Post date:** [July 19, 2026, 12:23am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/6 "2026-07-19T00:23:24Z")

</div>

Yes.  
If I tell the agent to prioritise simplicity & clarity during the refactor, then it does so.  
Typically, I run CodeComplexity over the refactored code base every few days to check that things haven’t grown out of hand, and so far, they haven’t.  
D.

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [July 20, 2026, 8:08am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/7 "2026-07-20T08:08:53Z")

</div>

Do you have a public Github repo with this setup ?

---

<div class="post-metadata">

**Author:** ![dwannetts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dwannetts/32/219012_2.png) [@dwannetts](https://discourse.julialang.org/u/dwannetts)\
**Post date:** [July 20, 2026, 10:41am UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/8 "2026-07-20T10:41:11Z")

</div>

I do not.

The key function is

```julia
 # Julia complexity
 function complexity_df(filenames::Vector{String})
 rows = []
 for fname in filenames
 fc = file_complexity(fname)
 
 # Total row
push!(rows, (filename=fname, function_name="TOTAL", complexity=fc.total_complexity))
 
 # Function rows
 for func in fc.functions
 push!(rows, (filename=fname, function_name=func.name, complexity=func.complexity))
 end
 end
 
 DataFrame(rows)
 end

```

then

```julia
# Directories to scan in order
dirs = [
"src",
"src/common",
"src/models"
]

# Accumulators
df_base = DataFrame()
df_totl = DataFrame()

for dir in dirs
if !isdir(dir)
@warn "Directory not found, skipping: $dir"
continue
end

jfiles = filter(endswith(".jl"), readdir(dir, join=true))

if isempty(jfiles)
@warn "No .jl files found in: $dir"
continue
end

println("Processing directory: $dir ($(length(jfiles)) files)")

for jfile in jfiles
println(" → ", jfile)
try
jtemp = complexity_df([jfile])

# Add source tracking columns
jtemp.source_file = fill(jfile, nrow(jtemp))
jtemp.source_dir = fill(dir, nrow(jtemp))

# Split into base and totals
base = jtemp[jtemp.function_name .!= "TOTAL", :]
totl = jtemp[jtemp.function_name .== "TOTAL", :]

# Append to accumulators
df_base = isempty(df_base) ? base : vcat(df_base, base)
df_totl = isempty(df_totl) ? totl : vcat(df_totl, totl)

catch e
@warn "Failed on $jfile" exception=e
end
end
end

# Sort base results by complexity descending
df_base_sorted = sort(df_base, :complexity, rev=true)
df_totl_sorted = sort(df_totl, :complexity, rev=true)

println("\n── Summary ──────────────────────────────")
println("Total functions analysed : ", nrow(df_base_sorted))
println("Total files analysed : ", nrow(df_totl_sorted))
# println("\nTop 10 most complex functions:")
# println(first(df_base_sorted[:, [:source_file, :function_name, :complexity]], 10))

```

Was that what you were after?

---

<div class="post-metadata">

**Author:** ![e3c6](https://avatars.discourse-cdn.com/v4/letter/e/e79b87/32.png) [@e3c6](https://discourse.julialang.org/u/e3c6)\
**Post date:** [July 21, 2026, 8:41pm UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/9 "2026-07-21T20:41:07Z")

</div>

Do you have this on CI ?

> [@dwannetts](#):
>
> Was that what you were after?

I just wanted to see an end-to-end example of how this is integrated in the agent loop.

---

<div class="post-metadata">

**Author:** ![dwannetts](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dwannetts/32/219012_2.png) [@dwannetts](https://discourse.julialang.org/u/dwannetts)\
**Post date:** [July 21, 2026, 11:01pm UTC](https://discourse.julialang.org/t/ann-codecomplexity-jl-cyclomatic-complexity-for-julia/135549/10 "2026-07-21T23:01:03Z")

</div>

Not on CI I’m afraid. Good idea though, so maybe in the future.
