Agent skill

Memory And Disposal

by andymai in andymai/brepjs

This skill should be used when managing WASM handle lifetimes or hunting memory leaks in brepjs — when a task mentions "createHandle() without using keyword risks WASM memory leak"…

Apache-2.0Auto-check passedDevelopment

Install Memory And Disposal

skills CLI
$ npx skills add andymai/brepjs --skill memory-and-disposal -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install andymai/brepjs memory-and-disposal --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/andymai/brepjs.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.claude/skills/memory-and-disposal .claude/skills/memory-and-disposal && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
memory-and-disposal
GitHub stars
115
Token cost
~3.1k tokens
SKILL.md length
1,170 words
Files
2 (incl. references)
Skills in repo
21
Repo updated
First seen
Licence
Apache-2.0

At a glance

This skill should be used when managing WASM handle lifetimes or hunting memory leaks in brepjs — when a task mentions "createHandle() without using keyword risks WASM memory leak"…

  • Works in 3 steps: resetDisposalStats() before the suspect… → Run it (ideally in a loop to amplify… → getDisposalStats() after.
  • Tasks that involve Performance optimization
  • SKILL.md covers Mental model, The three tools — when to use…, The gate:… and Escape hatches and long-lived…, plus 5 more sections
  • Calls npm

What it does

Memory And Disposal is an agent skill from andymai/brepjs. This skill should be used when managing WASM handle lifetimes or hunting memory leaks in brepjs — when a task mentions "createHandle() without using keyword risks WASM memory leak", "require-using-for-handles", "Shape handle has been disposed", "kernel handle has been disposed", "memory grows / heap keeps climbing", "leaking shapes", "getDisposalStats / gcCollected", "DisposalScope register vs track", "withScopeResult", "kernelCallScoped", "registerForCleanup", "returned shape from withScope is disposed", or…

Its SKILL.md is about 3.1k tokens, which your agent loads only when the skill is triggered. The skill folder holds 2 other files, including reference files (for example `references/kernel-memory-models.md`).

It sits in Development, covering Performance optimization. It works with WebAssembly. The repository describes itself as: Web CAD library with exact B-Rep geometry. The licence is Apache-2.0.

When your agent uses it

  • Tasks that involve Performance optimization

Example prompts

  • “createHandle() without using keyword risks WASM memory leak”
  • “require-using-for-handles”
  • “Shape handle has been disposed”
  • “/memory-and-disposal”

Workflow steps

3 steps, taken from the first numbered list in SKILL.md.

  1. resetDisposalStats() before the suspect operation.
  2. Run it (ideally in a loop to amplify churn).
  3. getDisposalStats() after.

What it can do on your machine

Read from SKILL.md and the folder at commit 2907fb1. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • npm

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use npm, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Memory And Disposal loads about 3.1k tokens when it runs, and up to ~4.2k if it reads all its reference files. Until then it costs about 151 tokens; SKILL.md has 1,170 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~151
When it runs · the whole SKILL.md, loaded when a task matches
~3.1k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~4.2k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from andymai/brepjs at commit 2907fb1, republished under its Apache-2.0 licence (© andymai). 1,170 words, ~3,076 tokens.

Download SKILL.mdSave it as .claude/skills/memory-and-disposal/SKILL.md (or your agent's skills folder). This skill also uses 1 other file; get the full folder from GitHub.
name
memory-and-disposal
description
This skill should be used when managing WASM handle lifetimes or hunting memory leaks in brepjs — when a task mentions "createHandle() without using keyword risks WASM memory leak", "require-using-for-handles", "Shape handle has been disposed", "kernel handle has been disposed", "memory grows / heap keeps climbing", "leaking shapes", "getDisposalStats / gcCollected", "DisposalScope register vs track", "withScopeResult", "kernelCallScoped", "registerForCleanup", "returned shape from withScope is disposed", or deciding how to clean up kernel temporaries in a new *Fns.ts function.

WASM memory management and disposal

Mental model

WASM objects are not visible to the JS garbage collector — a leaked shape grows WASM linear memory silently. Every branded shape (Vertex, Edge, Wire, Face, Shell, Solid, CompSolid, Compound) IS a disposable handle: src/core/shapeTypes.ts wraps each via createHandle() (src/core/disposal.ts). Cleanup has one primary rule and one safety net:

  • Primary: dispose deterministically with using / Symbol.dispose / DisposalScope. This is the plan.
  • Safety net: a FinalizationRegistry (disposal.ts) frees handles that were never disposed — non-deterministic, GC-timed, never something to rely on. Environments lacking it get a no-op stub plus a console.warn (disposal.ts).

User-facing prose lives in docs/memory-management.md (the four mechanisms, using examples, LIFO, heap-monitoring snippets, three common leak patterns) and the maintainer deep-dive in src/core/README.md. This skill adds what those lack: the tool-selection table, the pattern-checker rule, the kernel-dependent free semantics, and the leak-hunting workflow. Do not re-read those two docs for basics — point users to them.

using requires "target": "ES2022" + "lib": ["ES2022", "ESNext.Disposable"]; the repo tsconfig.json:3,6 already sets this.

The three tools — when to use each

SituationToolNotes
One temporary, freed at end of blockusing x = createHandle(...)Or using x = someFn() for any branded shape
Several temporaries in one functionusing scope = new DisposalScope() + scope.register(...)LIFO disposal; see ordering rule
A Result-returning *Fns.ts op that allocateskernelCallScoped(fn, code, msg) or withScopeResult(fn)Scope disposed on Ok, Err, AND throw
Async Result opwithScopeResultAsync(fn)Note the intentional return await
using for a single handle
ts
using box = box(1, 1, 1);

Any branded shape works directly this way, since every shape is a ShapeHandle. Accessing .wrapped after disposal throws 'Shape handle has been disposed' (disposal.ts); the KernelHandle variant throws 'kernel handle has been disposed' (disposal.ts). Double-dispose is safe — dispose is idempotent and inner delete() failures are swallowed.

DisposalScope — register vs track, and LIFO

Two registration methods, both return their argument for inline use:

  • scope.register(resource) — for anything Deletable ({ delete() }); calls .delete() on dispose (disposal.ts).
  • scope.track(disposable) — for anything with [Symbol.dispose] (branded shapes, Curve2DHandle); calls [Symbol.dispose]() (disposal.ts).

DisposalScope disposes in LIFO (reverse-registration) order (disposal.ts). The ordering rule (also a CLAUDE.md gotcha): register a dependency AFTER its dependee, so the dependent is disposed first. If B is built from A, register A first and B second.

Real code overwhelmingly uses the scope directly — using scope = new DisposalScope() then scope.register(...) (e.g. src/sketching/draw3d.ts, src/operations/threadFns.ts, src/gear/gearFns.ts). Prefer this idiom.

Scope helpers for Result-returning ops

kernelCallScoped(fn, code, message) (src/core/kernelCall.ts) creates a scope, runs fn, and disposes deterministically after return or throw — the canonical wrapper for a *Fns.ts op that needs intermediate kernel allocations and returns Result<AnyShape>:

ts
return kernelCallScoped(
  (scope) => {
    const axis = scope.register(makeKernelAx1(origin, dir));
    return getKernel().revolveVec(shape.wrapped, axis);
  },
  BrepErrorCode.REVOLUTION_NOT_3D,
  'Revolution failed'
);

withScopeResult(fn) (disposal.ts) is the same scope discipline for any Result-returning function. withScopeResultAsync(fn) (disposal.ts) is the async variant — its body is return await fn(scope). The await is load-bearing: using disposes synchronously at end of block, so without await the scope would dispose before the promise settles. Keep the await.

These helpers are exported and documented but rarely called directly in src/; present them as available conveniences, not the dominant convention.

The gate: require-using-for-handles

The pattern checker (scripts/check-patterns.ts, severity error) flags any createHandle() / createKernelHandle() call not bound with using. Message: "createHandle() without \using` keyword risks WASM memory leak.`"

Excused positions (check-patterns.ts):

  • using x = createHandle(...)
  • return createHandle(...) — caller owns lifetime
  • direct argument to another call, e.g. scope.register(createHandle(...))
  • property assignment { k: createHandle(...) } or array literal [createHandle(...)]

It does not catch handles nested in ternaries/sub-expressions — those slip through. Scan scope is src/**/*.ts only (tests and scripts exempt, check-patterns.ts).

Inline disable (line above or inline):

ts
// brepjs-patterns-disable: require-using-for-handles

Real use: createCurve2DHandle in src/core/curve2dHandle.ts, which returns the handle for the caller to own.

Where it runs: npm run check:patterns, pre-commit via lint-staged on staged src/**/*.ts, and CI's quality job. The baseline .pattern-baseline.json contains zero require-using-for-handles entries (see the quality-gates skill for the current baseline composition) — so ANY new violation of this rule fails the gate immediately; there is no baseline slack to absorb it. For baseline mechanics and the general pattern-checker workflow, see the quality-gates skill.

Show full SKILL.md (529 more words)Show less

Escape hatches and long-lived objects

  • Return a shape from a scope — do not register it. A shape returned from withScope/DisposalScope while intermediates are registered stays valid and meshable after the scope disposes. Registered intermediates are freed; the returned one is not (regression tests/withScope-disposal.test.ts, issue #723). Registering the returned value is a use-after-dispose bug.
  • Object must outlive its creating function (e.g. closure-captured kernel handle): use registerForCleanup(owner, deletable) / unregisterFromCleanup(deletable) (disposal.ts) — FinalizationRegistry cleanup keyed on owner. Used by Curve2D (src/2d/lib/curve2D.ts).
  • Validate liveness at a boundary: isLive(handle) (disposal.ts) is a named !handle.disposed. Pattern: if (!isLive(h)) return err(...).
  • Non-shape kernel objects: createKernelHandle(ocObj) for anything Deletable (.value getter instead of .wrapped). Curve2DHandle (src/core/curve2dHandle.ts) shows the branded-wrapper pattern, including synthesizing a no-op Deletable for arena handles that lack delete().

Kernel-dependent reality (critical for leak hunting)

The disposal API is uniform but the WASM-side effect of .delete() depends on the active kernel. Under the default occt-wasm kernel, a handle's delete() is a no-op — the shape lives in a WASM arena and is freed only by getKernel().dispose(shape.wrapped) → k.release(id), or releaseAll() on kernel teardown. Under Embind kernels (brepjs-opencascade) .delete() genuinely frees. So using on a branded shape always gives use-after-dispose protection and stats, but only frees arena memory on Embind. This split is the single most common source of confusion when a leak reproduces on one kernel and not another.

Full file:line breakdown, the arena vs Embind table, Embind vector cleanup, and internal getKernel().dispose() call sites are in references/kernel-memory-models.md. Read it before diagnosing a kernel-specific leak.

Finding leaks

getDisposalStats() / resetDisposalStats() (disposal.ts) return { liveHandles, peakHandles, gcCollected, scopeEnters, scopeExits }. Workflow:

  1. resetDisposalStats() before the suspect operation.
  2. Run it (ideally in a loop to amplify churn).
  3. getDisposalStats() after.

Symptom → meaning:

ReadingMeaning
gcCollected > 0Handles were reclaimed by the FinalizationRegistry — code forgot to dispose them. Each is a missed using.
peakHandles high in a loopHandles accumulate within an iteration; move disposal inside the loop body (a using per iteration or a per-iteration scope).
liveHandles non-zero at restSuggestive, but do not assert absolute values — the FinalizationRegistry adjusts it asynchronously after a synchronous reset, so it can even go negative for later readers (tests/disposalStats.test.ts). Use it as a trend signal, not a hard number.

For heap-monitoring snippets (performance.memory, WASM heap size), see docs/memory-management.md.

Testing disposal code

  • tests/disposal.test.ts is skipped on occt-wasm — describe.skipIf(shouldSkipSuite('disposal')) — because it wraps raw Embind oc objects that the default kernel does not expose. Do not add default-kernel coverage there.
  • Write kernel-agnostic disposal tests through the public API, like tests/disposalStats.test.ts (exercises stats, isLive, withScopeResult without touching oc).
  • Use tests/withScope-disposal.test.ts as the exemplar for return-value lifecycle assertions.

General test skeleton, geometry assertions, and kernel-skip mechanics are in the writing-tests skill.

History (recognition only)

gcWithScope, gcWithObject, and localGC were removed in commit d7e33e50 (#331). If old snippets reference them, they are gone — replace with using/DisposalScope.

Additional resources

  • references/kernel-memory-models.md — per-kernel free semantics (occt-wasm arena vs Embind .delete()), Embind vector cleanup, internal getKernel().dispose() call sites, with file:line anchors.
  • docs/memory-management.md — user-facing cleanup guide + heap monitoring.
  • src/core/README.md (disposal section) — maintainer deep-dive with API signatures and rationale.
  • Sibling skills: quality-gates (pattern-checker baseline workflow), kernel-abstraction (the .wrapped / getKernel() contract), writing-tests (test skeleton + kernel skips), result-error-handling (kernelCall / error codes), adding-operations (where cleanup fits in a new *Fns.ts).

© andymai, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 1 other file (references) in .claude/skills/memory-and-disposal of andymai/brepjs.

  • SKILL.md
  • references/kernel-memory-models.md

Open the folder on GitHubat commit 2907fb1

Compare with similar skills

Memory And Disposal next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Memory And Disposal compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Memory And Disposal this skillandymai/brepjs115—~3.1kAutomated safety check: PassApache-2.0
Profiling Wado Compilerwado-lang/wado117—~2.9kAutomated safety check: NotesMIT
Wado Performancewado-lang/wado117—~7.5kAutomated safety check: PassMIT
Code Review ChecklistshareAI-lab/learn-claude-code78k4 repos~1.1kAutomated safety check: PassMIT
LLM Torch Profiler Analysissgl-project/sglang37k2 repos~6.4kAutomated safety check: PassApache-2.0
Pycrazyguitar/pysheeet8.2k—~886Automated safety check: PassMIT

Similar skills

  • Profile the native Rust wado binary (compile/serve/run) for host-side bottlenecks — CPU with a sampling profiler, memory with the span trace's RSS and valgrind DHAT.

    117 GitHub stars~2.9k tokensUpdated today
    DevelopmentAuto-check: notes
  • Wado Performance

    wado-lang/wado

    Analyze and improve the runtime speed of a Wado program's compiled guest Wasm — profile hot functions, read the generated WIR for allocations and copies, reason about the WasmGC cost model, and…

    117 GitHub stars~7.5k tokensUpdated today
    DevelopmentAuto-check passed
  • Code Review Checklist

    shareAI-lab/learn-claude-code

    Reviews code against a five-part checklist covering security, correctness, performance, maintainability and testing, and reports findings in a fixed format.

    78k GitHub starsUsed in 4 repos~1.1k tokens
    DevelopmentAuto-check passed
  • LLM Torch Profiler Analysis

    sgl-project/sglang

    Unified LLM torch-profiler triage skill for sglang, vllm, TensorRT-LLM, and TokenSpeed.

    37k GitHub starsUsed in 2 repos~6.4k tokens
    DevelopmentAuto-check passed
  • Py

    crazyguitar/pysheeet

    Comprehensive Python programming reference covering syntax, concurrency, networking, databases, ML/LLM development, and HPC.

    8.2k GitHub stars~886 tokensUpdated 3 days ago
    DevelopmentAuto-check passed
  • Cmux Debugging Guide

    manaflow-ai/cmux

    Covers debug logging, the Debug menu, profiling rules and runtime pitfalls for working on the cmux macOS terminal app.

    28k GitHub starsUsed in 1 repo~1.1k tokens
    DevelopmentAuto-check passed

More from andymai/brepjs

All 21 skills in this repo
  • Implement

    andymai/brepjs

    A skill your agent uses when authoring or editing a brepjs .brep.ts part — writing the geometry with the functional API (box, cylinder, fuse, cut, fillet, sketch→extrude…), declaring an expected…

    115 GitHub stars~3.4k tokensUpdated yesterday
    Auto-check passed
  • Polish

    andymai/brepjs

    A skill your agent uses when a valid brepjs part should look designed rather than glued-from-primitives (products, toys, mechanisms, anything a human eyeballs), and when exporting/handing off the…

    115 GitHub stars~588 tokensUpdated yesterday
    Auto-check passed
  • Wasm Interop

    andymai/brepjs

    This skill should be used when working across the JS/WASM boundary in brepjs — writing or debugging code in src/kernel/occt, src/kernel/occtWasm, or src/kernel/brepkit, or diagnosing symptoms like…

    115 GitHub stars~3k tokensUpdated yesterday
    Auto-check passed
  • Writing Tests

    andymai/brepjs

    This skill should be used when writing, running, or fixing tests in the brepjs repository — when a task says "add a test", "write a regression test", "tests are failing", "test timed out", "coverage…

    115 GitHub stars~4.3k tokensUpdated yesterday
    Auto-check passed
  • Adding Operations

    andymai/brepjs

    This skill should be used when adding or extending a geometric shape operation in brepjs — the end-to-end recipe once the target module is chosen (which is decided by architecture-navigation) — when…

    115 GitHub stars~4.4k tokensUpdated yesterday
    Auto-check passed
  • This skill should be used when deciding which layer or module a new file, function, or directory belongs in, or when a layer-boundary check fails.

    115 GitHub stars~3.4k tokensUpdated yesterday
    Auto-check passed

Works with

Categories

Questions about Memory And Disposal

What does Memory And Disposal do?

This skill should be used when managing WASM handle lifetimes or hunting memory leaks in brepjs — when a task mentions "createHandle() without using keyword risks WASM memory leak"…. Memory And Disposal is an agent skill from andymai/brepjs.

When should I use Memory And Disposal?

Memory And Disposal fits situations like: tasks that involve Performance optimization.

How do I install Memory And Disposal in Claude Code?

Run `npx skills add andymai/brepjs --skill memory-and-disposal -a claude-code`. Or copy the skill folder (.claude/skills/memory-and-disposal in andymai/brepjs) into .claude/skills/memory-and-disposal in your project. Claude Code loads it when a task matches its description.

How do I install Memory And Disposal in Codex?

Run `npx skills add andymai/brepjs --skill memory-and-disposal -a codex`. Or copy the skill folder (.claude/skills/memory-and-disposal in andymai/brepjs) into .agents/skills/memory-and-disposal in your project. Codex loads it when a task matches its description.

Can I use Memory And Disposal in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add andymai/brepjs --skill memory-and-disposal -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/memory-and-disposal, .gemini/skills/memory-and-disposal, .github/skills/memory-and-disposal and .opencode/skills/memory-and-disposal in your project.

What does Memory And Disposal need to run?

Going by SKILL.md and its folder, Memory And Disposal needs the command-line tools its instructions call (npm).

Does Memory And Disposal access the network?

SKILL.md contains no URLs. Its commands use npm, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Memory And Disposal safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Memory And Disposal use?

Memory And Disposal is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Memory And Disposal use?

About 3.1k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 1.1k tokens, read only when the agent opens those files.

What are the alternatives to Memory And Disposal?

Skills that share tags, products or a category with Memory And Disposal: Profiling Wado Compiler (wado-lang/wado, 117 stars), Wado Performance (wado-lang/wado, 117 stars), Code Review Checklist (shareAI-lab/learn-claude-code, 78k stars) and LLM Torch Profiler Analysis (sgl-project/sglang, 37k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Memory And Disposal?

andymai (a GitHub user) maintains it in andymai/brepjs, which has 115 GitHub stars. The repository holds 21 skills in this directory. The repository was last updated on October 9, 2026.

Source: andymai/brepjs on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.