Skip to main content

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.md

The 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.ts

Fix 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-aarch64

Or 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.txt
  • License, License.md, License.txt
  • license, license.md, license.txt
  • COPYING, COPYING.md, COPYING.txt

If you ship a license file, list it under additionalFiles:

additionalFiles:
  - README.md
  - LICENSE

Worth: 2 points.

Set the repository field in manifest.yaml to a public repository on an allowlisted host:

repository: https://github.com/mycollective/swamp-s3

Allowlisted 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 @swamp namespace. 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
    LICENSE

Files 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:

  1. Confirm the manifest lists README.md under additionalFiles.
  2. Republish, or click "Rescore" on the owner panel.
  3. 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.