Releases: HarperZ9/learn
Releases · HarperZ9/learn
Release list
learn 2.3.0
- Choice items (
learn-choice/1,src/tutor/choice.mjs). A recall question keys one answer and names the misconception behind each wrong choice.diagnoseChoice()tells a wrong attempt which misconception it matches, using the same top levels as the arithmetic tree, and never returns the keyed answer.doctorchecks that with a probe and a known-bad item. - A browser entry,
@harperz9/learn/browser(src/browser.mjs). Practice, scheduling and diagnosis load in a page with no bundler. The session functions moved fromtutor.mjsintosession.mjs, which has no Node built-ins;tutor.mjsre-exports them unchanged. A test walks the entry's import graph and fails on anynode:or bare import. - An attempt may carry a
misconceptionleaf, andmisconceptions()counts it.
learn 2.2.0
- Misconception diagnosis for arithmetic practice. A wrong answer to a whole-number or fraction-addition prompt walks a fixed tree of yes-or-no questions and gets a cause, such as
misrecruited.no_carryorslip.one_digit.tutor misconceptionsandlearn_tutor_misconceptionsnow count causes per objective in adiagnosesfield. The diagnosis never shows the correct answer. On 50 held-out teacher-labelled answers it agreed with the teacher on 96%; details indocs/MISCONCEPTION-DIAGNOSIS.md.
learn 2.1.0
- Add Windows x64 MCPB and ZIP packages with a bundled runtime, scoped skills and qualified local stdio workflows.
- Require clean exact-tag source, versions ending in .0, payload hashes and matching same-release artifacts; refuse changed release reruns.
- Preserve the graded-assessment halt and CLI-only live course actuation; validate assessment outcomes rather than field-name substrings.
All notable changes to learn. Versions follow semantic versioning; each minor release was built
behind the feat/learning-loop branch and reviewed before merge.
learn 2.0.0
A security release that also makes the package's own entry points work. It changes where learn
keeps state and how resume authorizes steps; "Moving from 1.6.0" below lists what to do.
Security
Affected: 1.6.0 and earlier.
- Path escape through
sessionIdandrunId.learn_tutor_planjoinedsessionIdinto
tutor/<id>.jsonwith no check, so"../.claude/settings"replaced a project's
.claude/settings.json.learn_tutor_record,learn_verifyandlearn_receiptread or
rewrote files the same way, andlearn_dry_run,learn_tutor_prooflessonand
learn_tutor_reverifyread any path, with a non-JSON file's first characters in the error.
Ids now match[A-Za-z0-9._-]{1,64}, must not start with a dot or a hyphen and must not be a
Windows device name. Every resolved path, after links and junctions, must stay inside the state
folder. Path arguments resolve inside it, and a failure carries a closed code and fixed text. A
path outside the folder on its text, such as a\\host\shareUNC path, is refused before
anything opens it, so no SMB or WebDAV connection is made. A link whose target does not exist
is refused, not followed. - Resume submitted and paid without the opt-in.
learn resumepassed
allowIrreversible: trueon every call. After a halt atassess, a plain resume clicked the
nextsubmitstep and acoststep, and the receipt filed the submit as a witnessed automated
submission. A resume now keeps the run's recorded mode,--submittakes onlymanualor
witnessed-auto, and steps flaggedcostorirreversiblehalt unless--allow-costis given
on the invocation that reaches them. The ledger entry of each step a grant allowed names it,
and the receipt lists it (witnessedAutoSubmissions[].authorizedBy,authorizedCostSteps).
The command line is read once, so a grant word given as the value of another flag, as in
--attest "--allow-cost", is that flag's value and grants nothing. - Children of
LEARN_*_CMDinherited the caller's folder and environment. With the documented
python -m crucible, acrucible/package in the folder wherelearn assist --crucibleran was
executed. Children now start through the vendored safe spawn helper 1.0.1
(src/_vendor/safe_spawn.mjs, pinned inVENDORED.sha256): absolute executable, private empty
folder, environment allowlist extended only byLEARN_CHILD_ENV,
NoDefaultCurrentDirectoryInExePath=1on Windows,-PandPYTHONSAFEPATH=1for Python.
A command given as a bare name is looked up on PATH without any entry that reaches the folder
learn runs in: an entry naming that folder or a folder below it, a junction or symlink to it,
or a quoted spelling of it. The child's PATH leaves those entries out too, so a peer command
that runs a helper by bare name does not find one planted there on PATH. When learn runs in a
filesystem root, in your home folder or in a folder above it, it skips only an entry naming
that folder itself. It never skips Node's own folder or the Windows, System32 and SysWOW64
folders, and when it runs in one of them it skips no entry. On Windows a drive-relative name
such asC:toolis refused. For the same reasonLEARN_NATIVE_CONTROLmust be an absolute
path: a relative value imported abrowser.mjsfrom the folder wherelearn run --native
started. - The shipped
docs/smoke.mdno longer names a local development folder. The code default was
already removed onmainand ships here for the first time.
Breaking changes
- State location. Sessions (
tutor/) and runs (runs/) live inLEARN_HOMEwhen it is set,
else in%LOCALAPPDATA%\learnon Windows,~/Library/Application Support/learnon macOS, and
$XDG_DATA_HOME/learnor~/.local/share/learnelsewhere. 1.6.0 wrote them into the folder the
command started in.learn statusprints the folder understate. - Resume. A plain
learn resumeno longer submits or pays.run --submit witnessed-autono
longer coverscoststeps. A completed or denied run cannot be resumed. - MCP errors. A tool failure is a result with
isError: trueandstructuredContent
{code, retryable, setup, detail}, where code isINVALID_ARGUMENT,NOT_FOUND,CONFLICTor
INTERNAL. 1.6.0 returned JSON-RPC-32000errors with free text. An unknown tool is-32602. - No silent overwrite.
learn_tutor_planandlearn tutor planrefuse to replace an existing
session unlessreplace: trueor--replaceis given. - MCP paths.
learn_dry_runtakesworkflowinline orworkflowPathinside the state
folder;packetPathandfileresolve inside it too.learn_tutor_reverifynames each
receipt relative to the state folder (tutor/<id>.mastery.json), not by its absolute path. - Peer commands. A
LEARN_*_CMDchild sees only allowlisted variables and starts in a private
folder, and a relative path in the command is refused. A peer command installed inside the
folder learn runs in is no longer found by bare name, whether it sits in a project's
node_modules/.binor in a virtual environment inside that folder. With such a venv activated,
pythonresolves to the next Python on PATH, so name the venv's interpreter by absolute path,
for example["/absolute/path/to/course/.venv/bin/python", "-m", "crucible"]. Each peer start
reads every PATH entry, so a slow or unreachable network folder on PATH delays every start. The
interop functionscrucibleAssess,gatherRunandtelosRenderare async; they are not
package exports.
Fixed
- The
learnbin works.src/cli.mjsstarts with#!/usr/bin/env node, the repository checks
out LF everywhere (.gitattributes), and main-module detection compares real paths, so the bins
npm links run. In 1.6.0 the bin printed nothing on Windows and failed on Linux. - The human attestation records the real time of the resume. 1.6.0 recorded 1970-01-01.
- MCP
serverInfo.versionreports the package version; 1.6.0 said 1.0.0. A test now holds
package.json,package-lock.json,src/index.mjs,serverInfo, status, doctor, this file
and the README to one version.
Added
learn mcpand alearn-mcpbin start the MCP server:npx -y @harperz9/learn@2.0.0 mcp.--dir <folder>on the CLI for a project-local state folder, andLEARN_HOMEfor every entry
point.learn statusandlearn_statusreport the folder in use understate, with its
source:--dir,LEARN_HOMEordefault.LEARN_*_CMDalso takes a JSON argv array, which
keeps a path with spaces whole.- A release workflow. On a
v*tag it checks the tag against every version site, smokes the packed
tarball throughnpxon Windows, Linux and macOS, publishes with npm trusted publishing (npm
records provenance), and creates a GitHub Release with the tarball andSHA256SUMS. CI runs the
same tarball smoke on every push. Actions are pinned by commit SHA. - Also released from
mainfor the first time: the repository art and its tests, and the
src/interop.mjsorgan-bundle entries (not exported and not imported by the package).
Moving from 1.6.0
- To keep sessions and runs in a project folder, pass
--dir <that folder>or setLEARN_HOMEto
it. To move them, copy the folder'stutor/andruns/into the folderlearn statusprints. - A run that should submit on resume: pass
--submit witnessed-autoonrunor on that resume. A
run that should pay: pass--allow-coston the invocation that reaches the payment step. - MCP clients that read JSON-RPC error text read
structuredContent.codeinstead. LEARN_TELOS_CMD="node ../telos/src/cli.mjs"becomes
LEARN_TELOS_CMD='["node", "/absolute/path/to/telos/src/cli.mjs"]'. Name any variable a peer CLI
needs inLEARN_CHILD_ENV, for exampleLEARN_CHILD_ENV=ANTHROPIC_API_KEY.