{"id":51003046,"url":"https://github.com/dmno-dev/fledgling","last_synced_at":"2026-06-20T17:03:16.403Z","repository":{"id":364399681,"uuid":"1267767546","full_name":"dmno-dev/fledgling","owner":"dmno-dev","description":"🐣 Create and set up new npm packages w/ trusted (OIDC) publishing - for one package or a whole monorepo","archived":false,"fork":false,"pushed_at":"2026-06-12T23:07:51.000Z","size":2783,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-12T23:09:14.227Z","etag":null,"topics":["npm","package-management","setup"],"latest_commit_sha":null,"homepage":"https://fledgling.varlock.dev","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dmno-dev.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-12T21:00:39.000Z","updated_at":"2026-06-12T23:07:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dmno-dev/fledgling","commit_stats":null,"previous_names":["dmno-dev/newdle"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/dmno-dev/fledgling","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmno-dev%2Ffledgling","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmno-dev%2Ffledgling/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmno-dev%2Ffledgling/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmno-dev%2Ffledgling/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dmno-dev","download_url":"https://codeload.github.com/dmno-dev/fledgling/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dmno-dev%2Ffledgling/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34578095,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-20T02:00:06.407Z","response_time":98,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["npm","package-management","setup"],"created_at":"2026-06-20T17:03:15.698Z","updated_at":"2026-06-20T17:03:16.396Z","avatar_url":"https://github.com/dmno-dev.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fledgling 🐣\n\n[![npm version](https://img.shields.io/npm/v/fledgling?color=cb3837\u0026logo=npm)](https://www.npmjs.com/package/fledgling)\n[![npm downloads](https://img.shields.io/npm/dm/fledgling?color=cb3837\u0026logo=npm)](https://www.npmjs.com/package/fledgling)\n[![node](https://img.shields.io/node/v/fledgling)](https://www.npmjs.com/package/fledgling)\n[![license](https://img.shields.io/npm/l/fledgling?color=blue)](./LICENSE)\n\n**Create and set up packages on npm with trusted publishing.**\n\n\u003e Brought to you by [Varlock](https://varlock.dev) 🧙‍♂️🔐 — [check it out to keep your secrets out of plaintext](https://varlock.dev).\n\n`fledgling` claims your package name on npm and sets up token-less ([OIDC trusted](https://docs.npmjs.com/trusted-publishers/)) publishing — no `NPM_TOKEN`, no clicking through the npm website. It works for a single package or a whole monorepo, and it's idempotent, so you can re-run it any time you add a package.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/dmno-dev/fledgling/main/images/demo.gif\" alt=\"fledgling claiming a new package in a monorepo and setting up trusted publishing\" width=\"760\"\u003e\n\u003c/p\u003e\n\nDesigned to be run with `npx` (or `bunx` / `pnpm dlx`):\n\n```sh\nnpx fledgling                                # interactive walkthrough (in a terminal)\nnpx fledgling add my-great-new-idea --new    # claim a brand-new name, nothing in the repo yet\nnpx fledgling add \"*\" --yes                  # every package in a monorepo (globs ok)\nnpx fledgling sync                           # reconcile trusted publishing to your config\n```\n\nRun bare `fledgling` in a terminal and you get an interactive wizard (powered by [clack](https://github.com/bombshell-dev/clack)); pass packages to `add` (or `--yes` / run in CI) and it goes non-interactive.\n\n### Commands\n\n| Command | What it does |\n|---------|--------------|\n| `fledgling` | Interactive wizard (the default) |\n| `fledgling add [packages…]` | Claim names + set up trusted publishing for the given packages |\n| `fledgling sync` | Reconcile trusted publishing on npm with your config |\n| `fledgling init` | Write the trusted-publishing config to your `package.json` |\n\n## Why\n\nSetting up a new npm package the modern way is more fiddly than it should be:\n\n1. npm won't let you configure trusted publishing until the package **already exists** — so you have to publish *something* first.\n2. Then you configure the trusted publisher **per package**, by hand, on the website.\n3. In a monorepo, you do that **N times**.\n\n`fledgling` does all of it: publishes a tiny placeholder to claim each name, then configures the trusted publisher for every package via npm's own [`npm trust`](https://docs.npmjs.com/cli/v11/commands/npm-trust/). It's **idempotent** — re-run it whenever you add a package and it only does what's missing.\n\n## Quick start\n\n```sh\nnpm login        # needs 2FA enabled\nnpx fledgling       # interactive: pick packages, confirm, apply\n```\n\nPrefer non-interactive (or in CI)?\n\n```sh\nnpx fledgling --dry-run    # print a plan, change nothing\nnpx fledgling --yes        # apply: claim names + configure trusted publishing\n```\n\nThen add the matching publish step to your CI (e.g. a GitHub Actions job with `permissions: id-token: write` running `npm publish`). Your real releases now publish over OIDC — no token required.\n\n\u003e 🐸 **Next step: [Bumpy](https://bumpy.varlock.dev)** handles exactly that publish step for you — it versions your packages, writes changelogs, and publishes over OIDC trusted publishing (no `NPM_TOKEN`). `fledgling` sets up the trust, Bumpy does the releasing — they pair perfectly. (This repo is released with it.)\n\n## Configuration\n\n**The recommended way to configure `fledgling` is a `\"fledgling\"` block in your root `package.json`.** Set it once and every run reads it — CLI flags are just per-run overrides. Create it interactively:\n\n```sh\nnpx fledgling init\n```\n\n```jsonc\n{\n  \"fledgling\": {\n    \"provider\": \"github\",       // github | gitlab | circleci\n    \"workflow\": \"release.yml\",  // the workflow whose job runs `npm publish`\n    \"environment\": \"publish\",   // CI environment for the trusted publisher (optional)\n    \"permissions\": \"publish\"    // publish | stage | both\n  }\n}\n```\n\n**CircleCI** uses IDs instead of a workflow/repo:\n\n```jsonc\n{\n  \"fledgling\": {\n    \"provider\": \"circleci\",\n    \"orgId\": \"…\",\n    \"projectId\": \"…\",\n    \"pipelineDefinitionId\": \"…\",\n    \"vcsOrigin\": \"github/owner/repo\",\n    \"contextIds\": [\"…\"],        // optional\n    \"permissions\": \"publish\"\n  }\n}\n```\n\nAdd `\"registry\"` to either block to target a non-default npm registry.\n\n### Excluding packages\n\nfledgling skips any package marked `\"private\": true`. To exclude **public** packages too —\ninternal-but-published things you never want it to claim or manage trust for — add an\n`\"ignore\"` list of names or globs:\n\n```jsonc\n{\n  \"fledgling\": {\n    \"ignore\": [\"@scope/internal-*\", \"playground\"]\n  }\n}\n```\n\nIgnored packages are invisible to fledgling: they're left out of `add`, `sync`, `\"*\"`\nglobs, and tab completion.\n\n### Defaults\n\n| Option | Default | Notes |\n|--------|---------|-------|\n| `provider` | `github` | also `gitlab`, `circleci` |\n| `repo` | _auto-detected_ from git `origin` | override with `--repo` |\n| `workflow` | `release.yml` | the workflow whose job publishes |\n| `environment` | **none** | Optional and **unset by default** — the trusted publisher then isn't tied to a CI environment (it works, but adds no environment gate). Setting one (e.g. `publish`) is recommended for security, and `fledgling init` pre-fills it. |\n| `permissions` | `publish` | `publish`, `stage` (held for 2FA approval), or `both` |\n| `registry` | _your npm config_ | optional custom npm registry URL |\n\n**CircleCI** uses `orgId`, `projectId`, `pipelineDefinitionId`, `vcsOrigin`, and optional `contextIds` instead of `repo`/`workflow`/`environment`.\n\nPrecedence is **CLI flag → `fledgling` config → built-in default**.\n\n### Just want to claim names?\n\nTo skip trusted publishing entirely and only reserve package names, you can:\n- pass **`--skip-trust`** for a single run,\n- decline the wizard's \"Set up trusted publishing?\" prompt, or\n- set **`\"trust\": false`** in your `fledgling` config to make it the default.\n\n## Usage\n\n```sh\nnpx fledgling add [packages...] [options]\n```\n\nWith no package arguments, `add` targets **every public package** in your workspace. Pass names or globs to narrow it down:\n\n```sh\nnpx fledgling add my-pkg --yes              # one package\nnpx fledgling add \"@scope/*\" --yes          # a glob (quote it)\nnpx fledgling add \"*-plugin\" --yes          # all the plugins\nnpx fledgling add @scope/brand-new --new --yes   # claim a name that doesn't exist locally yet\n```\n\nRunning bare `npx fledgling` (no subcommand) in a terminal drops you into the same flow interactively.\n\n### Run options\n\n| Flag | Description |\n|------|-------------|\n| `-y, --yes` | Apply changes without prompting (default in a terminal is the interactive wizard) |\n| `--dry-run` | Print a plan without prompting (non-interactive) |\n| `--new` | Treat unmatched names as brand-new packages to claim (squat a name) |\n| `--skip-publish` | Only set up trusted publishing |\n| `--skip-trust` | Only claim names |\n| `--force` | Replace an existing trusted publisher (revoke + re-create) |\n| `--placeholder-version \u003cv\u003e` | Placeholder version (default: `0.0.0`) |\n| `--tag \u003ctag\u003e` | dist-tag for placeholders (default: `latest`) |\n| `--otp \u003ccode\u003e` | npm 2FA one-time password, used for every npm call this run |\n| `--otp-secret \u003csecret\u003e` | TOTP secret to generate 2FA codes from as needed (also `$FLEDGLING_OTP_SECRET`) |\n\n### 2FA / one-time passwords\n\nnpm requires 2FA to claim names and configure trusted publishing. By default fledgling\njust lets **npm handle it interactively** — it opens your browser to approve, and caches\nthat approval for ~5 minutes, so one approval covers the whole run. When prompted, tick\n**\"don't ask again for 5 minutes\"** so it doesn't ask per-package.\n\nFor non-interactive runs (CI, scripts) there's no browser, so pass a code yourself:\n\n- **`--otp \u003ccode\u003e`** — a single one-time password, reused for every npm call in the run.\n- **`--otp-secret \u003csecret\u003e`** — your authenticator's TOTP secret (base32); fledgling\n  generates a fresh code for each npm call. Prefer the **`FLEDGLING_OTP_SECRET`** env var\n  over the flag so the secret doesn't land in your shell history or process list.\n\nPull credentials straight from a password manager — e.g. 1Password's CLI (`op`). Read the\n**generated code** with `?attribute=otp` and pass it to `--otp`:\n\n```sh\nfledgling sync --otp \"$(op read \"op://Private/npm/Security/one-time password?attribute=otp\")\"\n```\n\n…or read the **secret itself** — the field's value with no attribute, an `otpauth://` URI —\ninto `FLEDGLING_OTP_SECRET`, and fledgling mints a fresh code for every npm call:\n\n```sh\nFLEDGLING_OTP_SECRET=\"$(op read \"op://Private/npm/Security/one-time password\")\" fledgling sync\n```\n\n### Config flags\n\nBetter set once in `package.json` (see [Configuration](#configuration)); as flags they override the config for that run.\n\n| Flag | Config key | Default |\n|------|-----------|---------|\n| `--provider \u003cp\u003e` | `provider` | `github` |\n| `--permissions \u003cp\u003e` | `permissions` | `publish` |\n| `--registry \u003curl\u003e` | `registry` | _npm config_ |\n| `--repo \u003cowner/repo\u003e` | _(auto-detected)_ | git `origin` |\n| `--workflow \u003cfile\u003e` | `workflow` | `release.yml` |\n| `--env \u003cname\u003e` | `environment` | none |\n| `--org-id \u003cuuid\u003e` | `orgId` | _(circleci)_ |\n| `--project-id \u003cuuid\u003e` | `projectId` | _(circleci)_ |\n| `--pipeline-definition-id \u003cuuid\u003e` | `pipelineDefinitionId` | _(circleci)_ |\n| `--vcs-origin \u003corigin\u003e` | `vcsOrigin` | _(circleci)_ |\n| `--context-id \u003cuuid\u003e` | `contextIds` | _(circleci, repeatable)_ |\n\n## What it does, precisely\n\nFor each target package:\n\n1. **Claim** — if the name isn't on npm yet, publish a `package.json`-only placeholder (`0.0.0`, no code) to reserve it.\n2. **Trust** — if there's no trusted publisher configured, set one up for your CI provider via `npm trust` (or replace an existing one with `--force`). Supports **GitHub, GitLab, and CircleCI**, with every option `npm trust` accepts.\n\nBoth steps are skipped when already done. Placeholders are packed from a throwaway temp dir, so your real `package.json` files are never touched.\n\n## `fledgling sync` — reconcile trusted publishing\n\nWhere the default command focuses on **new** packages (and hides already-published ones), `fledgling sync` reconciles **trusted publishing across every package** against your `fledgling` config.\n\nIt authenticates, reads each package's actual config on npm, and shows what's **not configured** or **out of sync** — with the exact difference (e.g. `environment publish → (none)`) — then asks before fixing it to match your config:\n\n```sh\nfledgling sync            # auth, check, then confirm + apply\nfledgling sync --yes      # skip the confirm\nfledgling sync \"@scope/*\" # a subset\n```\n\nUse it after changing your `fledgling` config, or to set up trust on packages that were published without it. (It uses the same config/flags as the main command.)\n\n## Shell completions\n\n`fledgling` ships tab-completion (via [`@bomb.sh/tab`](https://github.com/bombshell-dev/tab)) that completes package names and flags. Install it for your shell:\n\n```sh\nfledgling complete zsh  \u003e\u003e ~/.zshrc\nfledgling complete bash \u003e\u003e ~/.bashrc\nfledgling complete fish \u003e  ~/.config/fish/completions/fledgling.fish\n```\n\nThen `fledgling \u003cTAB\u003e` completes the packages in your workspace.\n\n## Requirements\n\n- **Node** ≥ 18\n- **npm** ≥ 11.15.0 (for `npm trust` + OIDC/staged publishing)\n- `npm login` with **2FA enabled** for the trust step (npm requires it)\n\nSupports **npm / yarn / bun** (`workspaces`) and **pnpm** (`pnpm-workspace.yaml`) monorepos, plus single-package repos.\n\n## License\n\n[MIT](./LICENSE) © DMNO Inc\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://varlock.dev\" target=\"_blank\" rel=\"noopener noreferrer\"\u003e\n    \u003cimg src=\"https://raw.githubusercontent.com/dmno-dev/fledgling/main/images/github-readme-footer.png\" alt=\"fledgling was created by Varlock\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cb\u003efledgling is a creation of the team behind \u003ca href=\"https://varlock.dev\"\u003eVarlock\u003c/a\u003e 🧙‍♂️\u003c/b\u003e\u003cbr/\u003e\n  \u003ca href=\"https://varlock.dev\"\u003eCheck it out for secure secret sorcery — get your keys out of plaintext!\u003c/a\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmno-dev%2Ffledgling","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdmno-dev%2Ffledgling","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdmno-dev%2Ffledgling/lists"}