# Share code between scripts

Put the code that scripts for one site have in common into one file with versions, and import it from each script, so a fix lands once.

Scripts for one site often need the same logic: read a table row, build a search URL, wait for a list to load. Instead of a copy in each script, you keep that code in one file for the site. We call it the **common code** of the site. Each script imports it.

You do not write this by hand. Your agent writes it with the `read_host_common` and `set_host_common` tools, when it sees that two scripts for the same site need the same helper.

## Import it

A script that imports common code uses `import` and exports a default function. The function receives `builtins`, `page`, `args` and `files`, as one object.

```js
import { parseRow, waitForTable } from "./news.ycombinator.com/common@3.js";

export default async ({ builtins, page, args }) => {
	await builtins.goto("https://news.ycombinator.com/newest");
	await waitForTable(page);
	return { rows: (await page.locator("tr.athing").all()).map(parseRow) };
};
```

The folder in the path is the site. A script for `news.ycombinator.com` can import only the common code of `news.ycombinator.com`, and only from its own owner. An import for another site fails.

Common code does not see `page` or `builtins`. A function that needs them takes them as arguments, as `waitForTable(page)` does above.

## Versions

Each time the agent saves common code, it adds the **next version**. An earlier version never changes and is never deleted. Saving the text of the latest version again adds nothing.

| Import                           | What it loads                                  |
| -------------------------------- | ---------------------------------------------- |
| `./<site>/common@3.js`           | Version 3. It never changes.                   |
| `./<site>/common.js`             | The latest version, at the moment of the run.  |

Use `common.js` while you test a draft, so a new edit shows at once. A script that is promoted must use `common@<n>.js`, so that it runs the same code tomorrow as today. Promote a script that imports `common.js` and Reduck refuses it with a `409` that names the import to pin:

```text
This version imports ./news.ycombinator.com/common.js, which is the latest common code and
changes when a version is added. Pin it before promoting: import
./news.ycombinator.com/common@<n>.js — set_host_common returns the number, read_host_common
shows the latest.
```

A script that is already promoted is never refused for this, so you can still roll back to an older version.

A new version of the common code does not change a script that pins an older one. To use it, the agent saves a new version of the script that imports `common@4.js`, tests it, and promotes it.

## Who can read it

Common code follows the scripts that import it. Anyone who can read the owner's scripts for that site can read its common code: everyone when the owner has a public script for the site, and the owner's [project](https://docs.reduck.ai/core-concepts/#projects) members otherwise. The source of an official script is for the members of its project only, and so is its common code. Only the owner, or a project member who may edit its scripts, can add a version.

## Ask your agent

```markdown
Using Reduck MCP, read the common code for news.ycombinator.com. If there is a helper
for reading a story row, use it in a new script that lists the newest stories.
```

The two tools:

- `read_host_common`: `host`, `handle` (optional), and `version` (optional, the latest if you leave it out).
- `set_host_common`: `host`, `handle` (optional), and `content`, the full JavaScript text. It returns the version number it saved.

`handle` is the owner, as for [other tools](https://docs.reduck.ai/core-concepts/#handles): `@user` for a user, a project handle without `@` for a project.

## From your code

The same two actions are in the [REST API](https://docs.reduck.ai/api-reference/) as `getHostCommon` (`GET /api/scripts/{handle}/{host}/common`, with `?version=` for one version) and `setHostCommon` (`PUT`, with `content` in the body).

> [!NOTE]
> Common code is plain JavaScript, with no type syntax, and at most 100,000 characters per version. It can import nothing except what the sandbox provides, so an npm package or a URL fails at run time. It cannot import another version of itself.
