IMPROVE YOUR EXTENSION SCORE
This guide shows you how to raise an extension's quality score. Each section addresses one factor from the scorecard rubric. Work through the sections for factors your extension does not currently earn.
Before you start
Open the extension's detail page and look at the factor breakdown. Everything marked "earned" can be skipped — only the gaps are worth your time.
If you change a per-version factor (README content, type annotations, JSDoc
coverage), you will need to either publish a new version or click "Rescore" on
the owner panel. Changes to per-package fields (description, platforms,
repository, license) take effect immediately; no rescore needed.
Ship a README
Worth: 2 points.
Create a README.md at the root of your extension and list it under
additionalFiles in the manifest:
additionalFiles:
- README.mdThe scorer accepts the file either at the extension root or under files/ in
the packaged tarball. Keeping it at repo root also means GitHub (and the other
allowlisted hosts) render it on the repository page.
The analyzer accepts README.md, README.MD, readme.md, and Readme.md. Any
other casing (for example ReadMe.md) is not detected.
Add a code example
Worth: 1 point.
Include at least one fenced code block in the README that shows the extension in use:
```ts
import { validate } from "@mycollective/my-ext";
validate({ region: "us-east-1" });
```Any fenced block counts. A realistic usage snippet is more useful to readers than a trivial one.
Make the README substantive
Worth: 1 point.
The README must be at least 500 characters and contain at least two fenced code blocks. A common shape is one block showing how to invoke the extension and a second showing the expected output or a workflow snippet that consumes it.
Any README with a short intro and two real examples clears the threshold.
Document your exports
Worth: 1 point.
At least 80% of symbols exported from your entry points must carry a JSDoc comment. One sentence each is enough:
/** Validate the model's inputs against the schema. */
export function validate(input: Input): ValidationResult {
// ...
}Only exported symbols are counted. Internal helpers that are not re-exported from the entry point do not affect the percentage.
If you are close to the threshold, favour documenting the symbols that consumers will actually call — public types, factory functions, and the main entry function — rather than spreading comments thin across everything.
Eliminate slow types
Worth: 1 point.
Slow types are TypeScript patterns that the fast-check path cannot resolve: exported functions without explicit return type annotations, public exports that reference private types, and similar.
Add explicit annotations to the public surface:
// slow — no return type
export function greet(name) {
return `Hello, ${name}`;
}
// fast
export function greet(name: string): string {
return `Hello, ${name}`;
}Run deno doc --lint locally before publishing to surface any remaining issues:
deno doc --lint extensions/models/your_model.tsFix every diagnostic it reports. This is the same check the scorer runs.
Fill in the description
Worth: 1 point.
Set the description field in manifest.yaml:
description: "Manage AWS S3 buckets — create, upload, invalidate, delete."One sentence is fine. This is a per-package field — editing it on the owner panel updates the score instantly, no republish required.
Declare platforms
Worth: 2 points total (one for any entry, one for two or more).
Set the platforms field in manifest.yaml:
platforms:
- linux-x86_64
- darwin-aarch64
- linux-aarch64Or leave it empty to declare "works everywhere":
platforms: []An empty array earns both platform factors. A list with two or more entries also earns both. A list with exactly one entry earns one.
Declare a license
Worth: 1 point.
Either set a license field on the extension, or ship a license file in the
tarball. The analyzer looks at the extension root and under files/ for any of
these filenames:
LICENSE,LICENSE.md,LICENSE.txtLicense,License.md,License.txtlicense,license.md,license.txtCOPYING,COPYING.md,COPYING.txt
If you ship a license file, list it under additionalFiles:
additionalFiles:
- README.md
- LICENSELink a verified repository
Worth: 2 points.
Set the repository field in manifest.yaml to a public repository on an
allowlisted host:
repository: https://github.com/mycollective/swamp-s3Allowlisted hosts are github.com, gitlab.com, codeberg.org, and
bitbucket.org. Verification runs automatically within a few seconds of publish
and re-runs when the URL changes. The result is cached for 7 days.
If your repository is on a self-hosted instance (GitHub Enterprise, self-hosted GitLab, private Gitea), the URL will still display on the detail page, but the factor cannot be earned. There is no workaround — the rubric requires verification against the public API of one of the four hosts.
If you have set the URL but the factor is not earned, check that:
- The URL points to a public repository (not a private one the API cannot read).
- The host is one of the four allowlisted ones.
- The owner and repository path are correct — GitLab nested group paths must resolve to a real project.
Earn the verified-by-swamp badge
Worth: 1 point.
Two paths earn this factor:
- Publish under the first-party
@swampnamespace. This is reserved for extensions maintained by System Initiative. - Be marked verified by a System Initiative admin. The admin review process for third-party extensions is planned but the request endpoint is not yet available.
If neither applies, this factor is not currently earnable. A third-party
extension that fills in every other factor caps at 12/13 = 92% = Grade A.
Troubleshooting: "My score did not move"
The most common cause is the tarball layout. The swamp CLI packages a published extension like this:
extension/
manifest.yaml
models/
your_model.ts
files/ ← additionalFiles land here
README.md
LICENSEFiles you list under additionalFiles end up under files/ in the archive. The
scorer looks for README.md and license files at both the extension root and
under files/, so either layout works — but if your local filesystem has a
README.md that is not listed in additionalFiles, it will not be in the
tarball at all.
If has-readme is reporting 0/2 and you are sure you shipped one:
- Confirm the manifest lists
README.mdunderadditionalFiles. - Republish, or click "Rescore" on the owner panel.
- Recheck the detail page — the factor should update within a few seconds.
Apply the same steps for has-license if the license factor is not earning.
Rescore after edits
Per-version factors (has-readme, readme-example, rich-readme,
symbols-docs, fast-check) are only re-evaluated when a new version is
published or when the owner clicks "Rescore" on the detail page. Editing
per-package fields on the owner panel does not retrigger per-version analysis.
Per-package factors (description, platforms-one, platforms-two,
has-license, verified-by-swamp) update instantly on edit.
The repository-verified factor re-runs immediately when the URL changes.
Otherwise it re-checks at the next publish or rescore, but only if the stored
result is more than 7 days old. There is no separate periodic sweep — if nothing
triggers a scoring event, a stale cache stays put.
Related
- Extension Scorecard Rubric — exact factors, weights, and grade thresholds.
- About the Extension Scorecard — what the score measures and why it exists.
- Extension Manifest — YAML schema for
description,repository,platforms, andadditionalFiles. - Create and Publish an Extension — full publish workflow.