Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

kanbanr — Open-Sourcing & Release Guide

A concrete, checklist-style path to publishing kanbanr publicly and keeping it maintainable — sized for a personal open-source project (one maintainer, friendly to contributors), not a foundation-governed one. Pair with ROADMAP.md and the board’s own assessment (kanbanr doc show notes/assessment.md).

Status today (updated): the workspace is now relicensed MIT OR Apache-2.0 with LICENSE-MIT + LICENSE-APACHE files; CONTRIBUTING.md, SECURITY.md, CODE_OF_CONDUCT.md, CHANGELOG.md, THIRD_PARTY.md, GitHub issue/PR templates, a CI workflow and a release workflow all exist. What’s left is mostly your work: reserve names, create accounts/tokens, fill two placeholders, add screenshots, and cut the first tagged release. Checked boxes below mark what’s already in the repo.

Placeholders: filled. The GitHub owner is startr-trade (README, this file, templates, workflows, manifests), and the contact address in CODE_OF_CONDUCT.md and SECURITY.md is kanbanr-oss-support@startr.trade. The copyright line in LICENSE-MIT / LICENSE-APACHE and the authors field in api/Cargo.toml deliberately read the kanbanr authors — change it only if you want a personal name on the licence.

# Forking this under a different owner? One pass replaces every reference:
grep -rl 'startr-trade' . --exclude-dir=.git --exclude-dir=node_modules --exclude-dir=target \
  | xargs sed -i 's/startr-trade/YOUR_GITHUB_OWNER/g'

Accounts, keys & credentials you’ll need (start here if this is your first OSS project)

Open-sourcing kanbanr means publishing to a few different services. Each needs an account and usually a token — a long secret string that proves you’re allowed to publish. You create the token once on the service’s website, then either paste it into your terminal (for a one-off manual publish) or store it as a GitHub Actions secret (so the automated release workflow can publish for you). Never paste a token into a file that gets committed.

The golden rules (these are the “measures” to take):

  • Turn on 2FA (two-factor auth) on every account below. crates.io and npm now require it to publish.
  • Use a password manager for accounts + tokens.
  • Scope tokens narrowly and give them an expiry. A publish token should only be able to publish.
  • Prefer “Trusted Publishing” where offered (crates.io and npm support it): instead of a long-lived token, GitHub Actions proves its identity to the registry over OIDC at publish time, so there’s no secret to leak. You set it up on the registry’s website by naming your GitHub repo + workflow. This is the modern best practice — use it if you can; the token method below is the fallback.
  • Store automation tokens only in GitHub → your repo → Settings → Secrets and variables → Actions → New repository secret. Workflows read them as ${{ secrets.NAME }}; they’re masked in logs and never shared with pull requests from forks.
  • Rotate (regenerate) a token immediately if it ever leaks, and treat anything that touched a commit as already leaked.

What each destination needs

DestinationWhat it’s forAccountCredential to createWhere it lives
GitHubHosts the repo, runs CI, stores release binaries, serves the plugin marketplacegithub.com (free) + 2FAan SSH key for git push; CI’s GITHUB_TOKEN is automaticSSH key on your laptop (~/.ssh); GITHUB_TOKEN is injected into Actions — nothing to store
crates.ioPublishes the standalone ears-classifier library — the only crate that is published. kanbanr itself is not on crates.io (see §5)crates.io (log in with GitHub) + 2FAan API token, or set up Trusted PublishingCARGO_REGISTRY_TOKEN secret, or none (Trusted Publishing)
GHCR (GitHub Container Registry)Publishes the Docker image so docker run ghcr.io/startr-trade/kanbanr worksyour GitHub accountnone — Actions uses the automatic GITHUB_TOKEN (packages: write)nothing to store; locally use a PAT with write:packages
Claude Code plugin marketplaceLets users claude plugin install kanbanryour GitHub accountnone — it’s just your public git reponothing — users add the repo URL
VS Code Marketplace (only when you ship the extension — editor/vscode/)Publishes the VS Code extensionAzure DevOps account (free) + a publisher at marketplace.visualstudio.com/managea Personal Access Token scoped Marketplace → ManageVSCE_PAT secret
Open VSX (optional, open-source VS Code registry)Same extension for VSCodium/Cursor/etc.open-vsx.org (log in with GitHub)an access tokenOVSX_TOKEN secret
npm (probably NOT needed)Only if you ever publish the web UI as a reusable package — kanbanr bundles it into the binary, so you likely just reserve the namenpmjs.com + 2FAan Automation tokenNPM_TOKEN secret

You don’t need every row. For a first release the essentials are GitHub (always: it hosts the release archives and the installers) and GHCR (for docker run). crates.io is only for ears-classifier. The Claude plugin needs nothing beyond a public repo. VS Code / Open VSX / npm can come later.

Step-by-step: creating each credential

GitHub SSH key (to push code) — on your laptop:

ssh-keygen -t ed25519 -C "you@example.com"   # press Enter for defaults; set a passphrase
cat ~/.ssh/id_ed25519.pub                     # copy this line

Paste it at GitHub → Settings → SSH and GPG keys → New SSH key. Test: ssh -T git@github.com.

crates.io API token (to publish ears-classifier):

  1. Sign in at crates.io with GitHub; enable 2FA.
  2. Account Settings → API Tokens → New Token. Name it kanbanr-release; scope to publish-update (plus publish-new for the very first publish); set an expiry.
  3. Manual publish: cargo login then paste it (stored in ~/.cargo/credentials.toml — never commit).
  4. Automated publish: add it as the CARGO_REGISTRY_TOKEN secret and set repo variable PUBLISH_CRATES=true (the release workflow’s crates job is guarded on that). Better: skip the token and set up Trusted Publishing on crates.io (your crate → Settings → Trusted Publishing → add startr-trade/kanbanr + the release.yml workflow), then delete the token line. The job publishes ears-classifier only; every kanbanr crate declares publish = false, so a stray cargo publish of one of them is refused.
  5. ⚠️ A published version is permanent — you can cargo yank a bad version but never delete or reuse it. Double-check before cargo publish.

GHCR (Docker image): nothing to create — the release workflow logs in with the built-in GITHUB_TOKEN. To push from your laptop instead, make a GitHub Personal Access Token (Settings → Developer settings → PATs) with write:packages, then echo $PAT | docker login ghcr.io -u startr-trade --password-stdin.

VS Code Marketplace PAT (when you publish the extension):

  1. Create a free Azure DevOps account at dev.azure.com (Microsoft runs the VS Code Marketplace on it — counter-intuitive but required).
  2. Create a publisher at https://marketplace.visualstudio.com/manage.
  3. Azure DevOps → User settings → Personal Access Tokens → New: Organization All accessible organizations, Scopes Custom defined → Marketplace → Manage, set an expiry.
  4. Publish: npx vsce publish -p <PAT>, or store it as the VSCE_PAT secret and let CI run it. Optional Open VSX: account at open-vsx.org → token → npx ovsx publish -p <OVSX_TOKEN>.

Where the automation secrets go: GitHub repo → Settings → Secrets and variables → Actions → New repository secret: CARGO_REGISTRY_TOKEN, VSCE_PAT, etc. (and the PUBLISH_CRATES variable under the same page’s “Variables” tab). The workflows reference them as ${{ secrets.NAME }} / ${{ vars.NAME }}; they never appear in logs.


0. Before you make the repo public — a safety sweep

Do this first; making a repo public (and pushing its history) is hard to undo.

kanbanr has no accounts, passwords, or tokens of its own (single-writer CLI + read-only viewer — see the architecture overview), so there are no app secrets to leak. The real risks are your own content and your publish credentials:

  • Nothing of the board ships with the source. kanbanr’s own board lives in a sibling repository beside this one (../<name>.kanbanr), which is the layout the tool recommends to everyone (FEAT-041): a board inside a checkout is one git add -A away from being committed, and a sibling cannot be. Publishing it, if you ever want to, is a separate git remote add on that repository — not a decision about this one.
  • The legacy security.yaml is gone — an inert leftover from the removed auth model (ADR-0001). It was never tracked (git ls-files | grep security.yaml prints nothing in both repositories) and the file itself has been deleted.
  • Check git remotes for embedded credentials. A remote like https://user:token@host/repo.git leaks the token — use SSH remotes; run git remote -v to confirm.
  • Grep the tree and history for anything sensitive: git grep -niE "secret|token|password|api[_-]?key|@.*\.(com|net)" $(git rev-list --all).
  • If anything sensitive was ever committed, rewrite history (git filter-repo --invert-paths --path <file>) or, simplest, start a fresh repo from a clean checkout with no prior history — then rotate the leaked credential (treat anything that touched a commit as burned).
  • Dual-licensed MIT OR Apache-2.0 — done: LICENSE-MIT + LICENSE-APACHE added and license = "MIT OR Apache-2.0" set in api/Cargo.toml (workspace). (Replace the copyright holder the kanbanr authors with your legal name/handle if you prefer; if you’d rather stay MIT-only, delete LICENSE-APACHE and set license = "MIT".)
  • (Optional) Add # SPDX-License-Identifier: MIT OR Apache-2.0 headers where convenient.
  • Name check: ears-classifier is confirmed free on crates.io — the only crate name kanbanr needs, since kanbanr itself is not published there. Its first publish claims it. (Check npm too if you’ll reserve it, plus a domain if you want one.)
  • Third-party notices documented in THIRD_PARTY.md (vendored libgit2 GPL-2.0-WITH-linking-exception + OpenSSL Apache-2.0, statically linked — fine for MIT/Apache distribution). Still to do: run cargo deny check licenses (and add it to CI) to verify nothing incompatible slipped in.

2. Repo presentation (the “front page”)

  • README polish: one-line pitch, a screenshot or short GIF of the live monitor, the 60-second quickstart, the architecture diagram (reuse the architecture overview), and a clear “is this for me?” (personal, git-backed, Claude-driven).
  • Badges: CI status, license, latest release.
  • A docs/ index linking USER_GUIDE, DESIGN, ROADMAP, this file.
  • Capture screenshots in docs/src/images/ (make screenshots) (board, feature page, status page, milestones, docs). A reproducible Selenium-Grid-in-Docker screenshot tool lives in ../tools/screenshots/ — make screenshots regenerates them all against a locally-running kanbanr serve. (No more “login” screen to capture — the monitor has no auth.)

3. Contributor & community files

  • CONTRIBUTING.md — build/test/lint commands, the design constraints (CLI is the only writer), code style, PR flow, inbound=outbound licensing.
  • CODE_OF_CONDUCT.md — Contributor Covenant 2.1. (Fill in the contact method placeholder it ships with.)
  • SECURITY.md — private reporting (GitHub advisory / email) and the actual security model: no accounts/auth, the serve daemon is read-only on 127.0.0.1, and exposing it is the operator’s job (reverse proxy + TLS). Reports go to a GitHub private security advisory or kanbanr-oss-support@startr.trade.
  • Issue + PR templates under ../.github/ (ISSUE_TEMPLATE/bug_report.yml, feature_request.yml, config.yml, PULL_REQUEST_TEMPLATE.md).
  • Support promise stated as “personal project, best-effort, no SLA” (in CONTRIBUTING/SECURITY).
  • CODEOWNERS asks the startr-trade/kanbanr-maintainers team to review every pull request. Give that team the Maintain role on the repository (Settings → Collaborators and teams): GitHub only requests a review from a team with write access or more. Requiring a code-owner review in branch protection is optional — with a single maintainer it would block your own pull requests unless admins may bypass it.
  • (Optional) Enable GitHub Discussions for Q&A (the issue config.yml links to it).

4. CI (GitHub Actions)

  • ci.yml on a push to main and on pull requests (one run per change; a newer run cancels an older one): cargo fmt --check, cargo clippy -- -D warnings, cargo test --workspace, and npm ci && npm run build for the web, with cargo + vendored-libgit2/openssl caching.
  • Run everything locally first: make ci. It runs every CI check that can run off GitHub, reading each step from the workflow files, and lists what only GitHub can verify (the macOS and Windows legs, uploads, publishing). Nothing should reach the public repository that make ci has not passed.
  • Security scanning (FEAT-130): codeql.yml (Rust, TypeScript and the workflows themselves) and trivy.yml (dependencies, committed secrets, the Dockerfile) on main, on pull requests and weekly, reporting to the Security tab; release.yml scans the image before pushing it and stops on a fixable HIGH or CRITICAL finding; ci.yml’s supply-chain job fails on a disallowed licence or a known vulnerability (cargo deny, cargo audit, npm audit). Locally: make audit, make scan-deps, make scan-image, make codeql. Code-scanning uploads need a public repository on the free plan, so they are skipped until it is public.
  • Suppressions are time-boxed. A scanner finding with no reachable fix goes in .trivyignore.yaml with its reason and an expiry date; CI refuses an entry without both, and one past its date.
  • Actions and runners are pinned. Every third-party action is pinned to a commit SHA with its version in a comment (CI refuses one that is not), and runners name an image (ubuntu-24.04, macos-15, windows-2025), not -latest, so neither changes under the project on the provider’s schedule. Both are updated deliberately — there is no Dependabot.
  • Once public: Settings → Actions → General → “Require approval for fork pull request workflows” (all outside collaborators), so no workflow runs on an outsider’s pull request until a maintainer has read it; and consider requiring code-scanning results in the main ruleset once the first scans are clean.
  • Cross-platform matrix (ubuntu/macos/windows) for cargo test — already in ci.yml.
  • Image build + GHCR push on tags — handled by release.yml (see §5), so a separate docker.yml isn’t needed.
  • (Optional) Add the #[ignore]d testcontainers smoke (make itest) to CI.

5. Versioning & releases

  • SemVer + CHANGELOG.md (Keep a Changelog format) in place.
  • release.yml triggered on v* tags does it all: builds cross-platform kanbanr binaries (linux/macos-arm/macos-x86/windows) and attaches them to a GitHub Release, and pushes the Docker image to GHCR (ghcr.io/startr-trade/kanbanr).
  • kanbanr is not published to crates.io. A published crate cannot carry the built monitor (ADR-0009), so kanbanr ships only as the release archives, the install.sh / install.ps1 installers and the GHCR image; from source, make install builds the web assets first. kanbanr-cli, kanbanr-core and kanbanr-server declare publish = false.
  • Publish ears-classifier to crates.io. The workflow’s crates job publishes it — and only it — on a tag once repo variable PUBLISH_CRATES=true and the CARGO_REGISTRY_TOKEN secret (or Trusted Publishing) are set. See the credentials section above.
  • Releases come from main only. The release workflow refuses a tag whose commit is not on main, so merge first, then tag the merged commit. The docs site deploys only from main as well. Once the repository is public, add a tag ruleset for v* that lets only kanbanr-maintainers create or delete release tags.
  • Cut the first release: git tag v0.1.0 && git push origin v0.1.0, then verify the Release assets + the GHCR image appear. Move the [0.1.0] section in the changelog from Unreleased to dated.
  • Publish the VS Code extension (../editor/vscode/) to the VS Code Marketplace (vsce publish, needs VSCE_PAT) and optionally Open VSX (ovsx publish) once you’ve smoke-tested it (F5 launch). Keep its version in step with releases.

6. Distributing the skill

The skill is the product surface for Claude users — make it trivial to install:

  • Document manual install (symlink/copy skill/kanbanr → ~/.claude/skills/kanbanr) — already in the guide; keep it front-and-center.
  • Provide an install script / make install-skill that does the copy and verifies the CLI is on PATH.
  • Investigate publishing via the Claude plugin/skill marketplace (the lowest-friction path for users) and link it from the README once available.
  • If the MCP direction is taken (ADR-0006 on the board), document the MCP server install alongside the skill.

Distribution as a Claude Code plugin (FEAT-023)

The lowest-friction install path: package the skill and the enforcement hooks together as a Claude Code plugin, so users get both in one step instead of copying the skill and hand-editing their settings.json. The plugin files live at the repo root:

  • .claude-plugin/plugin.json — the plugin manifest. It references the existing skill via "skills": ["${CLAUDE_PLUGIN_ROOT}/skill"] (Claude Code discovers skill/kanbanr/SKILL.md) and registers the two hooks inline (SessionStart → session-start, Stop → stop-check) with ${CLAUDE_PLUGIN_ROOT}-relative command paths — never hardcoded absolute paths, since the plugin is copied into a cache dir on install.
  • .claude-plugin/marketplace.json — a one-plugin marketplace catalog (the plugin’s source is "./", the repo root). Relative-path sources resolve only when the marketplace is added via git, which is the intended distribution channel.

Users install with:

claude plugin marketplace add <github-owner>/kanbanr   # add this repo as a marketplace
claude plugin install kanbanr@kanbanr                  # install the plugin (skill + hooks)

(or the in-app /plugin marketplace add + /plugin install equivalents). Validate before publishing with claude plugin validate ..

Cross-platform hooks ship in two flavors: Linux/macOS use the .sh scripts; Windows uses the .ps1 equivalents (session-start.ps1, stop-check.ps1) via a hook entry with "shell": "powershell". Both have the same best-effort, never-block semantics. See ../skill/kanbanr/hooks/README.md.

The plugin carries only the integration, not the program. The kanbanr binary still ships separately (the GitHub Release archives and installers, or GHCR, per §5 — not crates.io) and must be on PATH; the hooks are best-effort and stay silent if it isn’t installed. Keep the manifest’s version in step with releases (or omit it to let the git SHA version the plugin).

  • Reserve the marketplace/plugin name and confirm it isn’t an Anthropic-reserved name.
  • Run claude plugin validate . in CI; verify install + the two hooks fire on a clean machine.
  • Link the claude plugin install one-liner from the README once the repo is public.

7. Pre-announcement checklist

  • Fresh clone → follow the README quickstart on a clean machine → you reach a populated board with no undocumented step. (Ideally on macOS/Windows too.)
  • make / cargo test / web build all green in CI.
  • LICENSE(s), CONTRIBUTING, SECURITY, CODE_OF_CONDUCT, CHANGELOG, THIRD_PARTY present.
  • Owner slug (startr-trade) + copyright/email placeholders filled (see the top of this file).
  • Names reserved (GitHub, and ears-classifier on crates.io); image + binaries published for the first tagged release.
  • Discussions enabled (optional), release.yml secrets/variables set if publishing.
  • Secrets sweep (§0) re-confirmed on the exact commit you’ll make public.
  • Screenshots (make screenshots) + a couple of example projects under data/projects/ (non-sensitive).

8. After launch (keep it alive without burning out)

  • Triage with labels; be explicit that it’s a personal project (best-effort).
  • Keep the board current so contributors know where to help — kanbanr ready is the answer to “what can I pick up?”.
  • Dependency updates are deliberate, not automatic: there is no Dependabot version-update config (it opened one pull request per major bump across four ecosystems). Update on your own cadence with cargo update / npm update and npm audit, plan major upgrades as board items, and re-run cargo deny. Dependabot alerts and security updates are repository settings, independent of any file, if you want to be told about vulnerabilities.
  • Cut releases from CHANGELOG.md; don’t let main drift far ahead of a tagged release.

Minimal first-pass (the smallest credible public release)

Most of the scaffolding now exists in the repo. The shortest path to a public v0.1.0 is just the manual steps only you can do:

  1. Create the startr-trade/kanbanr repository on GitHub (the owner slug is already filled in throughout).
  2. Run the secrets sweep (§0); remove data/security.yaml; decide what data/ to publish.
  3. git init (if needed), commit, push, make the repo public.
  4. Set up crates.io publishing for ears-classifier (token or Trusted Publishing, plus PUBLISH_CRATES=true); its first publish reserves the name. kanbanr itself is not published there.
  5. git tag v0.1.0 && git push origin v0.1.0 → the release workflow builds binaries + the GHCR image.
  6. Add screenshots to the README (make screenshots), then announce.

Everything else (Open VSX, npm reservation, MCP, badges polish) can follow.