This skill should be used when the user asks to 'audit for JSR', 'check JSR readiness', 'review JSR config', 'verify package for JSR', 'publish to JSR', 'prepare for JSR publishing', 'JSR compliance check', 'run JSR audit', or wants to ensure their Deno/TypeScript package meets JSR standards before publishing.
This skill inherits all available tools. When active, it can use any tool Claude has access to.
Comprehensive audit guide for JSR (JavaScript Registry) compliance and scoring optimization.
JSR assigns packages a quality score from 0-100%, displayed with color coding:
The score directly influences search ranking. View any package's breakdown at jsr.io/@scope/package/score.
| Category | Factor | Impact |
|---|---|---|
| Documentation | Has README or module doc | High |
| Has examples in README/module doc | High | |
| Has module docs in all entrypoints | High | |
| Has docs for most symbols | High | |
| Best Practices | No slow types | Medium |
| Has provenance (SLSA attestation) | Medium | |
| Discoverability | Has description (≤250 chars) | Low |
| Compatibility | At least one runtime marked compatible | Low |
| At least two runtimes compatible | Low |
Key insight: Documentation carries the heaviest weight. Comprehensive JSDoc + README + @module tags will score higher than perfect types with minimal docs.
| Check | Command/Location | What to Look For |
|---|---|---|
| Required metadata | deno.json | name, version, exports fields |
| Scoped package name | name field | Format: @scope/package-name |
| Package description | description field | ≤250 characters for discoverability |
| Valid exports | exports field | Entry points exist and are correct |
| No slow types | deno publish --dry-run | No slow type warnings |
| Clean file list | deno publish --dry-run | Only intended files included |
| ESM only | Source files | No CommonJS (module.exports, require()) |
| Module documentation | Entry point files | @module JSDoc tag present |
| Symbol documentation | Exported symbols | JSDoc with @param, @returns, @example |
Read deno.json (or jsr.json) and verify:
{
"name": "@scope/package-name",
"version": "1.0.0",
"description": "Concise package description under 250 characters",
"exports": "./mod.ts"
}
Package name rules:
@scope/Config file choice:
deno.jsonjsr.jsonCheck all entry points exist:
{
"exports": {
".": "./mod.ts",
"./utils": "./src/utils/mod.ts"
}
}
For each entry point, confirm:
@module JSDoc tagModule-level documentation (top of entry points):
/**
* A module providing string utilities for common transformations.
*
* @example
* ```ts
* import { camelCase } from "@scope/cases";
* camelCase("hello world"); // "helloWorld"
* ```
*
* @module
*/
Symbol documentation:
/**
* Converts a string to camelCase format.
*
* @param input - The string to convert
* @returns The camelCase formatted string
*
* @example
* ```ts
* camelCase("hello world"); // "helloWorld"
* camelCase("foo-bar-baz"); // "fooBarBaz"
* ```
*/
export function camelCase(input: string): string {
// ...
}
JSDoc tags reference:
@param name - description - Document parameters@returns description - Document return value@example - Runnable code examples (use triple backticks)@deprecated message - Mark deprecated APIs@see SymbolName - Cross-reference related symbols@throws ErrorType - Document thrown errors{@link SymbolName} - Inline links{@linkcode SymbolName} - Inline links with monospacedeno publish --dry-run --allow-dirty
This reveals:
Review dry-run output for files that should NOT be published:
Common offenders:
.claude/, .zed/, .vscode/ - IDE settings.github/, .gitlab/ - CI/CD configs.mise.toml, .tool-versions - Local toolingcoverage/ - Test coverage datadocs/, *.md (except LICENSE/README) - Documentationdeno.lock - Lock files*.test.ts, **/test_utils/** - Test filessonar-project.properties, *.config.js - Build configs.env, *.local.* - Local configurationUse include (whitelist) + exclude (filter):
{
"publish": {
"include": [
"LICENSE",
"README.md",
"deno.json",
"mod.ts",
"src/**/*.ts"
],
"exclude": [
"**/*.test.ts",
"**/test_utils/**"
]
}
}
Why both?
include whitelists only intended filesexclude filters test files from src/**/*.ts globexclude takes precedence when both matchRun dry-run again. Only these should appear:
LICENSEREADME.mddeno.jsonmod.ts, etc.)src/**/*.ts minus tests)Slow types are exports without explicit type annotations. They prevent JSR from generating .d.ts files efficiently and degrade npm compatibility by 1.5-2x slower type checking.
// SLOW - inferred return type
export function greet(name: string) {
return "Hello, " + name + "!";
}
// FIXED - explicit return type
export function greet(name: string): string {
return "Hello, " + name + "!";
}
// SLOW - inferred type
export const GLOBAL_ID = crypto.randomUUID();
// FIXED - explicit annotation
export const GLOBAL_ID: string = crypto.randomUUID();
// SLOW - inferred property type
export class Config {
timeout = 5000;
}
// FIXED - explicit property type
export class Config {
timeout: number = 5000;
}
# Catch slow types before publishing
deno publish --dry-run
# Validate documentation generation
deno doc --lint
Note: TypeScript 5.5's isolatedDeclarations mode produces code that automatically satisfies JSR's no-slow-types requirement.
JSR enforces ESM-only architecture:
| Prohibited | Alternative |
|---|---|
require() | import |
module.exports | export |
declare global | Module-scoped types |
declare module | Module-scoped types |
| HTTP imports | jsr:, npm:, node: specifiers only |
For packages with multiple exports:
{
"exports": {
".": "./mod.ts",
"./providers": "./providers.ts",
"./utils": "./src/utils/mod.ts"
}
}
Users import as:
import { main } from "@scope/pkg";
import { OpenAI } from "@scope/pkg/providers";
import { helper } from "@scope/pkg/utils";
Each entry point should have its own @module JSDoc tag.
Declare in imports:
{
"imports": {
"@std/assert": "jsr:@std/assert@^1.0.0",
"zod": "npm:zod@^3.22.0"
}
}
Supported specifiers:
jsr:@scope/pkg@version - JSR packagesnpm:package@version - npm packagesnode:module - Node.js built-insGitHub Actions OIDC enables tokenless publishing with automatic SLSA provenance:
name: Publish to JSR
on:
push:
tags: ['v*']
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for OIDC and provenance
steps:
- uses: actions/checkout@v5
- uses: denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno publish
Requirements for provenance:
id-token: write permissionNo API tokens needed - JSR uses GitHub OIDC authentication.
After completing the audit:
## JSR Publishing Audit Results
| Check | Status |
|-------|--------|
| Required metadata | ✓ / ✗ |
| Scoped package name | ✓ / ✗ |
| Package description | ✓ / ✗ |
| Valid exports | ✓ / ✗ |
| No slow types | ✓ / ✗ |
| Clean file list | ✓ / ✗ |
| ESM only | ✓ / ✗ |
| Module documentation | ✓ / ✗ |
| Symbol documentation | ✓ / ✗ |
### Estimated Score Impact
- Documentation: X/4 factors
- Best Practices: X/2 factors
- Discoverability: X/1 factors
- Compatibility: X/2 factors
### Files Published
[List from dry-run]
### Issues Found
[List any problems]
### Recommendations
[Suggested fixes prioritized by score impact]
# Full audit dry-run
deno publish --dry-run --allow-dirty
# Validate documentation
deno doc --lint
# Type check
deno check **/*.ts
# Lint
deno lint
# Format
deno fmt
# Publish (when ready)
deno publish
--allow-slow-types