NJ School Data
← Data library
Data explainer

NJ School Performance Reports

2024–25 reports · updated June 2026

New Jersey's annual "report card" for every public school and district: state test results, student growth, graduation, attendance, discipline, college-and-career readiness, and staffing. We use four of those measures on school and district profiles — and this page is the manual for how each one works and how we chart it.

1 · The source

The data comes from the New Jersey School Performance Reports. The browsable site is at nj.gov/education/spr; the underlying downloadable databases — one workbook of school-level data and one of district/state data per year — are linked from its download page and posted (under a slightly different path, sprreports/) back to 2011–12. We work from the 2024–25 release.

Each year's school workbook is a single large Excel file (about 330 MB) that packs roughly eighty report tabs — one per measure — keyed on the same county / district / school codes as the state's enrollment files, so it joins cleanly to everything else on this site.

2 · The four measures

The reports carry far more than this; these are the four we surface today.

MeasureWhat it answersWhere it appears
NJSLA test scoresHow students score on the state test, by level (1–5), grade, and yearTest scores module
Student growthHow much progress students made vs. peers who started at the same placeTest scores module (the lead)
Graduation rateShare of a class that finishes within four yearsGraduation module (high schools)
Chronic absenteeismShare of students who miss 10% or more of school daysChronic absenteeism module

3 · Test scores (NJSLA)

The New Jersey Student Learning Assessment (NJSLA) is given each spring in English language arts (grades 3–9) and math (grades 3–8, plus the high-school courses Algebra I, Geometry, and Algebra II). Every student's result falls into one of five performance levels:

LevelMeaning
1Did not yet meet expectations
2Partially met expectations
3Approached expectations
4Met expectations
5Exceeded expectations

"Met or exceeded expectations" — the headline proficiency number — is levels 4 and 5 combined. But a single proficiency percentage hides the shape: a school where most non-proficient students sit at level 3 (just short) is in a very different place from one where they sit at level 1. So we show the full 1–5 distribution.

The chart: a flat proficiency line

Each small panel is a diverging area anchored to a flat horizontal line — the proficiency boundary. Levels 4–5 (proficient) fill the area above the line; levels 1–3 fill the area below. Light shading is level 1, dark is level 5.

Why the flat line matters: in an ordinary bottom-stacked chart, when students slip from level 4 down to level 3, level 3 swells and pushes the proficient bands upward — which looks like improvement even though it's decline. Anchoring to a flat line fixes that: a slip from 4 to 3 visibly shrinks the area above the line. Up is unambiguously better.

We label the proficient share at the first and last points, and you can hover any panel for the exact level-by-level breakdown.

Two ways to read it: by grade, and by class

Test scores are shown in two lenses, because they answer different questions:

By grade, year to year — one panel per grade, e.g. how have this school's third-graders done over the last four years? This mixes a different set of students each year (a new third-grade class annually) but tracks the grade itself.

Aggregate grade results, lined up across years — one panel per approximate class path along the diagonal of the grade-by-year grid. These are not linked student records: enrollment and the tested population can change between years, so the panel must not be read as the same students followed over time. Math paths cover grades 3–8 only, since the high-school course tests aren't a clean grade-by-grade sequence.

An honesty note: levels are per-grade, never averaged

We never compute a single school-wide 1–5 distribution by averaging across grades. New Jersey doesn't publish one, and synthesizing it is unsafe: a privacy-suppressed grade (see caveats) silently drops out of the average, and at high schools it would mix incomparable course populations (Algebra I vs. Algebra II). Each panel is one real, published per-grade result.

One consequence to keep in mind: a school's headline proficiency reflects only the grades it tests, while the district and state figures blend all grades 3–8 plus high school. So a high school's math can read below its district's overall rate — the district number is lifted by the higher-scoring elementary grades. That's real, not a glitch.

4 · Student growth

Proficiency tracks family income closely. Growth doesn't — which is why we lead with it.

The median Student Growth Percentile (SGP) measures how much a school's students progressed in a year compared with students statewide who scored the same the year before. It runs 1–99, where 50 is a typical year of growth; New Jersey labels the result Low, Typical, or High. A school can have modest proficiency but high growth (students gaining ground fast) or high proficiency but low growth (coasting) — so growth is the closest thing to a demographic-independent answer to "is this school doing well by its students?"

Growth is computed only for grades 4–8 (it needs a prior-year test to measure against). New Jersey does not report it for high schools, so high-school profiles fall back to leading with proficiency.

5 · Graduation

The graduation module shows the four-year graduation rate — the share of a class that earns a diploma within four years of entering ninth grade — over the most recent five years, against the statewide rate.

New Jersey publishes two versions: a State calculation and a Federal adjusted-cohort rate. Only the State rate is reported across all the trend years, so that's the line we plot; where the Federal rate is available (the latest year) the caption notes it, since the two use slightly different cohort rules and can differ by a few points. Because graduation rates cluster high (often 85–95%), this is the one chart where we zoom the vertical axis off zero so the movement is legible — and in a district with a single high school we drop the redundant district line.

6 · Chronic absenteeism

A student is chronically absent if they miss 10% or more of the days they're enrolled — roughly 18 days in a full school year, excused or not. It's a leading indicator of disengagement, and it rose sharply statewide after the pandemic. We plot the school's rate over time against the state, for all grade levels.

7 · Caveats that matter

Suppression and capping

To protect student privacy, the state withholds or caps small numbers. A figure can arrive as a sentence — "Fewer than 10 students…", "There is no data available…" — or as a privacy cap, <10% or >90%, instead of an exact value. We render these honestly: a capped grade shows "withheld" rather than a made-up number, and a capped figure never silently becomes a zero.

The COVID gap

The NJSLA was not given in spring 2020, and 2020–21 was disrupted. The current files' trend tabs therefore start at 2021–22, so the test-score and growth views run 2021–22 → 2024–25. Pre-pandemic results exist in older files but on a partly different test (PARCC), so we don't splice across that break.

State vs. federal, and which number is "official"

For both proficiency and graduation the state publishes more than one calculation. We headline the figure New Jersey itself features on the report card (so it matches what you'd find on the state site), and note the alternates in captions rather than quietly picking a different one.

8 · What we built

The tabs we use load into the same SQLite warehouse as the enrollment data, joined on the NJDOE county / district / school codes. Each is built straight from the published workbook — no modeling, no imputation.

TableFromHolds
grad_rateGraduation Rate Trends4- and 5-year rates (State + Federal), by entity, year, group
assessmentELA / Math Participation & Performanceschool-wide % met/exceeded, per subject & year
assessment_gradeELA / Math Performance by Testper grade-test Level 1–5 distribution + mean scaled score
growthStudent Growth Trendsmedian SGP (ELA + Math) with the Low/Typical/High label
absenteeismChronic Absenteeism Trends% chronically absent, by entity & year

Source data: New Jersey Department of Education, School Performance Reports, downloadable databases (nj.gov/education/spr/download), 2024–25 release.

The issue registry

Every dataset behind this site keeps a structured registry of its known issues — the format breaks, suppression rules, entry errors, and definitional traps we hit while building on it — so that the next person (or agent) who works with this data doesn't rediscover them the hard way. Each issue has a stable id, a machine-readable scope (which years, columns, and tables it touches), and an effect: breaks stops a pipeline, corrupts silently wrongs the numbers, misleads invites a wrong reading of right numbers, context is background you must hold to use the data responsibly. Issues marked ★ are core: read them before any use of this data. The registry is maintained in the ergo format and served in machine-readable form alongside this page — links at the end of this section.

NJ Dept. of Education, Office of Performance Reports · 2015-16 → 2024-25 for graduation and chronic absenteeism, from all ten published editions; 2021-22 → 2024-25 for assessment and growth, which still read the current workbook's trend tabs only (see spr/trend-tabs-post-covid-only) · source confidence A · updated 2026-08-03 · 25 known issues (1 core)

The pitfall: NJ publishes two 4-yr graduation rates — State and Federal — but only State is populated across years (27,115 of 27,201 trend rows; Federal in just 5,423, effectively one year); plotting Federal as a trend, or comparing states on it, is the classic misread.

url-host-split [breaks · monitor] Files live under /education/sprreports/, not the /education/spr/ landing path

Type: availability — applies to the whole dataset

How to spot it: 404s when constructing file URLs from the landing-page path instead of the sprreports host

Full entry, with the story and the numbers, in the served ergo doc.

layout-types-lie [corrupts · monitor] Code columns typed 'Numeric' in the layout are zero-padded TEXT in the data

Type: format — applies to years: all · tables: grad_rate, assessment, assessment_grade, absenteeism, growth · columns: CountyCode, DistrictCode, SchoolCode

How to spot it: CountyCode='13', DistrictCode='4900' — string cells with leading zeros preserved, despite the layout workbook's dictionary calling them Numeric

The misread: Coercing codes to integers strips leading zeros and silently breaks the warehouse join.

Full entry, with the story and the numbers, in the served ergo doc.

schoolyear-typing-inconsistent [corrupts · monitor] SchoolYear is declared Numeric in some tabs' layout and Text in others, though the data is always the string "2020-21"

Type: format — applies to years: all · tables: grad_rate, assessment, assessment_grade, absenteeism, growth · columns: SchoolYear

How to spot it: layout workbook's Type column for SchoolYear varies by tab; every tab's actual SchoolYear cell reads as the hyphenated string, e.g. '2020-21'

The misread: Writing per-tab ingestion code that trusts each tab's declared SchoolYear type parses some tabs as numeric and others as text inconsistently; always treat SchoolYear as a string.

Full entry, with the story and the numbers, in the served ergo doc.

rate-prose-suppression [breaks · monitor] Rate cells carry % signs, prose suppression sentences, and >90%/<10% privacy caps

Type: suppression — applies to years: all · tables: grad_rate, assessment, assessment_grade, absenteeism · columns: *Rate*, *Percent*

How to spot it: value fails float() after stripping a trailing % — includes '>90%', '<10%', and prose sentences

The misread: Treating suppression NULLs as zero. Capped extremes also go NULL — fine for All Students (they only hit tiny subgroups), a real loss for small subgroups.

Full entry, with the story and the numbers, in the served ergo doc.

grad-state-vs-federal [misleads · monitor] State and Federal 4-yr graduation rates coexist; only State is populated across years

Type: measurement — applies to years: all · tables: grad_rate · columns: 4YrGraduationRate*, 5YrGraduationRate*

How to spot it: 4YrGraduationRateState_District non-empty in 27,115 of 27,201 trend rows; …Federal_District in only 5,423 (≈ one year)

The misread: Drawing the Federal rate as a trend line (it has one point), or comparing a State figure against another state's federal ACGR — NJ's State calc runs higher (SOMSD 2024-25: State 93.2% vs Federal 89.4%).

Full entry, with the story and the numbers, in the served ergo doc.

monolithic-workbook-size [breaks · monitor] The school-level workbook is ~330 MB with ~80 tabs — a full non-streaming load is impractical

Type: format — applies to the whole dataset

How to spot it: Database_SchoolDetail.xlsx is 346,029,712 bytes (330 MB); Database_DistrictStateDetail.xlsx is 119,164,900 bytes (114 MB)

Full entry, with the story and the numbers, in the served ergo doc.

new-format-2024-25-xlsx-only [context · open] From 2024-25 on, NJDOE drops the zip, Access, and Reference Guide PDF variants

Type: availability — applies to years: 2024-25 →

How to spot it: download.js sets isNewYearFormat = year >= '2024-2025'; for those years only Database_*.xlsx is linked

The misread: Expecting a Reference Guide PDF, zip, or Access variant for 2024-25 and later — from 2024-25 on NJDOE publishes .xlsx only.

Full entry, with the story and the numbers, in the served ergo doc.

legacy-archive-link-is-dead [breaks · resolved] The legacy-years archive link is dead, and the live location is elsewhere

Type: availability — applies to years: 2011-12 → 2014-15

How to spot it: https://nj.gov/education/schoolperformance/archive/ returns 404, as do every year path beneath it and a PDF still indexed there; https://www.nj.gov/education/schoolperformance/ itself returns 200

The misread: Sending a reader to nj.gov/education/schoolperformance/archive/ for 2011-12 through 2014-15, which 404s, and concluding the material is gone.

Full entry, with the story and the numbers, in the served ergo doc.

cohort-profile-text-suppression-tell [breaks · open] NonContinuing/Persisting columns on GraduationCohortProfile are typed Text while their siblings are Numeric

Type: suppression — applies to years: all · tables: GraduationCohortProfile · columns: NonContinuing_District, Persisting_District

How to spot it: NonContinuing_District and Persisting_District are typed Text in the layout workbook; every other GraduationCohortProfile metric column is Numeric

Full entry, with the story and the numbers, in the served ergo doc.

trend-tabs-post-covid-only [context · open] The 2024-25 file's trend tabs start at 2020-21 or 2021-22, not earlier

Type: coverage — applies to years: 2024-25 file only shows 2020-21→2024-25 (grad) / 2021-22→2024-25 (assessment, absenteeism, growth) · tables: grad_rate, assessment, assessment_grade, absenteeism, growth

How to spot it: GraduationRateTrends carries 2020-21…2024-25 (five years); ELA/MathParticipationPerformance, PerformanceByTest, and StudentGrowthTrends carry 2021-22…2024-25 (four years) in the 2024-25 file

The misread: Assuming the current file's trend tabs cover full history — pre-COVID NJSLA (2018-19 and earlier, with the no-spring-2020 testing gap) requires pulling older years' files separately; deferred in this builder.

Full entry, with the story and the numbers, in the served ergo doc.

the-nine-earlier-editions-are-the-same-measure [context · mitigated] Older editions republish the same figures, and the overlap is the proof

Type: measurement — applies to tables: absence_history, grad_rate_history

How to spot it: the 2024-25 trend tab and each earlier year's own edition agree on 11,952 of 11,953 shared chronic-absence rows, and on 6,620 of 6,620 shared graduation rows

The misread: Splicing two publisher tabs into one line because they carry the same column name, without checking that they carry the same number where they meet.

Instead: Keep the overlap check in the adapter. A tab that stops agreeing is a different measure and must break the line rather than extend it.

Full entry, with the story and the numbers, in the served ergo doc.

edition-census-is-source-shaped-not-conformed [context · mitigated] The edition census preserves publisher columns and asserts no metric identity

Type: measurement — applies to tables: absence_history, grad_rate_history, absence_edition, grad_rate_edition, absenteeism_trend_edition

How to spot it: the artifact's own metadata: 'This layer asserts no cross-edition metric identity; mapping an edition's columns onto another edition's metrics is a conformance decision.'

The misread: Reading the census as though it were already conformed, and joining columns across editions because they sound alike.

Instead: Project it through the consumer's edition layer, which names the shape of every edition and refuses one it does not recognise.

Full entry, with the story and the numbers, in the served ergo doc.

the-trend-tab-is-two-editions-old [context · mitigated] Only the last two editions publish a chronic-absenteeism trend tab at all

Type: coverage — applies to tables: absenteeism, absenteeism_trend_edition

How to spot it: the census marks chronic-absenteeism-trends not-collected-this-edition in 15 of 20 edition/grain cells; the tab first appears in 2023-24

The misread: Concluding that New Jersey has only measured chronic absenteeism since 2021-22, when it is the trend *tab* that is new. The longer record is in each edition's own student-group snapshot.

Instead: Read the register in absenteeism_trend_edition, and take the earlier years from absence_history.

Full entry, with the story and the numbers, in the served ergo doc.

chronic-absenteeism-was-waived-in-2019-20 [corrupts · mitigated] New Jersey collected no chronic absenteeism for 2019-20, by waiver

Type: coverage — applies to years: 2019-20 · tables: absence_history

How to spot it: the census marks 2019-2020 not-collected-this-edition at both grains; the edition ships no ChronicAbsenteeism sheet of any kind

The misread: Drawing a line straight through 2019-20, or reading a blank or a zero as a year in which nobody missed school.

Instead: Render the year as a labelled band carrying NJDOE's own words: 'The requirement to report on chronic absenteeism and related accountability measures for the 2019-2020 school year was waived. As a result, NJDOE will not report on chronic absenteeism and other attendance data for 2019-2020. Tables showing attendance data will be hidden in the 2019-2020 reports.' — 'Important 2019-2020 Notes' sheet, Database_DistrictStateDetail.xlsx, retrieved 2026-07-31.

Full entry, with the story and the numbers, in the served ergo doc.

pandemic-editions-carry-per-element-publisher-cautions [misleads · mitigated] NJDOE cautions 2019-20 and 2020-21 element by element, not once

Type: measurement — applies to years: 2019-20, 2020-21 · tables: absence_history, grad_rate_history

How to spot it: the 'Important 2019-2020 Notes' and 'Important 2020-2021 Notes' sheets inside the workbooks carry a status and a note per data element; graduation and chronic absenteeism each get their own, and neither matches the discipline wording

The misread: Reusing the discipline caution ('Due to school closures in spring 2020, discipline data ... may not be comparable') for graduation or attendance. It is not what the publisher says about either, and for 2019-20 absenteeism there is nothing to caution because nothing was collected.

Instead: Quote the element's own note. Chronic absenteeism 2020-21: 'because the number of days students spent in in-person and remote learning environments during the school year differed, the NJDOE recommends caution in comparing 2020-2021 attendance data between schools and districts and to prior or future school years.' Graduation 2019-20 and 2020-21: the graduation assessment requirement was waived for the classes of 2020 and 2021, and annual targets were not reported. Both retrieved 2026-07-31 from the workbooks' notes sheets.

Full entry, with the story and the numbers, in the served ergo doc.

graduation-rate-type-is-recovered-from-the-statewide-column [corrupts · mitigated] Six editions lose GraduationRateType, and it is recovered rather than guessed

Type: measurement — applies to years: 2018-19, 2019-20, 2020-21, 2021-22, 2022-23, 2023-24 · tables: grad_rate_history

How to spot it: the 2018-19 to 2023-24 workbooks carry a GraduationRateType column ('4-Year Rate' / '5-Year Rate'); the AQ-090 census records it in dimension_columns_json but source_rows.dimension_label carries only CohortYear, so those editions arrive with two indistinguishable rows per cohort

The misread: Taking either row as the four-year rate, or dropping six editions and rendering the classes of 2019 and 2020 as a hole New Jersey never published.

Instead: Recover the rate type from StatewideGraduationRate, which the same publisher prints on the same row: a cohort's statewide four-year rate is the literal carried by the newest cohort in an edition, the only one there with a single row. Check it forwards against the conformed 2024-25 mart and backwards against the 2017-18 edition's unambiguous 4YR_Rate.

Full entry, with the story and the numbers, in the served ergo doc.

the-all-students-row-is-labelled-four-ways [corrupts · mitigated] Chronic absence labels its all-students row four ways across ten editions

Type: identity — applies to tables: absence_history

How to spot it: 2015-16 has no student-group dimension and its row is unlabelled; 2016-17 to 2023-24 use 'Schoolwide' / 'Districtwide'; 2024-25 uses 'All Students'

The misread: Filtering on 'All Students' and silently losing eight editions off the chart.

Instead: Enumerate the labels. They are publisher facts, not values to normalise away.

Full entry, with the story and the numbers, in the served ergo doc.

no-statewide-absence-rate-before-2021-22 [context · mitigated] Only the 2024-25 edition prints a statewide chronic-absence comparator

Type: coverage — applies to tables: absence_history

How to spot it: ChronicAbsenteeismRate_State exists in the 2024-25 edition only; earlier editions publish Target and MetTarget but no statewide rate, and no state entity row

The misread: Computing a statewide average from the district rows to fill the earlier years, and drawing it as though New Jersey had published it.

Instead: Let the state line start where the state started printing it, and say so in the caption.

Full entry, with the story and the numbers, in the served ergo doc.

two-2024-25-tabs-disagree-for-one-school [context · open] The 2024-25 student-group and trend tabs disagree for Bayonne Alternative High

Type: measurement — applies to years: 2024-25 · tables: absence_history

How to spot it: district 0220 school 010, 2024-25: ChronicAbsenteeismStudentGroup prints 90.0%, ChronicAbsenteeismTrends leaves the year blank. Both tabs agree on 87.4 for 2023-24. One row in 11,953.

The misread: Widening the overlap tolerance until this stops failing, which would also stop the check catching a real divergence.

Instead: Pin it by name in ABSENCE_KNOWN_TAB_DISAGREEMENTS. It is the publisher disagreeing with itself inside one workbook, and if it stops reproducing the pin is stale and must be re-read.

Full entry, with the story and the numbers, in the served ergo doc.

pre-2020-editions-join-on-an-unverified-code [misleads · mitigated] Before 2020-08-11 a resolving CDS code proves the code, not the school

Type: identity — applies to tables: absence_history, grad_rate_history

How to spot it: the release's identity_resolution table marks every edition before 2020-08-11 outside its evidence window, with the caveat that a code which resolves 'says the tuple is a current NJDOE organization, and says nothing about what that tuple named in this edition's school year'

The misread: Presenting a ten-year line as one school's history when its older end is matched only by a code New Jersey may have reused.

Instead: Say which points are outside the evidence window, on the page, beside the chart.

Full entry, with the story and the numbers, in the served ergo doc.

the-oldest-graduation-edition-rounds-to-whole-percent [context · mitigated] 2015-16 publishes graduation rates as bare whole numbers on a different sheet

Type: measurement — applies to years: 2012-13, 2013-14 · tables: grad_rate_history

How to spot it: the 2015-16 edition's ExtYearGradRate sheet prints '96', not '96.3'; every value it shares with a later edition is within 0.5 of that edition's one-decimal figure (806 shared school-cohort rows, max difference 0.5)

The misread: Reading a step between the 2013 and 2015 classes as a change in graduation when it is a change in rounding.

Instead: State the precision where it applies. It is the same measure at coarser precision, not a different one.

Full entry, with the story and the numbers, in the served ergo doc.

grade-aggregation-bias [misleads · monitor] Summing grade-test proficiency into a school-wide figure is biased by suppression and course-mix — a capped Algebra I once inflated one

Type: measurement — applies to years: all · tables: assessment_grade · columns: l1, l2, l3, l4, l5, proficiency, prof_str

How to spot it: a capped Algebra I test (values suppressed to '<10%'/'>90%') once inflated a home-grown school-wide aggregate by silently dropping its lowest cohort from the average

The misread: Aggregating assessment_grade's per-grade-test Level 1-5 distributions into a school-wide number instead of using NJ's own published school-wide MetExceededExpectations (table assessment) — suppression and incomparable course populations (Algebra I vs II) bias the result.

Full entry, with the story and the numbers, in the served ergo doc.

hs-no-sgp [context · open] StudentGrowthTrends has no rows for standalone high schools — SGP only exists for grades 4-8

Type: universe — applies to years: all · tables: growth · entities: standalone high schools

How to spot it: growth table has zero rows for a standalone high school's own school_code; district/state context columns are still populated

The misread: Reading an absent growth row for a high school as missing or bad data — SGP is defined only for grades 4-8 by NJ's own methodology; high schools need a proficiency-only frame with no cohort lens.

Full entry, with the story and the numbers, in the served ergo doc.

math-cohort-grades-3-8-only [context · open] The cohort-diagonal view (a class followed as it moves up) only works for grades 3-8 math

Type: coverage — applies to years: all · tables: assessment_grade · rows: grade_test rows for HS course tests (Algebra I/II, Geometry, etc.)

The misread: Trying to trace a high school math cohort year-over-year the way grades 3-8 are traced — HS course tests (Algebra I/II, Geometry, etc.) aren't a clean grade+1 sequence, so students in 'Algebra I' this year aren't reliably in 'Algebra II' next year.

Full entry, with the story and the numbers, in the served ergo doc.

grade-mix-context [context · open] District/state context blends all tested grades; a school's value covers only its own

Type: definitional — applies to tables: assessment, assessment_grade

The misread: Reading a high school's math proficiency sitting below its district as a deficit — the district figure blends grades 3-8 with HS course tests over different populations.

Full entry, with the story and the numbers, in the served ergo doc.

Changelog

  • — Consolidated the five conformed SPR projections and absence/graduation edition records behind one complete family adapter. Advanced the assessment headline, assessment-by-test, and growth pins from missing baseline directories to retained refresh-2 releases whose conformed source-table bytes match the prior exact pins. The consumer assessment mart now also projects literal cells and physical workbook provenance from the pinned typed tables, restoring participation-aware answers in a cold offline rebuild without a local workbook parser.
  • — Registered spr/legacy-archive-link-is-dead: the nj.gov/education/schoolperformance/archive/ link this page gave for 2011-12 to 2014-15 returns 404, as does every year path under it. Repointed at the live Title I ESEA Flexibility waiver accountability archive (12.zip through 16.zip), with the caveat that it holds accountability determinations rather than SPR tabs and stops at 2016.
  • — Converted to ergo format: 13 issues registered from the oddities list and tab notes; confirmed-from-real-data log became validation records.

The text on this page was generated by Claude Opus 4.8, working as part of a stack of tools created by Lyra Forge.