Repository navigation
Release Type: A minor release, and the householding one. The open Engine issues went from 243 when 13.3.1 shipped to 5 at the cut on 2026-11-09, the fewest since 1.0.0. Most of the drop came in a sweep that began on 2026-11-05 at 189, through premise reads, delivered fixes and moves to the repositories where the work belongs. Beside it ship five other changes:
- CI that runs only the test tiers a change can reach, with the Brain-gated tier retired;
- Neural Link specs that run in hosted CI without a Bridge;
- one Pointer Events sensor for every drag, in place of the mouse and touch sensors;
- grid header groups and CSV export;
- 93 completed requests filed before 2025, the oldest from November 2019.
Stability: Stable. Set at the cut candidate after the release gate.
Upgrade Path: Not a drop-in for every app. Eleven behaviour changes are listed under Upgrading from 13.3.1. The package's entry points are unchanged.
TL;DR: An open issue is a claim that something is still broken or still wanted. On 2026-11-05 the Engine held 189 of those claims, 111 of them filed more than 180 days earlier, and nobody could say which still held. Writing code had stopped being the scarce part; deciding whether a months-old report is still true had not. So each of the 189 got a premise read against current source by the maintainer who knows that code, and one of four verdicts: close with a citation, rewrite, move to a Discussion, or holds. Bugs were fixed rather than triaged, and small requests were built rather than parked. The gate, fewer than 25 open, held at 03:45Z on 2026-11-08, and 5 remained at the cut, the fewest since 1.0.0 shipped in November 2019. In the same window Engine CI learned to start only the test tiers a change can reach and retired its Brain-gated tier, single-app Neural Link specs began running in hosted CI without a Bridge, one Pointer Events sensor took over every drag, grids gained header groups and CSV export, and 93 requests filed before 2025 were completed, the oldest from November 2019. Eleven behaviour changes need a look before you upgrade; the package's entry points are unchanged.
📋 13.4 in 2 Minutes
New to Neo.mjs? It is an agent institution, persistent AI maintainers with identities, memory and peer review, together with the multi-threaded application engine they build, in sibling open-source repositories (README). This note covers the engine. Your app's components, state and data stores run in a worker, the App Worker; the main thread applies DOM changes and answers layout questions.
Who built it:
- On Claude: Ada (@neo-opus-ada), Clio (@neo-fable-clio), Grace (@neo-opus-grace), Mnemosyne (@neo-fable-mnemosyne) and Vega (@neo-opus-vega).
- On Gemini: Julia (@neo-gemini-julia) and Maryam (@neo-gemini-maryam).
- On GPT: Emmy (@neo-gpt-emmy), Euclid (@neo-gpt-euclid) and Sophie (@neo-gpt-sophie).
- Outside contributors: eight people sent ten pull requests, each person's first in this repository: @Athmika08, @anasdahani220, @calude-bot, @kaushlendra-pt-singh, @RClaudiuM, @SimonGebru, @Toufiqul-27 and @wanjinhao1. From the community thanks each of them by pull request.
- The householding's charter: Clio wrote #15000, the ticket the sweep ran on. Her work in this cycle was planning rather than pull requests.
The maintainers review each other across model families. Tobi (@tobiu) merged every pull request in this release except 31 Dependabot bumps, which merged automatically.
The one line: the backlog is clean, and the tests run only where a change can reach.
What changed:
- Householding (#15000, #20497): 243 open Engine issues when 13.3.1 shipped became 5 at the cut. The sweep from 2026-11-05 gave each of its 189 a premise read, without one bulk close by age.
- CI by reach (#20328, #20451): a pull request starts the test tiers its change can reach, superseded heads are cancelled, the lint, unit and review-admission families each run as one job, and the Brain-gated e2e tier is retired.
- Neural Link specs without a Bridge (#20370): single-app specs drive the page's own App Worker in hosted CI, with no Bridge and no Brain checkout.
- One drag sensor (#17889): a Pointer Events sensor with pointer capture replaces the mouse and touch sensors, so a drag that crosses an iframe still ends.
- Grid (#20379, #20380, #20359, #9486):
- columns under shared group headers;
- CSV export;
- nested
dataFieldpaths in every column type; - the multi-body architecture for locked columns, completed.
- Requests that waited years: 93 issues filed before 2025 were completed, 81 of them by a pull request.
Try it: the header groups demo groups twenty regions' monthly sales into quarters, with Region and the Year total locked at either end. What you can try walks through it.
The scale: 336 pull requests merged in neomjs/neo and 424 issues closed since 13.3.1 shipped on 2026-10-23. The Full Changelog lists them.
Read for your work:
- Upgrading from 13.3.1, if you ship the engine;
- One drag sensor, if you build drag interactions or drive them from tests;
- Grid, if you build data views;
- CI by reach and From the community, if you contribute.
🧹 The householding
The operator, 2026-11-05: "We resolve 200+ tickets every week, yet inside engine and brain repos we have backlog items that are several months old and rot. We need to check if intents are still valid, even in case the code reality can have changed a lot. The benefit is getting to a clean slate which betters allows us planning new items afterwards."
Velocity stopped being the scarce part this year. Anthropic reported in October that it went from about 2,500 merged code changes a day in May to over 30,000 by September, and built its own source control to carry them; its engineers found that "very often … the role of the engineers was to tell Claude 'no'" (Anthropic). A popular tool's tracker feels the same pull: Claude Code's closed 5,139 issues in the 30 days to 2026-11-08 while 7,446 new ones arrived (GitHub). Source control scales with output; issue control takes judgment. For 13.4 we pointed our velocity at issue control, starting with our own backlog.
The charter was older than the ask. Clio (@neo-fable-clio) had filed #15000 in July: every open engine issue gets a premise read and a verdict. On 2026-11-05 it became the instrument. At 10:20Z that day the Engine had 189 open issues; 111 of them had been filed more than 180 days earlier, 94 were unassigned, and 102 were the operator's own. Thirteen days earlier, when 13.3.1 shipped, it had 243.
The rules made the count an outcome, not a target.
- Age is not a staleness signal. Each ticket was read by the peer who knows that domain, against current source. The verdict was one of four:
- close, citing the resolving file, pull request or ADR;
- rewrite the body to the current architecture;
- move to a Discussion, when the idea was valid but had no plan;
- holds.
- Bugs got fixed, not triaged.
- The operator's own tickets closed like any other once he allowed it (2026-11-05), with one condition: every part of the original intent is checked first. A part that still held survived as a rewrite or a successor, never inside the close.
- The good-first-issue set stayed open for contributors.
The domain reads ran in parallel across eight areas, from the class system to docking. Their ledgers stay in #15000's body.
The numbers come from the gate receipt (#20497, cross-checked row by row by a second maintainer).
From 2026-11-05T00:00Z to the gate at 2026-11-08T03:45Z, 260 issues closed:
- 199 completed: 154 through a merged pull request and 45 by hand, most of those after a premise read found the work already shipped;
- 60 not planned;
- 1 duplicate.
104 of the 260 were filed inside the window itself, because the sweep filed its own follow-ups and closed them.
The fewest open issues since 1.0.0. We rebuilt the open count from the open and close dates of all 12,775 Engine issues. It had never been lower than 23, the count on 2019-11-17, the day 1.0.0 shipped, until this week. It passed 300 in 2023 and peaked at 542 on 2026-05-16. Issues that later moved to another repository drop out of that history, so it can only undercount the past: it shows 174 open the night before the sweep began, where 189 were measured. The 243 at 13.3.1 comes from the content-sync corpus's snapshot 13 minutes after that release. The rebuilt history agrees with it once the 18 issues the sweep later moved to other repositories are added back, and 3 that it counts open but that were closed at the time are taken out.
Tickets whose work lives in another repository moved there: Agent OS and Fleet Manager work to Institution, skill work to Skills, deployment work to the middleware. Valid ideas without a plan became Discussions, until the last night narrowed that rule. A transfer leaves no closed record here, so the 260 does not count those moves.
The last night
That night the operator walked the last tickets one by one with Vega. The gate held at 03:45Z on 2026-11-08 with 24 open, and the walk went on past it, sharpening two rules:
- A Discussion is for an open design question that someone will work. A ticket with a clear scope and no one on it is debt in either place, so it gets built, or closed with its reason.
- Dropping an item for lack of demand is for large items. An editor epic closed that way (#20166): work of that size is not built until someone needs it. A small item gets built.
Note
At about 04:00Z the drag-sensor rewrite (#17889) was headed out of the backlog for lack of demand: Vega proposed a Discussion, then a close. The operator: "move to discussion is non trivial. is it worth an ideation sandbox? or is the scope clear? because moving ticket DEBT into discussion DEBT is not feasible either." And of the ticket itself: "this ticket feels SMALL, something you could probably finish inside this very session." It was built that night and merged at 07:36Z; see One drag sensor.
Two user-facing defects were fixed before the tag: nested dataField paths in grid column types (#20359) and the concept ontology left in the npm package (#19093).
The last two days
Five findings already on dev surfaced on 2026-11-08, the day the cut was planned, and all five were fixed before the tag:
- A splitter drag opened a sort session in its parent dashboard (#20588 → #20590). Maryam traced it while reviewing the new drag sensor: the splitter's
drag:startbubbled up to the dashboard's sort zone, which took the splitter for a sortable item and left its container markedneo-is-draggingfor at least 15 seconds after the release. The splitter's own drag listeners no longer bubble. - The Workstation's light theme lost its own accent in the dock's drop previews (#20591 → #20592). Since #18747 (2026-09-15) moved the app's theme sheets under
:where(), the tie between the app's projection and the engine's value went to load order, and the engine's#0d9488replaced the app's#0f766e. The visual suite's light arm caught it. The app's sheets are back at theme-root weight. - A grid pooling test flaked (#9160 → #20586). It now drains its two-flight mount updates before it measures.
- Every production
main.jscarried the path of the machine that built it (#20600 → #20602). Webpack inlinedimport.meta.urlat build time, so the public neomjs.com bundle shipped its builder's absolutefile://path, and the workspace-addon check tested the builder's tree instead of the page's. The main config now keepsimport.meta.urla runtime value, andbuild-allfails a production build that shipsfile:///(see Upgrading from 13.3.1). - The portal's news tab bar clipped its last tabs on portrait phones (#20599 → #20603). At 390×664, Pull Requests and the new Videos tab were out of reach. The portal's tab containers now use the engine's
Neo.tab.plugin.Overflow: headers past the bar's height fold behind one ⋮ menu, and a tab chosen there moves the route as its header would.
Then the operator's manual test of the header groups demo blocked the cut; Grid lists what it found.
From the gate to the cut the open count went from 24 to 5: 49 more issues closed and 29 new ones were filed, most of them the last two days' own findings and follow-ups, and one closed ticket reopened until its flake was fixed. Tickets filed before the cut went into it, so the release closed everything it found.
Honest bounds:
- "Completed" covers both work delivered in the window and premise reads that found it already shipped.
- The open count is a snapshot at the cut, and it moves every day.
- The Brain repository runs the same sweep separately (neomjs/neo-agent-brain#1438).
⚙️ CI by reach
The organization runs on 20 concurrent job slots, and every repository's pull requests share them. Engine CI used to start every tier on every push. #20328 measured that baseline and then cut it, leaf by leaf:
- A scope classifier decides which tiers a change can reach. It keeps deny-lists, gives the Brain tier
none, and reports its boundary (#20329, #20332). Engine pull requests then run only the e2e specs their change can reach (#20330). - A ruled-out tier starts no runner. On the measured corpus that saved 806 job starts (#20338, #20362).
- A superseded head is cancelled instead of finishing (#20340, #20341).
- One job per family instead of one per check:
- A
devpush diffs from its workflow's last completed run, so a cancelled push no longer leaves its own diff unclassified. The measured hole went from 17 pushes to 0 (#20363, #20368). - e2e shards are balanced by measured run time against a five-minute target per shard, replacing the split by test count. Run-to-run variance remains, so the target is not a guarantee (#20521, #20522).
- A ruled-out components tier starts no runner either. It used to boot three runners only to report a skip; its shards now skip at job level behind one
componentscontext (#20595, #20596). - The repository's own guards run as one required context. Fifteen guard commands from four standalone workflows now run as one list in the shared baseline's
guardsjob, and the baseline reports three contexts where it reported ten. A pull request starts 3 baseline jobs instead of 10, and thedevruleset requires 7 contexts instead of 16 (#17171, #20598). - No Engine job checks out the Brain. The guide lint now runs inside the shared baseline at its pinned release (
neo-agent-skills1.2.0) instead of cloning the Brain'sdev, so a Brain push can no longer change an Engine pull request's verdict (#20597, #20612). With that leaf, #20328 closed.
On the last night, a calendar-only fix (#20578) ran four of the tier's e2e spec files, its own two among them.
The Brain-gated e2e tier retired on 2026-11-08 (#20451, #20584). In #20328's baseline it held about two thirds of Engine CI runner-minutes. Of the 71 spec files it gated:
- 61 moved into the engine tier, which now selects 196 of its 212 files. 54 moved with the retirement. Four followed once the off-socket adapter released a held worker session before a re-boot (#20587, #20615), and two once it could bind a second browser context by worker id (#20614, #20621). The Workstation film tour, excluded after a hosted flake, came back once its throw kept its momentum on a slow runner (#20593, #20601).
- 10 stay local, each with its reason in
LOCAL_ONLY: four test the Bridge itself, and six import Brain modules.
A pull request now starts no Brain-tier job, where it started up to ten shards before, and a full engine run is 14 jobs where the two tiers ran 18.
🔌 Neural Link specs without a Bridge
A Neural Link spec used to need the full cycle: the Brain's Bridge, a Brain checkout, and the Engine page on the other end. Discussion #18775 chose an off-socket adapter instead, which lets a single-app spec drive the page's own App Worker directly. Its epic, #20370, landed in 13.4:
- the seam (#20371, #20381);
- the dedicated-worker adapter (#20372, #20373);
- spec selection (#20374, #20404);
- SharedWorker apps (#20376, #20461).
The Brain keeps testing its own Bridge and tool definitions in its own repository. On 2026-11-08 #20451 brought the rest across: a local probe ran 37 of the 42 window-driving specs clean off-socket, so they joined the engine tier (#20584). Four of the six window specs that still failed off-socket (#20587) followed the same evening. The adapter's session on the App SharedWorker had kept that worker alive past its last client, so a re-booted page reached a stale worker; the fixture now releases the session before a navigation (#20615). The last two bind a second browser context by worker id, and joined once the adapter could reach a worker in another context (#20614, #20621).
🖱️ One drag sensor
Every drag in the engine starts in a main-thread sensor: dock tabs and tear-outs, splitters, grid column moves and resizes, calendar events, dialogs. Until 13.4 there were two sensors, one for mouse events and one for touch events. A drag that wandered over an iframe could go silent there, because the iframe took the moves and the release, so the drag never ended. #17889 asked for Pointer Events with pointer capture. The roadmap had deferred it, and on the last night it nearly left the backlog (see The last night). It was built that night instead, from Grace's notes of September and Euclid's intake of 2026-11-07, and merged at 07:36Z (#20585).
Neo.main.draggable.sensor.Pointer replaces Mouse and Touch:
- one state machine hears
pointerdown,pointermove,pointerupandpointercancelfrom mouse, touch and pen, and owns each gesture by itspointerId; - it captures the pointer on the document root only once a drag passes its threshold, so a press that never becomes a drag still clicks its own element, and an engaged drag ends exactly once, over an iframe or not;
- a captured event names the document root, so the sensor adds the hit-test path as
eventPathandDragDropbuilds its targets from it; thedrag:*payloads the App Worker receives are unchanged; - the engine's own drag handles (splitters, resize handles, a draggable dialog's header) declare
touch-action: none, and a custom handle opts in the same way (src/main/draggable/README.md).
The proof: a new component test drags across an iframe pane. On the old sensors no move arrives inside the iframe; on the new one the moves keep streaming there and the release ends the drag once. Before the merge, the full unit suite (6,656 tests), the full component suite (581) and 136 drag, dock, splitter and sort e2e tests passed locally, and hosted CI ran every tier the change reaches.
A touch held still always arms. The arm timer re-read Date.now(), which can show the delay a millisecond short: measured, 11 of 1,500 timers of 10 ms. When it did, the arm declined and nothing re-armed it, so a perfectly still finger never started its drag, and a unit test flaked in CI. The timer now tells the sensor its delay has elapsed (#20636, #20637).
Honest bounds: touch was checked through Chrome DevTools Protocol emulation, not on a device. The operator's manual drag walk is the open post-merge check on #20585.
📊 Grid
Header groups (#20379, #20397). A columns entry with its own columns array is a group:
columns: [
{dataField: 'name', text: 'Name'},
{text: 'Q1', columns: [{dataField: 'jan'}, {dataField: 'feb'}, {dataField: 'mar'}]}
]The leaf header row does not change: sorting, resizing, filters, menus, drag and aria-colindex keep working on the same flat buttons. A group row is projected above it, one part per region, so locked columns get their own group cells.
The operator made "header groups finished" a second gate for this release. A verification matrix of 8 rows ran on #20379, and every defect it found was fixed before the tag (#20510, #20511, #20512, #20517). #20571 made a cancelled header drag put the body cells back.
The operator's manual test of the demo then blocked the cut, and six more changes made it before the tag:
- A header's drag proxy kept its header. After a horizontal scroll, the proxy could show an empty slot where its header belonged. Every sort zone kept its previous drag's boundary, so the next drag's first move ran before that drag had started, and wrote screen coordinates into the header the proxy copies. A drag now ends by clearing its boundary (#20626, #20632).
- A grouped header's proxy stays over its group, the rule its drop always followed. Past the group's edge the header waits in the edge slot, and a release keeps it there. The first fix slid the other headers back to their old order instead, and the operator's second pass rejected that (#20632).
- A group header drags its whole group between the other top-level headers (#20627, #20630).
- A group drag shows where its group lands. It runs through its region's column drag zone as one unit: the neighbours it passes slide aside live with their group cells, its proxy carries the group cell over its headers and their cells, and the release keeps the order the drag showed. A header drop also measures the headers only once they have rendered. Before, a flex column could take the width of headers the drag had lifted out of the flow, leaving group cells and body columns misaligned until the next resize (#20641, #20644).
- The demo got its finish.
examples/grid/headerGroupsopens in the modern light theme. Above the unchanged grid it adds a title, gesture instructions and a light/dark switch. Each skin has its own palette, which the drag proxies carry too (#20635, #20638). The switch reveals the new skin in a circle that grows from the click (#20648, #20651). - A header drag's gap reads as a header. While a column or group drags, the slot it vacates showed the generic toolbar beneath it: near-black in neo-dark, white in the light themes. During a drag the header toolbar now takes the header-button background, in every grid. The drag proxy now ends at the last row when the rows stop above the grid's bottom (#20652, #20653).
CSV export (#20380, #20389). grid.toCsv(options) returns the store's current records as a string:
- columns run in display order under their header text;
- rows follow the store's filter and sort, including rows a buffered grid never rendered;
- quoting follows RFC 4180, lines end in CRLF, dates are ISO 8601, and
nullis an empty field; - a formula guard, on by default (
escapeFormulas: falseturns it off), prefixes a string cell that starts with=,+,-,@, a tab or CR.
grid.exportCsv({fileName}) downloads the string. A column can override a cell through exportRenderer({record, value}).
Nested data fields (#20359, #20582). A dataField such as metrics.load already worked in plain cells, sorting and filtering. Nine column types read their value themselves and missed the path: Progress, Sparkline, Tree, Icon, IconLink, LinkedIn, CountryFlag, AnimatedCurrency and AnimatedChange. They now read through one method, Neo.grid.column.Base#getRecordValue, which uses Record#get on records and Neo.ns on the plain objects of Turbo Mode rows. AnimatedChange animates when the value at the path moves, not when a sibling member of the same object changes.
The multi-body grid, completed (#9486, #9872, #20499). Neo.grid.View now owns the up to three bodies, bodyStart, body and bodyEnd. It creates and destroys them on a runtime lock change and hands configs across them, the same way the header wrapper does. That closes the epic for zero-jitter locked columns. Its cross-window follow-ons, detaching a locked region into its own window and syncing scroll over a direct channel, are now Discussion #20579.
Smaller grid fixes:
- tree rows announce their real expansion state (#20566, #20567);
- a re-added tree node keeps expanding after the store sorts (#20568, #20569);
- a header menu no longer throws over a retired trigger (#20564, #20546);
- the themes no longer define
--grid-container-header-cell-border-bottom, a token no stylesheet had read since it was added in 2022. The header's bottom border comes from--grid-container-border-color, so a theme that set the token changes nothing by dropping it (#20646, #20649).
⏳ Requests that waited years
106 issues filed before 2025 closed in this window. 93 were completed, 81 of them by a pull request. The oldest were filed in the engine's first weeks on GitHub, in November 2019:
- Closable tabs,
tab.Container(#26, #20399). - Docs app: routes for class tabs, so a reload restores the open class, filed the day 1.0.0 shipped (#24, #20620); tab header tooltips (#29, #20224), theme button texts (#45, #20272) and the mixins of a class (#99, #20327).
DateSelector: keyboard navigation and selection (#44, #20316), with arrow navigation no longer stopping at the current month (#47, #20247).
2020 followed close behind:
- the gallery's loading spinner (#290, #20343);
- the Helix selection model's
toggleSelection(#318, #20203); - the calendar's 12- and 24-hour time axis (#941, #20326), plus its month view's wheel, font-size and scroll fixes (#989, #991, #992);
- the week view's infinite scrolling (#1069, #20360).
🤝 From the community
Eight people from outside the team merged ten pull requests in this window, and for each of them it was a first pull request in this repository:
- @kaushlendra-pt-singh fixed the calendar week-view example that threw on load (#19930 → #19958), one of the two broken examples 13.3.0 left open as good first issues, and pinned the number field's spin-button trigger (#19144 → #20123).
- @RClaudiuM made long grid header text clip inside its own column instead of running into the next one (#20444 → #20446), and made
seat:startrebuild stale development themes (#20429 → #20475). - @wanjinhao1 stopped the development theme preflight from naming E2E when
seat:startruns it (#20506 → #20504). - @anasdahani220 made the Neural Link e2e fixture name
NEO_NL_PORTwhen a seat's fleet Bridge refuses it (#20339 → #20386). - Four pinned an engine behaviour with tests: @calude-bot,
HashHistory's one route stack per browser window (#19132 → #20197); @Toufiqul-27, when the toast manager refuses a toast (#19147 → #20191); @SimonGebru, how the currency field parses and renders amounts (#19129 → #20157); and @Athmika08, howNeo.util.CountryFlagsturns a location into a flag (#19177 → #20094).
Thank you, all eight. New good first issues are filed as the team finds them: comment on an unassigned one to claim it. The claim holds for 7 days from your latest comment there (#20616, #20617).
🧰 Also in 13.4
- Data: store pipelines compose awaited interceptors (#9553, #20487).
- Events: a Function passed to
un()orremoveListener()now removes the function registered with it, by identity (#20560, #20561). - Calendar: pressing Escape during an event drag puts the event back instead of moving it (#20577, #20578).
- Responsive:
Neo.plugin.Responsivebinds to the matching viewport on mount and rebinds when a component moves to another window (#20334). - Package: the npm package no longer ships the Agent OS concept ontology; it lives in the Agent OS plane (#19093, #20580).
- Tabs: a tab chosen from
Neo.tab.plugin.Overflow's menu moves the route as its header would: a plain route replaces the hash, and aneditRouteheader merges its fields into it (#20599, #20603). - Portal: the news section gains a Videos tab; each film stays a click-to-play facade until a visitor starts it, and at most one plays (#20589, #20594).
- Dependencies: Dependabot proposes updates every day, weekends included, so a release shipped on a Saturday or Sunday no longer waits until Monday (#20606, #20607). Its first run after the change brought Playwright 1.65, with the copied Chromium launch defaults refreshed to match (#20613, #20608). A new Skills workflow release is proposed on its next run instead of three days later (#20618, #20619).
- Rendering: with the default DOM API renderer, SVG in a component's vdom renders.
svgandmathsubtrees are created in their own namespaces, an element inserted into a live<svg>lands as SVG, andforeignObjectreturns its children to HTML. The engine's Timer example draws its ring again (#20647, #20650). - View transitions:
Neo.main.DomAccess.startViewTransition()resolves once the browser has captured the old state. Before, it resolved earlier, so a fast theme change could land in both snapshots and a circular reveal showed nothing. The Portal and Workstation reveals get the same guarantee (#20648, #20651). - Tooling: in an engine checkout, test runs and
npm run server-startrefuse an install that differs frompackage-lock.json, naming the drifted packages and the fix (#20642, #20643). - Workstation: a popup the browser refuses explains, in a hint that leaves the page usable, how to allow it (#19537, #20623).
- Drag:
Neo.draggable.container.SortZonegains two protected hooks,getPinnedItemsandgetDragElement. A subclass can now keep non-sortable siblings in place during a drag and clone a handle into the drag proxy without copying the drag lifecycle (#20605, #20611). - Forms, components and docs: the long tail of requests above, listed in the Full Changelog.
▶️ What you can try
Open the header groups demo, twenty regions' monthly sales under quarter headers:
- Drag the Q2 header past Q3: its three months move with it, and the headers it passes slide aside while you drag.
- Drag Apr to the other side of May: a month reorders within its quarter, and its proxy stays over Q2.
- Drag Apr on toward Jul: it waits at the edge of Q2, and a release keeps it inside its quarter.
- Resize a month by its header's edge: the quarter's group cell stays aligned above it.
- Scroll the months sideways: Region stays locked at the start, and the Year group over Total at the end.
- Press Dark theme: the new skin grows in a circle from the button, and the drag proxies take its palette.
On your own grid, give a columns entry its own columns array, as Grid shows above.
⬆️ Upgrading from 13.3.1
What did not change: package.json's main, exports, bin, engines and type are the same as in 13.3.1. The rest of the file changes like this:
- three npm scripts are new:
create-theme,move-filesandseat:start; - the
dompurifyrange moves to^3.4.17; - dev tooling adds three PostCSS packages and moves
neo-agent-skillsfrom 0.1.56 to 1.2.0.
Public behaviour to check:
| If your code… | In 13.4 | Do this |
|---|---|---|
imports CountryFlag, GitHubOrgs, GitHubUser or IconLink from src/component/, or names their old className |
they live in src/grid/column/component/ as Neo.grid.column.component.*; the column types countryFlag, githubOrgs, githubUser, iconLink and linkedin are unchanged (#20470) |
update the import path or the className |
uses the Neo.Responsive global |
it is gone; Neo.plugin.Responsive keeps its configuration per instance (#20334) |
use the plugin |
gives a Button a route and relies on Neo.Main.editRoute |
editRoute defaults to false, so the button renders as an anchor and the browser follows the route (#20342) |
set editRoute: true to keep the old dispatch |
declares a StateProvider stores entry without module, className or ntype |
it becomes a Neo.data.Store; before, the entry silently ended up null. An entry with an explicit className keeps its class (#20214) |
nothing, unless your code relied on that null |
removes a listener by passing a Function to un() or removeListener() |
the Function is matched by identity, so only the function that was registered is removed. Before, a different function with the same name could match (#20561) | keep the registered Function, or the subscription id on() returned, and remove with that. A String passed as the second argument is still read as a subscription id, as in 13.3.1 |
reads .neo-ai-data/concepts/ from the npm package |
the package no longer ships it (#20580) | nothing for apps |
points one of the nine column types above at a dotted dataField |
the path resolves as in a plain cell (#20582) | nothing; values that rendered empty now show |
imports src/main/draggable/sensor/Mouse.mjs or Touch.mjs, or names Neo.main.draggable.sensor.Mouse or .Touch |
both are gone; Neo.main.draggable.sensor.Pointer replaces them, and DragDrop exposes it as pointerSensor and getPointerSensor(), keeping mouseSensor and getMouseSensor() as deprecated aliases (#20585) |
use the Pointer sensor through pointerSensor or getPointerSensor() |
sends raw mousedown, mousemove or mouseup through EventSimulator#dispatch, for example from the Neural Link's simulate_event |
each one is preceded by the pointer event a real mouse fires, with one synthetic pointerId, so a simulated gesture arms a drag as real input does; mouse listeners receive the same events as before (#20585) |
nothing, unless a listener counts every pointer event |
handles the click a browser fires after a drag ends |
past the drag threshold the sensor captures the pointer on the document root, so that click lands on html and no component receives it; a press that never becomes a drag still clicks its own element (#20585) |
nothing, unless your code relied on the post-drag click |
runs build-all for a workspace |
the production build fails when a .js or .mjs file under the build folder contains file:///, the path an inlined import.meta.url leaves, and the message names the file (#20602) |
keep import.meta.url a runtime value in your own webpack config, for example with module.parser.javascript.importMeta: false |
🧭 What comes next
The roadmap for the next release is set after this cut. The backlog keeps standing bands from here on: under 25 open issues is green, 25 to 50 orange, over 50 red. A clean slate leaves room for new tickets, and the bands keep it from growing back. The five still open at the cut are content and contributor work:
- the Grid-family examples with captions (#20500), under the epic for example overviews and the learning section (#20498);
- a video of 100,000 grid rows that never block the page (#20185);
- a post on the Dream Pipeline (#19058);
- a range-field test, a good first issue a contributor holds (#19145).
📦 Full Changelog
336 pull requests merged in neomjs/neo and 424 issues closed (354 completed, 69 not planned, 1 duplicate) between 13.3.1's release at 2026-10-23T23:27:07Z and dev at 328f3f86e5. Counted at 2026-11-09T12:10Z with GitHub search: is:pr is:merged base:dev merged:>=2026-10-23T23:27:07Z and is:issue is:closed closed:>=2026-10-23T23:27:07Z (reason:completed and reason:"not planned" for the split). The counts and this list are regenerated at the cut head.
Grid and tables (42)
- #20108 test(grid): settle two-flight VDOM updates in StoreInteractions and PremeasureRows · @neo-gemini-julia
- #20116 fix(grid,collection): optimize Row, Container, Collection, and bigData hot paths · @neo-gemini-julia
- #20125 fix(grid): ScrollManager isScrolling toggle launches colliding child VDOM flight · @neo-gemini-julia
- #20140 feat(grid): a cellEditingReady promise for the lazily created plugin · @neo-opus-vega
- #20189 fix(grid): one ARIA grid across locked regions · @neo-opus-grace
- #20190 fix(grid): keep search toolbar and menu triggers out of ARIA rows · @neo-gemini-maryam
- #20203 fix(selection): Align HelixModel#select and toggleSelection with selection.Model · @neo-gemini-maryam
- #20247 feat(selection): add stayInMonth config to DateSelectorModel · @neo-gemini-maryam
- #20253 feat(selection): fire modifier-key select events in table and grid RowModel onRowClick · @neo-gemini-maryam
- #20261 feat(grid): allow column configs to name a column class via module · @neo-gemini-julia
- #20271 fix(grid): guard Button#afterSetResizable lazy import against destroy · @neo-gemini-julia
- #20291 test(grid): pin Progress, CountryFlag, and GitHubUser applyRecordConfigs · @neo-gemini-maryam
- #20299 test(grid): enforce computational budget in Pooling.spec.mjs · @neo-gemini-maryam
- #20316 feat(selection): separate date navigation from selection · @neo-gpt-euclid
- #20319 feat(grid): restore body store listeners and support disabling AnimateRows at runtime · @neo-gemini-julia
- #20348 feat(selection): add AccordionModel and wire container.Accordion keynav/selection · @neo-gemini-maryam
- #20352 feat(table): allow Body#applyRendererOutput to render Neo instances and configs · @neo-gemini-maryam
- #20366 feat(grid,table): align grid.Row and table.Body cell component renderer lifecycle · @neo-gemini-maryam
- #20388 feat(table): add drag-and-drop column resizing for table header toolbar · @neo-gemini-maryam
- #20389 feat(grid): export a grid's rows as a CSV file · @neo-opus-grace
- #20394 test(grid): fix AnimateRows teardown and enable CI coverage · @neo-gpt-sophie
- #20397 feat(grid): grid columns can sit under a shared group header · @neo-opus-grace
- #20408 test(grid): IssuesShowcase AX test waits for the lazy menu triggers · @neo-opus-grace
- #20431 test(grid): run Node unit coverage in CI · @neo-gpt-emmy
- #20446 fix(grid): header label ends in an ellipsis inside its own column · @RClaudiuM
- #20455 test(grid): open the header-resize motion window with the gesture · @neo-opus-vega
- #20466 fix(grid): stale scroll reports keep anchor corrections · @neo-opus-ada
- #20470 refactor(grid): move the grid-cell components under grid/column/component · @neo-opus-grace
- #20482 test(grid): the header-resize motion check asserts live growth, not a size inside its window · @neo-opus-vega
- #20499 feat(grid): move locked body lifecycle orchestration into grid.View · @neo-gemini-maryam
- #20502 fix(grid): a re-projected group row keeps its scroll position · @neo-opus-grace
- #20514 fix(grid): a resized flex column keeps its width, and group cells follow the drag · @neo-opus-grace
- #20520 feat(grid): a header drag keeps every header group in one piece · @neo-opus-grace
- #20567 fix(grid): a tree grid row announces its own expansion state · @neo-opus-vega
- #20571 fix(grid): a cancelled header drag puts the body cells back · @neo-opus-grace
- #20582 fix(grid): column types read a dotted dataField like a plain cell · @neo-opus-vega
- #20586 test(grid): drain two-flight mount updates deterministically in Pooling.spec.mjs · @neo-gemini-maryam
- #20630 feat(grid): a group header cell drags its whole group · @neo-opus-grace
- #20632 fix(grid): a grouped header's drag proxy keeps its header and stays over its group · @neo-opus-vega
- #20644 feat(grid): a group header drag slides its neighbours and carries its columns · @neo-opus-grace
- #20649 refactor(grid): retire the grid token no stylesheet ever read · @neo-opus-vega
- #20653 fix(grid): a header drag's gap reads as header, and its proxy ends at the last row · @neo-opus-grace
Docking, dashboard, drag and Workstation (40)
- #20087 feat(dock): an app holds a rail reveal open and hears when the person ends it · @neo-opus-ada
- #20092 fix(dock): a rebuilt rail keeps the application's held reveal · @neo-opus-ada
- #20093 fix(tab,toolbar): clear overflow title caps when strip room returns · @neo-gemini-maryam
- #20100 fix(main): a visible document without frames still drains Main's DOM write queue · @neo-opus-grace
- #20103 feat(dock): the reveal toolbar carries the revealed item's pop-out, and every reveal end names its cause · @neo-opus-ada
- #20110 fix(dock): load active lazy panes in tab-chrome reconciler · @neo-gemini-julia
- #20130 feat(dock): tear out a never-shown lazy pane by materializing it first · @neo-opus-vega
- #20135 fix(tab): a press on a tab holds the focus-gated reveal until it clicks or its drag ends · @neo-opus-grace
- #20145 feat(dock): a reloaded tear-out window keeps its pane · @neo-opus-vega
- #20149 fix(dock): a tear-out vessel whose opener departed releases its pane at once · @neo-opus-vega
- #20160 fix(dock): return a workspace whose opener departed at once · @neo-gemini-maryam
- #20225 feat(workstation): let a subclass choose the Workspace its viewport creates · @neo-opus-vega
- #20266 feat(workstation): add statusModule config seam on Workspace · @neo-gemini-julia
- #20325 feat(tab): wire the WAI-ARIA tabs pattern into tab.Container · @neo-opus-ada
- #20333 feat(toolbar): opt-in arrow-key navigation between buttons · @neo-opus-ada
- #20387 docs(tab): explain selection and card lifetime · @neo-gpt-sophie
- #20399 feat(tab): add opt-in closable tabs and migrate Docs · @neo-gpt-euclid
- #20428 test(dock): the reorder e2e waits out the drag shield · @neo-opus-ada
- #20438 test(workstation): read feed ordering in one worker turn · @neo-gpt-sophie
- #20474 feat(main): OpenStreetMaps addon markers and map messages · @neo-opus-ada
- #20479 chore(dashboard): extract Demo B cross-window gesture driver · @neo-gpt-sophie
- #20494 chore(dashboard): compose Demo B keyboard host · @neo-gpt-sophie
- #20495 fix(dashboard): load the example skin in popups · @neo-gpt-sophie
- #20516 chore(dashboard): compose Demo B native-window host routing · @neo-gpt-sophie
- #20524 chore(dashboard): separate Demo B tear-out gesture driver · @neo-gpt-sophie
- #20546 fix(dashboard): restore tab titles and extract perspective host · @neo-gpt-sophie
- #20550 chore(dashboard): compose Demo B native effects · @neo-gpt-sophie
- #20552 chore(dashboard): compose Demo B interaction and tour hosts · @neo-gpt-sophie
- #20553 test(workstation): witness rendered cross-root drag isolation · @neo-gpt-euclid
- #20555 fix(dock): skip unchanged placement after queued moves adopt · @neo-gpt-euclid
- #20576 fix(workstation): the grid bridge maps selection and header groups · @neo-opus-vega
- #20585 feat(draggable): one Pointer Events sensor with post-threshold capture replaces Mouse and Touch · @neo-opus-vega
- #20590 fix(component): a splitter owns its drag, so its parent dashboard opens no sort session · @neo-opus-vega
- #20592 fix(theme): the Workstation's dock projections outrank the engine's value sheets again · @neo-opus-vega
- #20601 fix(workstation): release film tour throw without post-move stall · @neo-gemini-maryam
- #20611 feat(draggable): add SortZone getPinnedItems and getDragElement hooks · @neo-gemini-julia
- #20623 feat(workstation): explain refused popup opens with non-modal guidance · @neo-gemini-julia
- #20625 test(draggable): the touch-arm test waits on drag:start, not a fixed 40 ms sleep · @neo-opus-vega
- #20634 test(workstation): pin the popup bootstrap's shell flag · @neo-opus-ada
- #20637 fix(draggable): the drag-arm timer arms a still pointer even when Date.now() reads its delay short · @neo-opus-vega
Forms, components and calendar (100)
- #19958 fix(calendar): defer weekview header creation until currentDate is set · @kaushlendra-pt-singh
- #20107 fix(list): a changed record re-renders at its current index, not the payload's pre-sort one · @neo-opus-grace
- #20123 test(form): add unit spec for SpinUpDown field trigger · @kaushlendra-pt-singh
- #20141 fix(core): a destroyed instance refuses late config writes · @neo-opus-ada
- #20159 fix(manager): bind releaseHeld closed continuation to exact readmit admission · @neo-gemini-maryam
- #20162 feat(component): resolve nativeDragZone record-field templates synchronously · @neo-gemini-maryam
- #20197 test(util): pin Neo.util.HashHistory behavior · @calude-bot
- #20200 fix(util): keep cold history reads unregistered · @neo-gpt-euclid
- #20202 feat(data): Support array bracket paths in RecordFactory field mappings · @neo-gemini-maryam
- #20204 feat(form): add Container.setErrors(errors, suspendEvents) · @neo-gemini-maryam
- #20205 feat(list): add orderByRow_ config to list.plugin.Animate · @neo-gemini-maryam
- #20206 fix(form): batch Text.reset() and updateError() into a single vdom update · @neo-gemini-maryam
- #20207 feat(manager): support node attribute selectors in DomEvent delegation · @neo-gemini-maryam
- #20209 fix(component): pass mapId to destroyMarkers and serialize Record fields in GoogleMaps · @neo-gemini-maryam
- #20210 feat(component): add recordChange listener for GoogleMaps markerStore · @neo-gemini-maryam
- #20213 fix(data): TreeStore clear() and reloads stay linear in the visible node count · @neo-opus-grace
- #20214 feat(state): default StateProvider store entries to Neo.data.Store · @neo-gemini-maryam
- #20216 fix(component): re-render GoogleMaps markerStore markers on remount · @neo-gemini-maryam
- #20218 fix(collection): splice(0, count, items) keeps the items it adds · @neo-opus-grace
- #20221 fix(component): pass mapId to destroyMarkers and spread Record#toJSON() in OpenStreetMaps wrapper · @neo-gemini-maryam
- #20230 feat(data): assign temporary negative record ids in Store · @neo-gemini-maryam
- #20231 fix(vdom): settle a departed window's first render quietly · @neo-opus-ada
- #20233 feat(form): add fieldDefaults config to form.Container · @neo-gemini-maryam
- #20234 feat(component): allow Toast to be both closable and auto-dismissed after removeDelay · @neo-gemini-maryam
- #20235 fix(list): combine onStoreFilter and sortBaseList in list.plugin.Animate · @neo-gemini-maryam
- #20240 feat(container): clear item context in removeAt when not destroyed · @neo-gemini-maryam
- #20242 feat(collection): Filter#createEvaluator reads the filter's configs once per scan · @neo-opus-grace
- #20243 feat(form): move required_ config and afterSetRequired hook to form.field.Base · @neo-gemini-maryam
- #20244 fix(tree): filter tree.List per item and collapse unmatched child folders · @neo-gemini-maryam
- #20245 feat(component): support fewer than 3 items and dynamic store changes in Carousel · @neo-gemini-maryam
- #20246 fix(calendar): refresh MonthComponent headerHeight on baseFontSize change · @neo-gemini-maryam
- #20248 test(form): add component-based test spec for form.field.Switch · @neo-gemini-maryam
- #20249 test(form): add component-based test spec for form.field.FileUpload · @neo-gemini-maryam
- #20250 test(form): add component-based test spec for form.field.Email · @neo-gemini-maryam
- #20251 feat(component): move Carousel CSS variables into theme variable files · @neo-gemini-maryam
- #20252 feat(component): honor sibling minWidth and minHeight during Splitter drag · @neo-gemini-maryam
- #20255 fix(component): a code span inside a Markdown link stays part of that link · @neo-opus-grace
- #20259 fix(data): TreeStore#filter selects active filters via Filter#effective · @neo-gemini-julia
- #20263 feat(button): support per-UI borders on SplitButton · @neo-gemini-maryam
- #20268 fix(data): Store#filter and Store#isFilteredItem gate soft hydration via Filter#effective · @neo-gemini-julia
- #20269 feat(form): add form.field.IBAN with per-country regex validation · @neo-gemini-maryam
- #20276 fix(collection): resolve dotted property paths in Sorter, Collection, and TreeStore · @neo-gemini-julia
- #20281 feat(list): add String.escapeRegExp and escape list and tree search highlights · @neo-gemini-maryam
- #20287 fix(button): a url set after construction opens per urlTarget · @neo-opus-ada
- #20288 feat(canvas): GraphScene draws node labels and flies its camera to a node · @neo-opus-vega
- #20289 fix(collection): resolve dotted filter paths via Sorter.getValue · @neo-gemini-maryam
- #20290 test(util): pin ClassSystem.beforeSetInstance normalization branches · @neo-gemini-maryam
- #20292 test(calendar): pin Events#getDayRecords single-day filtering and sorting · @neo-gemini-maryam
- #20293 test(util): pin Css#insertRules and Css#deleteRules main-thread forwarding · @neo-gemini-maryam
- #20297 fix(form): accept balanced international phone groups · @neo-gpt-euclid
- #20298 feat(data): re-sort records after opted-in edits · @neo-gpt-sophie
- #20300 chore(core): replace remaining hasOwnProperty calls with Object.hasOwn · @neo-gemini-julia
- #20302 test(menu): ContextMenuNL reads the leaf close from the worker · @neo-opus-ada
- #20304 fix(calendar): compensate MonthComponent downward wheel scroll and disable scroll anchoring · @neo-gemini-maryam
- #20305 feat(manager): isolate focus history by window · @neo-gpt-euclid
- #20311 feat(form): show live character counts on text fields · @neo-gpt-sophie
- #20317 feat(canvas): GraphScene's near look: a mark floor, names in focus, a crossfade · @neo-opus-vega
- #20322 feat(form): show required group errors once · @neo-gpt-sophie
- #20326 feat(calendar): add 12h (am/pm) and 24h mode to TimeAxisComponent · @neo-gemini-maryam
- #20331 feat(calendar): update MonthComponent wheel-end header date and snap to closest row · @neo-gemini-maryam
- #20334 feat(plugin): bind Responsive to matching Viewport resize on mount and remove Neo.Responsive · @neo-gemini-maryam
- #20335 feat(manager): add multi-window and per-app running support to ToastManager · @neo-gemini-maryam
- #20336 feat(list): link useCheckBoxes state to record checkedField · @neo-gemini-maryam
- #20342 feat(button): change editRoute config default value to false · @neo-gemini-maryam
- #20343 feat(component): show Gallery and Helix loading feedback · @neo-gpt-sophie
- #20360 feat(calendar): trigger infinite scrolling on week view drag-scroll edges · @neo-gemini-maryam
- #20369 feat(calendar): add month view EventDragZone and DragDrop plugin · @neo-gemini-maryam
- #20382 fix(core): retire instance-owned delays on destruction · @neo-gpt-sophie
- #20383 feat(form,component): add WAI-ARIA datepicker dialog semantics to DateField and DateSelector · @neo-gemini-maryam
- #20385 docs(data): explain Stores behind tabular views · @neo-gpt-sophie
- #20395 fix(calendar): destroy eventDragZone when week DragDrop plugin destroys · @neo-gemini-maryam
- #20400 feat(list): animate dynamic membership across pooled wrappers · @neo-gpt-sophie
- #20406 fix(form): preserve shared Store record-change routing · @neo-gpt-sophie
- #20413 fix(gallery): defer initial selection until its record exists · @neo-gpt-sophie
- #20416 fix(component): destroy(true) takes a functional component out of its parent too · @neo-opus-ada
- #20422 test(calendar): the month drag e2e waits for the view's scroll · @neo-opus-ada
- #20423 fix(core): a nested Effect run no longer ends an outer tracking pause · @neo-opus-vega
- #20430 fix(list): restore checked selection when re-enabled · @neo-gpt-emmy
- #20434 feat(data): add opt-in Pipeline stage telemetry · @neo-gpt-euclid
- #20439 fix(data): dispose Pipeline counterparts through the worker owner · @neo-gpt-euclid
- #20440 fix(component): clear Clock dimensions when size becomes nonnumeric · @neo-gpt-euclid
- #20443 feat(form): add Store-backed native Select field · @neo-gpt-sophie
- #20449 docs(store): add the practical shared-data guide · @neo-gpt-sophie
- #20456 fix(component): render legend icons as native nodes · @neo-gpt-emmy
- #20457 fix(data): a Store releases only the Model it created · @neo-opus-ada
- #20458 fix(form): an open ComboBox picker repaints a Store record edit · @neo-opus-ada
- #20462 feat(data): cache completed Pipeline reads · @neo-gpt-euclid
- #20469 fix(form): keep Display inputs readonly and pin field presets · @neo-gpt-euclid
- #20473 fix(data): send Fetch request headers · @neo-gpt-sophie
- #20483 feat(component): month and year selector for DateSelector · @neo-opus-ada
- #20487 feat(data): compose awaited Pipeline interceptors · @neo-gpt-sophie
- #20488 feat(canvas): GraphScene's stats say when a frame is owed, and its e2e waits for none · @neo-opus-vega
- #20490 fix(data): Xhr composes params into a URL that has a query or fragment · @neo-opus-ada
- #20536 fix(container): a component moved across parents renders in its new parent · @neo-opus-grace
- #20559 fix(store): preserve streaming state across pipeline reads · @neo-gpt-sophie
- #20561 fix(core): remove Function listeners by identity · @neo-gpt-sophie
- #20569 fix(data): a re-added tree node keeps expanding once the store sorts · @neo-opus-vega
- #20578 fix(calendar): skip event date commit when drag is cancelled via Escape · @neo-gemini-maryam
- #20640 fix(navigator): skip a subscribe whose eventSource is gone · @neo-opus-ada
- #20650 fix(render): the DOM API renderer creates svg and math subtrees in their namespace · @neo-opus-grace
CI, build and tests (101)
- #20094 test: add CountryFlags unit tests · @Athmika08
- #20096 fix(seo): strip doubled blog/ prefix from portal and sitemap blog routes · @neo-gemini-julia
- #20097 fix(seo): exclude raw ticket and PR archives from primary sitemap and llms.txt · @neo-gemini-julia
- #20102 feat(seo): segment sitemap into core/archive index and emit llms-full.txt and llms-all.txt · @neo-gemini-julia
- #20112 fix(deps-dev): bump fast-uri from 3.1.8 to 3.1.9 · @dependabot
- #20120 fix(deps-dev): bump the all-deps group with 2 updates · @dependabot
- #20121 fix(deps-dev): bump neo-agent-skills from 0.1.56 to 0.1.61 · @dependabot
- #20122 fix(deps): bump the actions group with 2 updates · @dependabot
- #20136 fix(ai): an app that registers after its Neural Link socket opens announces its window · @neo-opus-grace
- #20137 fix(build): a package root inside node_modules is a dependency build for prepare · @neo-opus-grace
- #20138 fix(build): the dev server's theme check inspects the root it serves, silent where it builds no theme · @neo-opus-grace
- #20143 fix(test): route neo-config.json before beforeEach navigation in lockedColumns e2e · @neo-gemini-julia
- #20150 test(e2e): the moveItem witness brackets the Workspace's own FLIP signal · @neo-opus-ada
- #20151 test(e2e): GridViewFocus reads each click's own pointer stamp · @neo-opus-ada
- #20155 fix(deps-dev): bump webpack from 5.112.1 to 5.112.2 in the all-deps group · @dependabot
- #20156 fix(deps-dev): bump neo-agent-skills from 0.1.61 to 0.1.64 · @dependabot
- #20157 test: add currency field unit tests · @SimonGebru
- #20158 test(e2e): three pop-out round trips leave the App worker only the main window's application · @neo-opus-vega
- #20163 fix(deps-dev): bump neo-agent-skills from 0.1.64 to 0.1.70 · @dependabot
- #20164 fix(deps): bump the actions group with 2 updates · @dependabot
- #20165 fix(deps): bump qs from 6.16.0 to 6.17.0 · @dependabot
- #20171 fix(deps-dev): bump neo-agent-skills from 0.1.70 to 0.1.73 · @dependabot
- #20172 fix(deps): bump the actions group with 2 updates · @dependabot
- #20174 ci(workflows): run neo's agent review check from the shared Skills workflow · @neo-opus-vega
- #20179 fix(deps): raise the DOMPurify floor to 3.4.17 and lock body-parser 2.4.0 · @neo-opus-ada
- #20180 ci(workflows): run the Brain's guide lint over neo's guides again · @neo-opus-ada
- #20181 fix(deps-dev): bump the all-deps group with 4 updates · @dependabot
- #20182 fix(deps-dev): bump neo-agent-skills from 0.1.73 to 0.1.78 · @dependabot
- #20183 fix(deps): bump the actions group with 2 updates · @dependabot
- #20191 test: add Toast manager unit tests · @Toufiqul-27
- #20194 fix(deps-dev): bump sass from 1.106.1 to 1.107.0 in the all-deps group · @dependabot
- #20195 fix(deps-dev): bump neo-agent-skills from 0.1.78 to 0.1.82 · @dependabot
- #20196 fix(deps): bump the actions group with 3 updates · @dependabot
- #20201 test(rpc): pin API registration precedence · @neo-gpt-euclid
- #20208 fix(build): compute depth-aware relative paths in createExample · @neo-gemini-maryam
- #20219 feat(build): add container.Viewport to createClass guessBaseClass() · @neo-gemini-maryam
- #20227 fix(deps-dev): bump the all-deps group with 2 updates · @dependabot
- #20228 fix(deps-dev): bump neo-agent-skills from 0.1.82 to 0.1.84 · @dependabot
- #20229 fix(deps): bump the actions group with 3 updates · @dependabot
- #20232 feat(build): ask to generate matching data.Store when creating data.Model · @neo-gemini-maryam
- #20236 fix(build): emit :root .neo- selectors in buildScripts/create/scss.mjs · @neo-gemini-maryam
- #20237 fix(build): merge framework and workspace theme folders in buildThemes · @neo-gemini-maryam
- #20238 fix(build): merge framework and workspace themes in createApp · @neo-gemini-maryam
- #20257 feat(build): prompt to create matching data.Model when generating data.Store · @neo-gemini-maryam
- #20262 feat(build): scaffold ViewportController in create-app · @neo-gemini-maryam
- #20265 feat(build): compile SCSS shipped inside installed packages · @neo-gemini-julia
- #20273 fix(deps-dev): bump ws from 8.22.0 to 8.22.1 in the all-deps group · @dependabot
- #20274 fix(deps): bump the actions group with 3 updates · @dependabot
- #20294 fix(deps-dev): bump parse5 from 8.0.1 to 8.1.0 in the all-deps group · @dependabot
- #20295 fix(deps-dev): bump neo-agent-skills from 0.1.84 to 0.1.86 · @dependabot
- #20296 fix(deps): bump the actions group with 3 updates · @dependabot
- #20314 fix(build): keep rebased webpack context requests POSIX-relative on Windows · @neo-gemini-julia
- #20324 feat(build): prompt for controller & stateProvider when generating views · @neo-gemini-julia
- #20332 feat(ci): the scope classifier stops admitting e2e tiers for paths they cannot reach · @neo-opus-grace
- #20341 feat(ci): PR Baseline cancels the run for a superseded head · @neo-opus-grace
- #20346 feat(ci): collapse review-admission mergeability into a single job · @neo-gemini-julia
- #20349 feat(ci): consolidate repo-local lint and check workflows · @neo-gemini-julia
- #20354 fix(ci): quote publish job name in review-admission-mergeability.yml · @neo-gemini-julia
- #20355 feat(ci): run the unit family in one prepared job · @neo-gpt-emmy
- #20357 fix(test): restore Docs hierarchy addon fixture state · @neo-gpt-sophie
- #20362 ci(e2e): ruled-out e2e tiers start no runner · @neo-opus-grace
- #20365 feat(build): scaffold workspace themes from existing skins · @neo-gpt-euclid
- #20367 test(e2e): the resizeSplit glide witness brackets its own producer · @neo-opus-grace
- #20368 ci(test): a dev push diffs from its workflow's last completed run · @neo-opus-grace
- #20378 fix(build): pin consumer toolchain to lock resolutions · @neo-gpt-euclid
- #20381 feat(ai): ai.Client starts transport only when asked; tests boot the registry alone · @neo-opus-vega
- #20386 test(e2e): name NEO_NL_PORT when a fleet Bridge refuses the neuralLink fixture · @anasdahani220
- #20391 feat(test): dispatch neuralLink fixture to the page's dedicated App Worker · @neo-gemini-maryam
- #20392 test(build): prove AI test entry stays out of production artifacts · @neo-gemini-maryam
- #20396 test(ai): add off-socket NL dispatch refusal, regression, conflict and lifetime specs · @neo-gemini-maryam
- #20404 feat(test): select adapter-eligible single-app NL specs without Brain checkout · @neo-gemini-maryam
- #20410 feat(ci): provision the transaction archive e2e tier · @neo-gpt-euclid
- #20411 ci(test): a pull request runs only the e2e specs its change can reach · @neo-opus-grace
- #20435 feat(build): add checked file and folder relocation · @neo-gpt-sophie
- #20441 fix(deps-dev): bump the all-deps group with 2 updates · @dependabot
- #20442 fix(deps-dev): bump neo-agent-skills from 0.1.86 to 0.1.90 · @dependabot
- #20450 fix(ci): Engine tests never talk to a Memory Core · @neo-opus-grace
- #20461 test(nl): run single-page SharedWorker specs off-socket in the engine tier · @neo-opus-vega
- #20463 test(layout): cover Fit geometry and class cleanup · @neo-gpt-sophie
- #20475 feat(build): seat:start rebuilds stale development themes · @RClaudiuM
- #20485 test(unit): convert file URLs and paths portably in two specs · @neo-opus-ada
- #20504 fix(build): theme preflight messages name no caller · @wanjinhao1
- #20513 test(email): wait for a rendered inbox before scrolling · @neo-gpt-sophie
- #20522 ci(e2e): the engine tier's shards split by measured time, as the Brain tier's do · @neo-opus-grace
- #20580 chore(build): delete the engine's concept JSONL copy and its package carve-out · @neo-opus-vega
- #20584 ci(e2e): the Brain-gated tier retires; its specs run off-socket or locally · @neo-opus-grace
- #20596 ci(components): a ruled-out components tier starts no runner, behind one context · @neo-opus-grace
- #20598 ci(baseline): the repository's guards run as one required guards context · @neo-opus-vega
- #20602 fix(build): the production main bundle keeps import.meta.url a runtime value · @neo-opus-vega
- #20607 ci(deps): Dependabot runs every day, weekends included · @neo-opus-vega
- #20608 fix(test): align launch defaults with the dependency update · @dependabot
- #20609 chore(deps-dev): bump neo-agent-skills from 0.1.90 to 1.1.0 · @dependabot
- #20610 chore(deps): bump the actions group with 2 updates · @dependabot
- #20612 ci(guides): Engine's guides run through the shared baseline's guide lint, so no job checks out the Brain · @neo-opus-grace
- #20615 fix(test): the off-socket adapter releases a held SharedWorker session before its page re-boots · @neo-opus-grace
- #20617 fix(build): a claim holds for 7 days from the claimant's latest comment, and CONTRIBUTING says so · @neo-opus-vega
- #20619 ci(deps): Dependabot proposes each Skills workflow release on its next run, not three days later · @neo-opus-grace
- #20621 feat(test): bind exact worker ids across browser contexts · @neo-gpt-euclid
- #20628 fix(deps): bump the actions group with 2 updates · Dependabot
- #20643 feat(build): test runs refuse an install off the lockfile · @neo-opus-ada
- #20645 fix(deps-dev): bump sass from 1.107.1 to 1.108.0 in the all-deps group · Dependabot
Docs, guides, blog and portal (40)
- #20153 docs(identity): the front door reads as of October 2026 · @neo-opus-ada
- #20168 docs(neural-link): the capability matrix's Engine copy goes, and its links point at the Brain's · @neo-opus-ada
- #20176 docs(agentos): add Stage trigger line and compact AGENTS.md below Antigravity rule limit · @neo-gemini-maryam
- #20186 docs(blog): the main thread is the wrong place for a data grid · @neo-opus-grace
- #20193 docs(blog): state the worker's mechanism, not an unmeasured 300 ms sort · @neo-opus-grace
- #20215 feat(docs): check only selected class by default in HierarchyTreeList · @neo-gemini-maryam
- #20224 feat(docs): add full-name tooltips to Docs app tab headers · @neo-gemini-maryam
- #20226 docs(blog): persistent memory for AI coding agents, pulled over MCP · @neo-opus-grace
- #20239 docs(guidelines): replace chronologically with alphabetically · @neo-gemini-maryam
- #20272 feat(docs): adjust Docs theme button texts to initial theme · @neo-gemini-maryam
- #20279 feat(portal): add API Docs link and route handling to learning section · @neo-gemini-maryam
- #20280 docs(blog): mark the memory post as part 1 of 8 in its series · @neo-opus-grace
- #20303 docs(guides): CustomEvents' procedural snippets call on() · @neo-opus-ada
- #20315 fix(portal): use secondary button CSS variables for hero GitHub button · @neo-gemini-julia
- #20321 docs(blog): give the persistent-memory post a Medium-ready title and subtitle · @neo-opus-grace
- #20327 feat(docs): show mixin sources and members · @neo-gpt-sophie
- #20361 feat(docs): separate application classes from API navigation · @neo-gpt-sophie
- #20405 docs(roadmap): Engine 13.4 replaces the shipped 13.3 section · @neo-opus-ada
- #20412 feat(portal): replace obsolete services with Connect · @neo-gpt-emmy
- #20415 feat(examples): demonstrate deeply nested component state · @neo-gpt-sophie
- #20464 docs(roadmap): 13.4 aims for under 25 open issues and cuts this weekend · @neo-opus-grace
- #20467 docs(gettingstarted): state the Node minimum and create-app's options · @neo-opus-ada
- #20468 docs(identity): spell out gated recursive self-improvement · @neo-gpt-sophie
- #20491 docs(tutorial): use the keyless shared-store map · @neo-gpt-sophie
- #20507 docs(learn): rewrite README.md and UsingTheseTopics.md for three readers · @neo-gemini-julia
- #20509 docs(learn): sweep over-claims and stale MCP topology in benefits/body · @neo-gemini-julia
- #20519 fix(learn): restore conviction and platform-first positioning across benefits/body and README · @neo-gemini-julia
- #20540 docs(blog): debug a reactive Clock through the Neural Link · @neo-gpt-emmy
- #20542 docs(learn): the multi-window and features pages show the whole platform · @neo-opus-grace
- #20544 docs(learn): the comparisons stop sending business-app teams back to React, Vue and Angular · @neo-opus-grace
- #20545 docs(readme,learn): remove front-door niche gatekeeping and 5-MCP list across README and CoreSkills · @neo-gemini-julia
- #20549 docs(learn): Effort.md leads with where Neo's curve wins, not its cost · @neo-opus-grace
- #20557 docs(contributing): keep the lane-selection route current · @neo-gpt-euclid
- #20563 docs(blog): context compaction recovery for AI coding agents, part 2 of the memory series · @neo-opus-grace
- #20574 docs(blog): part 2's origin paragraph matches its receipts, with a dated reference · @neo-opus-grace
- #20594 feat(portal): a Videos tab with click-to-play YouTube facades · @neo-opus-ada
- #20603 fix(portal): section tabs fold overflow behind one control · @neo-opus-ada
- #20620 feat(docs): class tabs get a route, so a reload restores them · @neo-opus-ada
- #20631 test(portal): read the news tab bar while its menu is open · @neo-opus-ada
- #20638 feat(examples): add Header Groups theme controls · @neo-gpt-sophie
Other (13)
- #20134 fix(agentos): the lead-role baton wakes in AGENTS_ATLAS.md · @neo-fable-mnemosyne
- #20154 fix(worker): a departed window's application is destroyed after its disconnect · @neo-opus-vega
- #20283 feat(splitter): unify multi-sibling and conserved-pair minSize bounds · @neo-gemini-maryam
- #20318 fix(highlight): share resources across consumers · @neo-gpt-emmy
- #20323 feat(functional): add useMemo hook for effect memoization · @neo-gemini-julia
- #20337 feat(code): render editable Mermaid previews · @neo-gpt-euclid
- #20419 fix(codex): pass the Brain root to manual Neural Link · @neo-gpt-emmy
- #20426 feat(hooks): a PreToolUse guard refuses Bash file writes · @neo-opus-ada
- #20447 feat(email): complete retained multi-window demo · @neo-gpt-sophie
- #20448 fix(dialog): show and hide follow the component visibility contract · @neo-opus-grace
- #20471 fix(config): point manual Neural Link entries at Brain · @neo-gpt-euclid
- #20572 fix(theme): neo-dark's grays take the theme's own hue · @neo-opus-vega
- #20651 feat(theme): reveal Header Groups switches after capture · @neo-gpt-sophie
All changes delivered in 1 atomic commit: ffa130c

