Developing a Julia package
SkillDev toolsUse when you write a Julia package
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the Developing a Julia package skill
What this skill tells your AI
The instructions your AI receives, as published by hashgraph-online/awesome-codex-plugins in plugins/AtelierArith/atelier-arith-julia-development-skills/skills/developing-julia-package/SKILL.md and read by ahel’s review.
Notes on developing Julia packages.
Assume the package is named MyPkg. Substitute your actual package name wherever MyPkg appears.
Use src/MyPkg.jl as the package entry point. Keep the module declaration, exports, and include list there; put substantial implementation in focused files under src/.
module MyPkg
export fit_model, FitResult, GaussianModel
include("models.jl")
include("fit.jl")
include("preprocess.jl")
end
Split files to improve readability, not to recreate Python-style class or submodule hierarchies. Prefer one public module unless there is a real user-facing namespace boundary.
Guidelines below.
Avoid excessive exports
- Do not
exporthelpers that are only used internally just so tests can reach them. Prefer importing explicitly in tests:
# test/runtests.jl
using Test
using MyPkg: <internal-only helper>
Test public behavior through the public API first. Import internals only when the helper has meaningful behavior that is hard to exercise through the public path:
using Test
using MyPkg
using MyPkg: initial_guess
@testset "fit_model" begin
result = fit_model(x, y; model = GaussianModel())
@test result isa FitResult
end
@testset "initial_guess" begin
@test initial_guess(x, y, GaussianModel()) isa NamedTuple
end
Julia-idiomatic style
Multiple dispatch
Prefer splitting behavior across methods instead of a large if/elseif chain on isa, unlike typical Python style.
# Do not write if else end
function f(x)
if x isa Integer
return 2x
else
return x
end
end
Instead, use multiple dispatch:
f(x) = x # generic implementation
f(x::Integer) = 2x # specialized implementation for x::Integer
For package APIs, make the dispatch object explicit and keep symbol options as a thin compatibility layer if needed:
abstract type AbstractModel end
struct GaussianModel <: AbstractModel
baseline::Bool
end
GaussianModel(; baseline = true) = GaussianModel(baseline)
fit_model(x, y; model::AbstractModel = GaussianModel()) =
fit_model(model, x, y)
function fit_model(model::GaussianModel, x, y)
guess = initial_guess(x, y, model)
# gaussian-specific implementation
end
Use a marker or configuration struct for the model choice, and use a separate result struct for fitted values. Do not mutate a model type into a mixed "algorithm plus fitted state" object unless that is clearly the public contract.
struct FitResult{P,T}
params::P
residuals::Vector{T}
converged::Bool
end
This keeps GaussianModel() as the method-selection/configuration value and FitResult as the returned fitted state.
Type annotations
- On public APIs, narrow signatures when it prevents misuse or clarifies the contract.
- Inside the package, avoid over-constraining types everywhere; leave room for the compiler and for generic code.
Type stability
- On hot paths, avoid return types that vary unpredictably across inputs (type instability hurts specialization).
- Confirm bottlenecks with profiling before micro-optimizing.
Code formatting (JuliaFormatter)
- Format package sources with JuliaFormatter.jl so layout and whitespace stay consistent across contributors and CI.
- Optionally commit a
.JuliaFormatter.tomlat the repository root (or rely on defaults) so everyone applies the same rules.
From the package root:
using JuliaFormatter
format(".") # formats src/, test/, etc. under the current directory
Run formatting before merging substantive edits; wire the same command into CI or pre-commit hooks if the team wants enforcement.
Performance and allocations
- Measure with
@benchmark/@btimefrom BenchmarkTools.jl rather than guessing. - Watch unnecessary array copies from slicing and broadcasting; when an in-place API is needed, expose it explicitly (separate function name or keyword argument) so callers opt in.
Errors and documentation
- Raise
ArgumentError,DomainError, or other appropriate exceptions; messages should tell the caller what to fix. - Give docstrings to exported/public functions—ordinary docstrings above definitions integrate cleanly with Documenter.jl; use
@docwhen you attach documentation programmatically.
Signals
- GitHub stars
- 1k
- Forks
- 278
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
developing-julia-package- Source
- github.com/hashgraph-online/awesome-codex-plugins