Skip to content

Package a script as a one-command tool

Turn a script you built into a tool other people run by name, in one command — no copying files, no folder to set up. The recipient types uvx your-tool (or npx your-tool), it fetches and runs, done. Their own agent can run it for them too.

Time: ~1 min to your agent for the packaging. The un-delegable bit is making a registry account and publishing (the one step that proves the tool is yours): ~10 min once for PyPI or npm. You'll need: Claude Code, and the script you want to share. Last verified: 2026-06-07 · commands checked against uv, npm, and Homebrew's own docs. [confirmed]

New to all this? Do Set up Claude Code first, then come back. Just want them to read or copy the code, not run it as a command? A GitHub repository is simpler — this page is for "type one word and it runs."

Before you begin

  • Claude Code running in the folder that holds your script — ~10 min once. It writes the packaging config and runs every command below.
  • A script that does one job from the terminal — a Python file or a Node file with a clear "run this" entry point. If it's a notebook or a pile of loose cells, ask your agent to turn it into a single runnable script first.
  • The one thing only you can do: a free account on a package registryPyPI for Python, npm for Node — plus a publish token. That account is your name on the tool; an agent can't create it for you (email confirm + 2FA). ~10 min once.

New to asking an agent to run setup for you? Read How to ask your agent — one screen, then come back.

Pick your path first

Two questions decide the route, and your agent can answer both — "Is this a Python or a Node script, and is it ready to publish?"

  • Python → publish to PyPI so anyone runs uvx your-tool. Or skip publishing entirely and let people run it straight from a public GitHub repo (no account at all — see the no-account path below).
  • Node → publish to npm so anyone runs npx your-tool.
  • Want a polished brew install on Mac/Linux? That's a finishing touch on top — see Homebrew at the bottom.

The rest of this page is the publish-to-a-registry path, because it gives the recipient the shortest command (uvx your-tool, not a long URL).

The default: ask your agent

With Claude Code running in your project folder, say:

Package this script as a published command-line tool.

If it's Python: set up pyproject.toml with a [project.scripts] entry point
so the command is `my-tool`, add a build backend, then build with `uv build`
and publish to PyPI with `uv publish`. Stop and hand me the account-and-token
step — I'll make the PyPI account and paste you a token.

If it's Node: set up package.json with a `bin` field mapping `my-tool` to the
script, then publish to npm with `npm publish --access public`. Stop and hand
me the `npm login` step.

Pick a short, lowercase, available name and tell me what it is.

Your agent writes the packaging config (the entry point is the whole trick — it tells the registry "when someone runs my-tool, call this"), then pauses at the one step it can't do: you make the account and hand it a token. After that it builds and publishes, and prints the one command your recipient runs. [confirmed]

The step that's yours: account + publish token

The registry makes you prove the tool is yours. Your agent stops here.

=== "Python (PyPI)"

1. **Make a [PyPI account](https://pypi.org/account/register/).** Email confirm, then turn on 2FA — PyPI requires it on every account. ~5 min. `[confirmed]`
2. **Create an API token.** Account settings → **API tokens** → *Add API token* (scope it to "entire account" for your first one). Copy it — it starts `pypi-` and shows **once**. `[confirmed]`
3. **Hand it to your agent**, which publishes with `uv publish --token pypi-…`. It can also read the token from a `UV_PUBLISH_TOKEN` environment variable so it never lands in a file. `[confirmed]`

=== "Node (npm)"

1. **Make an [npm account](https://www.npmjs.com/signup).** Email confirm, then turn on 2FA. ~5 min. `[confirmed]`
2. **Log in from the terminal:** your agent runs `npm login`, which opens a browser page for you to approve (the un-delegable click). `[confirmed]`
3. **Publish.** Your agent runs `npm publish` — add `--access public` if the name is scoped like `@you/my-tool`, or it'll default to private and the recipient can't reach it. `[confirmed]`

That account is a one-time cost. Every later version is one sentence to your agent — no new account, no new token.

You're done when

Your agent prints the command your recipient runs, and it works from a clean terminal:

  • Python: uvx my-tool [confirmed]
  • Node: npx my-tool [confirmed]

Run it yourself once to confirm. That command is the share — paste it in chat, an email, a doc. The recipient needs nothing installed but uv (or Node); their agent can install that and run the command for them. [confirmed]

Shipping a new version later

Edit the script, then one sentence: "bump the version and publish again." Your agent raises the version number (registries refuse to overwrite a version that already exists — every publish needs a new number) and re-publishes. The recipient gets the new one next time they run it; uvx my-tool@latest or npx my-tool@latest forces the newest. [confirmed]

If it doesn't work

  • Recipient gets command not found after install → the entry point isn't wired up. For Python, the [project.scripts] line in pyproject.toml must map the command to a real module:function (e.g. my-tool = "mypkg:main"); for Node, the bin field must point at a file that starts with a #!/usr/bin/env node line. With uvx/npx there's usually no PATH issue — they run the command directly. Tell your agent "check the entry point resolves and re-publish." [confirmed]
  • They installed it globally (pip install / npm install -g) and then hit command not found → that's a PATH problem on their machine, not yours — the install dir isn't on their PATH. uvx/npx sidestep it; steer recipients to those. If they insist on a global install, uv tool install my-tool puts it on PATH cleanly. [confirmed]
  • Publish fails with 403 / not authorized / invalid token → the token is wrong, expired, or wasn't passed. Make a fresh PyPI token (it shows once — a copy slip is the usual cause), or re-run npm login. Don't paste the token into a committed file; use UV_PUBLISH_TOKEN or the login flow. [confirmed]
  • File already exists / cannot publish over existing version → you tried to re-publish the same version number. Registries are write-once per version. Bump the version and publish again — you can't reuse or overwrite, even after deleting. [confirmed]
  • name … already taken / package name too similar to an existing package → someone owns that name. Pick another (npm scoped names like @yourname/my-tool are almost always free — publish with --access public). Check first: visit pypi.org/project/<name> or npmjs.com/package/<name> — a 404 means it's free. [confirmed]
  • npm publishes but it's invisible / install says 404 → a scoped package went out private. Re-publish with npm publish --access public. [confirmed]
  • Anything else → the authoritative pages: uv's publish guide and npm's publish docs.

Shortcut: no account, run straight from GitHub

Don't want a registry account at all? If the code is in a public GitHub repo, people can run it with no PyPI/npm signup — at the cost of a longer command.

  • Python: uvx --from git+https://github.com/you/your-tool your-tool runs it straight from the repo. [confirmed]
  • Node: npx github:you/your-tool does the same, as long as the bin command matches the repo name. [confirmed]

The trade: zero account setup for you, but the recipient copies a full Git URL instead of one short word, and there's no version pinning by name. Good for "try my thing" links; publish to a registry once it's something people use repeatedly. [confirmed]

Optional: a polished brew install

For a Mac/Linux tool you want to feel first-class, a Homebrew tap lets people run brew install you/tools/my-tool. It's extra setup — a second GitHub repo named homebrew-tools holding a small formula file — so only reach for it once the registry version is solid.

Ask your agent: "Set up a Homebrew tap repo with a formula for this tool, pointing at the published release." The recipient then runs:

brew install you/tools/my-tool

brew tap reads the repo named homebrew-<name>, so you/tools resolves to github.com/you/homebrew-tools. [confirmed] Homebrew is Mac/Linux only — there's no Windows brew; Windows users stick to uvx/npx. [confirmed]

Prefer to do it by hand?

No agent — just you and a terminal. The minimum, per language:

=== "Python → PyPI"

1. Add to `pyproject.toml`:

    ```toml
    [project]
    name = "my-tool"
    version = "0.1.0"

    [project.scripts]
    my-tool = "mypkg:main"

    [build-system]
    requires = ["hatchling"]
    build-backend = "hatchling.build"
    ```

2. `uv build` → creates the package files in `dist/`. `[confirmed]`
3. `uv publish --token pypi-…` → uploads to PyPI. `[confirmed]`
4. Anyone runs `uvx my-tool`. `[confirmed]`

=== "Node → npm"

1. Add to `package.json`:

    ```json
    {
      "name": "my-tool",
      "version": "0.1.0",
      "bin": { "my-tool": "./cli.js" }
    }
    ```

    and make sure `cli.js` starts with `#!/usr/bin/env node`.

2. `npm login` → approve in the browser. `[confirmed]`
3. `npm publish --access public`. `[confirmed]`
4. Anyone runs `npx my-tool`. `[confirmed]`

Watch / read

YouTube blocked transcript pulls on 2026-06-07, so these aren't line-by-line verified — they're picked by channel credibility and a tight on-task title/length. Lean on the official written guides below if any video drifts.

  • How To Create And Publish Your First NPM Package — Web Dev Simplified, 7:39. Node path end to end: bin, package.json, npm publish. Why this one: a trusted teaching channel, and the clearest short walk through the bin entry point that makes npx work.
  • Blazing Fast Tips: Publishing to NPM — Matt Pocock, 3:37. Why this one: under four minutes, by a well-known npm/TypeScript author — the fastest sanity-check of the publish step.
  • Publish Your First Python Package to PyPI (Step-by-Step) — Ghost Python Academy, 5:10. Why this one: shortest on-task Python-to-PyPI walkthrough; okay start — it uses the classic build/twine flow, so map its publish step onto uv build + uv publish from the docs below.

Best written walkthrough: uv's own Building and publishing a package for the Python path (uv build, uv publish, tokens) and Running tools with uvx for how recipients run it — the authoritative sources the commands here were checked against. For Node, npm's npm publish docs. [confirmed]

Sources

Good to know

  • 2FA is mandatory on both registries. PyPI requires 2FA on every account, and npm enforces it for accounts that publish — so a passkey or authenticator app is part of the one-time account setup, not optional. Re-check live at PyPI's 2FA page and npm's 2FA docs. [confirmed]
  • A published name is public and effectively permanent. Anyone can see and install it; you can't reuse or overwrite a version number, and deleting a package doesn't free the name for re-use the way you'd hope. Pick a name you're happy to keep, and don't publish anything secret — see Who can see it?. [confirmed]
  • uvx needs uv on the recipient's machine; npx ships with Node. If your recipient has neither, that's their one install — their agent can do it, or uv's install page / nodejs.org cover it in a line. [confirmed]
  • Pricing: publishing public packages to PyPI and npm is free. Private packages cost money (npm paid plans, PyPI has no private hosting) — re-check live at npmjs.com/products if you need private. [confirmed] on public being free; [unclear] on current private-plan pricing.