Earn Code::Stats XP for the NetLogo code you type.
Code::Stats is a keystroke-counting "RPG for programmers": editor plugins send the number of edits you make, per language, and the site turns them into levels. NetLogo's editor has no plugin API, but a NetLogo extension runs inside NetLogo's own JVM — so this one hooks the Code tab's Swing document, counts your edits, and posts them to Code::Stats every 10 seconds, exactly as the official plugins do.
Works with NetLogo 7.0.x (extension API 7.0). Pure Java, no dependencies beyond NetLogo itself.
-
Get
codestats.jar: download it from the Releases page, or build it (sbt package, see below). -
Put it where NetLogo looks for extensions — either run
scripts/install.sh(macOS/Linux), or copy it by hand:OS Folder macOS ~/Library/Application Support/NetLogo/7.0/extensions/codestats/Windows %APPDATA%\NetLogo\7.0\extensions\codestats\Linux ~/.netlogo/7.0/extensions/codestats/(Or drop a
codestats/codestats.jarfolder next to a model — NetLogo checks the model's folder first.) -
Create a machine token at https://codestats.net/my/machines and save it in
~/.config/codestats/netlogo.properties(%USERPROFILE%\.config\codestats\netlogo.propertieson Windows):token = YOUR-TOKENcodestats.properties.examplelists the other settings. The token can also come from theCODESTATS_API_TOKENenvironment variable. It is never written into a model. -
Put
extensions [codestats]at the top of a model's Code tab. From the moment that model compiles, everything you type in any Code tab — including included.nlstabs and a popped-out code window — counts, for the rest of that NetLogo session, even in models that don't declare the extension.Prefer not to touch your models?
scripts/netlogo-with-codestats.sh [model.nlogox]starts NetLogo with tracking already running (it puts the jar on the classpath and calls NetLogo's normalmain).
Check that it works with models/CodeStats Dashboard.nlogox: type in its Code tab and watch the
XP this session monitor climb; status tells you whether a token was found and when the last pulse
was delivered. Messages also go to NetLogo's console/terminal, prefixed [codestats].
| Primitive | Reports / does |
|---|---|
codestats:xp |
XP counted since NetLogo started |
codestats:sent |
XP delivered to Code::Stats this session |
codestats:pending |
XP counted but not delivered yet (retried automatically) |
codestats:status |
one-line status string (never contains the token) |
codestats:flush |
send pending XP now; errors if it cannot be delivered |
codestats:reload-config |
re-read the properties file (e.g. after adding a token) |
codestats:level xp |
the level for that much XP, using the site's formula floor(0.025 · √xp) |
codestats:user-xp "name" |
total XP of a public profile (cached for a minute) |
codestats:user-language-xp "name" "NetLogo" |
XP of one language on a public profile |
The last two make network requests, so don't call them every tick (a monitor is fine: results are cached).
Every keystroke or paste in a Code tab is 1 XP — a typed character, an Enter (including the
auto-indent it triggers), a paste, a deletion — which is what the official editor plugins do (the
VS Code plugin counts one per change event). Deletions can be excluded with count_deletions = false.
Edits only count while the editor has keyboard focus and a key/menu event is being handled, so opening
a model (which rewrites the whole document) earns nothing, and neither does anything typed in the
Command Center or widget dialogs.
Pulses are sent every interval_seconds (default 10) with the local time and UTC offset, as
{"coded_at": "…", "xps": [{"language": "NetLogo", "xp": N}]}. Failed sends are retried with backoff,
and a final flush is attempted when NetLogo quits. Nothing but that JSON, your token header, and a
NetLogoCodeStats/<version> user agent ever leaves your machine.
Requirements: a JDK (11+; NetLogo 7 itself bundles 17) and sbt. The build
uses CCL's official netlogo-extension-plugin, which pulls NetLogo 7.0.4 from their Maven repository.
sbt test package # unit tests, then codestats.jar in the project root
scripts/smoke-headless.sh # loads the extension in NetLogo headless and checks the primitives
scripts/selftest-gui.sh # launches NetLogo, types into the Code tab, checks a pulse reaches a local mock server
scripts/selftest-gui.sh extension # same, but via `extensions [codestats]` in test-models/CodeStats Smoke.nlogox
sbt packageZip # zip for the NetLogo Extension Manager libraryThe GUI self-test needs NetLogo 7 installed (NETLOGO_HOME if it isn't in /Applications). It never
contacts codestats.net: CODESTATS_API_URL/-Dcodestats.url point the extension at the mock server, which
is also how you would test against a staging deployment.
IntelliJ: open the folder; with the Scala plugin installed, File ▸ New ▸ Project from Existing Sources ▸ build.sbt
gives you a fully configured project. Without it, add /Applications/NetLogo 7.0.4/app/* as a library to compile.
CodeStatsExtension.runOnce (called when a model declaring the extension compiles) starts Tracker,
a Swing timer that walks NetLogo's windows every 1.5 s looking for org.nlogo.editor.* text components
that live inside a CodeTab, and attaches a DocumentListener to each new Document it finds. That is
enough to survive model loads, .nls tabs opening, and the Code tab being popped out. Pulser
accumulates XP and posts it with java.net.http. The tracker matches NetLogo classes by name only, so
the extension does not depend on NetLogo's GUI classes at compile time.
- NetLogo 7.0.x only. The sources use nothing but
org.nlogo.api, so a NetLogo 6.x build should be a matter ofnetLogoVersion := "6.4.0"+ Scala 2.12 + plugin 6.0.1 inbuild.sbt, but that is untested. - NetLogo Web is a different codebase and cannot load JVM extensions.
- macOS "NetLogo Launcher" opens each model in its own process, so each needs the extension line (or use the launcher script).
MIT — see LICENSE.