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-APACHEfiles;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 inCODE_OF_CONDUCT.mdandSECURITY.mdiskanbanr-oss-support@startr.trade. The copyright line inLICENSE-MIT/LICENSE-APACHEand theauthorsfield inapi/Cargo.tomldeliberately 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
| Destination | What it’s for | Account | Credential to create | Where it lives |
|---|---|---|---|---|
| GitHub | Hosts the repo, runs CI, stores release binaries, serves the plugin marketplace | github.com (free) + 2FA | an SSH key for git push; CI’s GITHUB_TOKEN is automatic | SSH key on your laptop (~/.ssh); GITHUB_TOKEN is injected into Actions — nothing to store |
| crates.io | Publishes 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) + 2FA | an API token, or set up Trusted Publishing | CARGO_REGISTRY_TOKEN secret, or none (Trusted Publishing) |
| GHCR (GitHub Container Registry) | Publishes the Docker image so docker run ghcr.io/startr-trade/kanbanr works | your GitHub account | none — Actions uses the automatic GITHUB_TOKEN (packages: write) | nothing to store; locally use a PAT with write:packages |
| Claude Code plugin marketplace | Lets users claude plugin install kanbanr | your GitHub account | none — it’s just your public git repo | nothing — users add the repo URL |
VS Code Marketplace (only when you ship the extension — editor/vscode/) | Publishes the VS Code extension | Azure DevOps account (free) + a publisher at marketplace.visualstudio.com/manage | a Personal Access Token scoped Marketplace → Manage | VSCE_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 token | OVSX_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 name | npmjs.com + 2FA | an Automation token | NPM_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 forears-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):
- Sign in at crates.io with GitHub; enable 2FA.
- 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. - Manual publish:
cargo loginthen paste it (stored in~/.cargo/credentials.toml— never commit). - Automated publish: add it as the
CARGO_REGISTRY_TOKENsecret and set repo variablePUBLISH_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 → addstartr-trade/kanbanr+ therelease.ymlworkflow), then delete the token line. The job publishesears-classifieronly; every kanbanr crate declarespublish = false, so a straycargo publishof one of them is refused. - ⚠️ A published version is permanent — you can
cargo yanka bad version but never delete or reuse it. Double-check beforecargo 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):
- Create a free Azure DevOps account at dev.azure.com (Microsoft runs the VS Code Marketplace on it — counter-intuitive but required).
- Create a publisher at https://marketplace.visualstudio.com/manage.
- Azure DevOps → User settings → Personal Access Tokens → New: Organization All accessible organizations, Scopes Custom defined → Marketplace → Manage, set an expiry.
- Publish:
npx vsce publish -p <PAT>, or store it as theVSCE_PATsecret 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 onegit add -Aaway from being committed, and a sibling cannot be. Publishing it, if you ever want to, is a separategit remote addon that repository — not a decision about this one. - The legacy
security.yamlis gone — an inert leftover from the removed auth model (ADR-0001). It was never tracked (git ls-files | grep security.yamlprints 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.gitleaks the token — use SSH remotes; rungit remote -vto 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).
1. Licensing & legal
- Dual-licensed MIT OR Apache-2.0 — done:
LICENSE-MIT+LICENSE-APACHEadded andlicense = "MIT OR Apache-2.0"set inapi/Cargo.toml(workspace). (Replace the copyright holderthe kanbanr authorswith your legal name/handle if you prefer; if you’d rather stay MIT-only, deleteLICENSE-APACHEand setlicense = "MIT".) - (Optional) Add
# SPDX-License-Identifier: MIT OR Apache-2.0headers where convenient. - Name check:
ears-classifieris 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: runcargo 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 screenshotsregenerates them all against a locally-runningkanbanr 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, theservedaemon 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).
-
CODEOWNERSasks thestartr-trade/kanbanr-maintainersteam 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.ymllinks to it).
4. CI (GitHub Actions)
-
ci.ymlon a push tomainand on pull requests (one run per change; a newer run cancels an older one):cargo fmt --check,cargo clippy -- -D warnings,cargo test --workspace, andnpm ci && npm run buildfor 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 thatmake cihas not passed. - Security scanning (FEAT-130):
codeql.yml(Rust, TypeScript and the workflows themselves) andtrivy.yml(dependencies, committed secrets, the Dockerfile) onmain, on pull requests and weekly, reporting to the Security tab;release.ymlscans the image before pushing it and stops on a fixable HIGH or CRITICAL finding; ci.yml’ssupply-chainjob 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.yamlwith 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
mainruleset once the first scans are clean. - Cross-platform matrix (ubuntu/macos/windows) for
cargo test— already inci.yml. - Image build + GHCR push on tags — handled by
release.yml(see §5), so a separatedocker.ymlisn’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.ymltriggered onv*tags does it all: builds cross-platformkanbanrbinaries (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.ps1installers and the GHCR image; from source,make installbuilds the web assets first.kanbanr-cli,kanbanr-coreandkanbanr-serverdeclarepublish = false. - Publish
ears-classifierto crates.io. The workflow’scratesjob publishes it — and only it — on a tag once repo variablePUBLISH_CRATES=trueand theCARGO_REGISTRY_TOKENsecret (or Trusted Publishing) are set. See the credentials section above. - Releases come from
mainonly. The release workflow refuses a tag whose commit is not onmain, so merge first, then tag the merged commit. The docs site deploys only frommainas well. Once the repository is public, add a tag ruleset forv*that lets onlykanbanr-maintainerscreate 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, needsVSCE_PAT) and optionally Open VSX (ovsx publish) once you’ve smoke-tested it (F5 launch). Keep itsversionin 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-skillthat does the copy and verifies the CLI is onPATH. - 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 discoversskill/kanbanr/SKILL.md) and registers the two hooks inline (SessionStart→session-start,Stop→stop-check) with${CLAUDE_PLUGIN_ROOT}-relativecommandpaths — 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’ssourceis"./", 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 installone-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-classifieron crates.io); image + binaries published for the first tagged release. - Discussions enabled (optional),
release.ymlsecrets/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 underdata/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 readyis 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 updateandnpm audit, plan major upgrades as board items, and re-runcargo 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 letmaindrift 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:
- Create the
startr-trade/kanbanrrepository on GitHub (the owner slug is already filled in throughout). - Run the secrets sweep (§0); remove
data/security.yaml; decide whatdata/to publish. git init(if needed), commit, push, make the repo public.- Set up crates.io publishing for
ears-classifier(token or Trusted Publishing, plusPUBLISH_CRATES=true); its first publish reserves the name. kanbanr itself is not published there. git tag v0.1.0 && git push origin v0.1.0→ the release workflow builds binaries + the GHCR image.- Add screenshots to the README (
make screenshots), then announce.
Everything else (Open VSX, npm reservation, MCP, badges polish) can follow.