Create and publish a new version of docent to npm registry
Purpose: Create and publish a new version of docent to npm registry Owner: Maintainers Last Updated: 2025-10-17 Frequency: As needed for releases
This runbook covers the complete release process from version bumping through automated npm publishing. The workflow is:
Expected duration: 20-30 minutes (plus monitoring time)
git command line toolgh CLI (GitHub CLI) - installed and authenticatednpm - Node.js package managerBefore starting, ensure:
git checkout maingit statusgit pull origin mainPurpose: Validate code quality and documentation before release
Commands:
# Run full test suite
npm test
# Run build to ensure no compilation errors
npm run build
# Check markdown linting
npm run lint:md
# Search for temporary/debug code that shouldn't be released
git grep -n "console\.log\|debugger\|TODO.*remove\|FIXME.*before.*release\|XXX" src/ || echo "✓ No obvious debug code"
# Check for test-only markers (should be removed before release)
git grep -n "\.only\|\.skip" test/ && echo "⚠ Remove .only/.skip from tests" || echo "✓ No test-only markers"
# Verify no uncommitted changes
git status --short
# Check documentation quality (optional but recommended)
# This provides a detailed analysis of docs coverage
npm run docent audit . 2>/dev/null || echo "Note: docent audit available via MCP"
Validation:
.only or .skip in testsIf step fails:
git add . && git commit -m "chore: pre-release cleanup"Purpose: Decide what version number to use based on changes
Semantic Versioning Rules:
Commands:
# Check current version
npm pkg get version
# Review commits since last release
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -n "$LAST_TAG" ]; then
echo "Commits since $LAST_TAG:"
git log $LAST_TAG..HEAD --oneline --no-decorate
# Check what changed in public API
echo -e "\nAPI changes:"
git diff $LAST_TAG -- src/mcp/ --stat
else
echo "No previous tags found - this is the first release"
git log --oneline --no-decorate
fi
# Check CHANGELOG for any BREAKING markers
git grep "BREAKING:" CHANGELOG.md && echo "⚠ Breaking changes found in CHANGELOG"
Validation:
Decision Point:
Choose version bump type:
patch - Bug fixes only (0.5.0 → 0.5.1)minor - New features, no breaking changes (0.5.0 → 0.6.0)major - Breaking changes (0.5.0 → 1.0.0)If step fails:
Purpose: Bump version in package.json
Commands:
# Choose ONE based on Step 2 decision:
# For patch release (0.5.0 → 0.5.1)
npm version patch --no-git-tag-version
# For minor release (0.5.0 → 0.6.0)
npm version minor --no-git-tag-version
# For major release (0.5.0 → 1.0.0)
npm version major --no-git-tag-version
# Or set specific version
npm version 0.6.0 --no-git-tag-version
# Capture new version for later steps
NEW_VERSION=$(npm pkg get version | tr -d '"')
echo "New version: $NEW_VERSION"
Validation:
package.json shows new version numberpackage-lock.json also updated with new version (2 places)npm pkg get versiongit status shows both package.json and package-lock.json modifiedIf step fails:
Purpose: Document changes in this release for users
Commands:
# Open CHANGELOG.md in editor
$EDITOR CHANGELOG.md
# Review commits for this release (if needed)
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
[ -n "$LAST_TAG" ] && git log $LAST_TAG..HEAD --oneline
Required CHANGELOG Structure:
## [X.Y.Z] - YYYY-MM-DD
### Breaking Changes (if any)
- **BREAKING**: Clear description of breaking change
- Migration guide: how to update code
### Added
- New features and capabilities
- User-facing improvements
### Changed
- Changes to existing functionality
- Behavior modifications
### Fixed
- Bug fixes and corrections
### Technical
- Internal improvements, refactoring
- Dependency updates
- Development tooling changes
Validation:
If step fails:
git log --oneline --since="2 weeks ago"gh issue list --state closed --limit 20gh pr list --state merged --limit 20Purpose: Ensure documentation accurately reflects the release
Commands:
# Check for outdated version references
git grep -n "0\.[0-9]\.[0-9]" README.md docs/*.md | grep -v CHANGELOG.md | grep -v "version.*latest"
# Verify examples still work (manual check)
# Review key documentation files:
# - README.md - Installation and quick start
# - docs/guides/getting-started.md - Setup instructions
# - docs/guides/mcp-api-reference.md - API examples
# Check for references to removed features
# (manual review based on CHANGELOG)
Validation:
If step fails:
Purpose: Ensure everything builds and tests pass with new version
Commands:
# Clean previous build
rm -rf lib/
# Install dependencies (if any changes)
npm install
# Run full build
npm run build
# Run full test suite
npm test
# Verify package contents
npm pack --dry-run | head -20
# Check package size
npm pack --dry-run | grep "Tarball Contents"
Validation:
lib/ directory contains compiled JavaScript/bin, /lib, /templates, CHANGELOG.mdsrc/, test/, docs/, .git/If step fails:
files array in package.json if package contents wrongPurpose: Final review of all changes before committing
Commands:
# Check git status
git status
# Review all changes
git diff
# Specifically review version and changelog
git diff package.json
git diff CHANGELOG.md
# Verify no unexpected changes
git status --short
Validation:
If step fails:
git checkout -- <file> to discard unwanted changesPurpose: Create release commit and git tag
Commands:
# Get version from package.json
VERSION=$(npm pkg get version | tr -d '"')
echo "Preparing release v$VERSION"
# Stage release changes (IMPORTANT: include package-lock.json)
git add package.json package-lock.json CHANGELOG.md
# Add any documentation updates if made
# git add README.md docs/
# Create release commit
git commit -m "chore: release v${VERSION}"
# Create annotated tag
git tag -a "v${VERSION}" -m "Release v${VERSION}"
# Verify commit and tag
git log -1 --stat
git show "v${VERSION}" --stat
Validation:
chore: release vX.Y.ZvX.Y.Z (lowercase v)git show --statIf step fails:
git commit --amend -m "correct message"git tag -d vX.Y.Z && git tag -a vX.Y.Z -m "..."git reset HEAD <file>Purpose: Last check before pushing (triggers automated publish)
Commands:
# Verify working tree is clean
git status
# Verify all local CI checks pass
npm run build && npm test && npm run lint:md || echo "⚠ Local checks failed"
# Verify commit and tag are correct
git log -1 --oneline
VERSION=$(npm pkg get version | tr -d '"')
git tag -l "v${VERSION}"
# Verify you're on main branch
git branch --show-current
# Check remote CI status
gh run list --branch main --limit 5 --json conclusion,name,startedAt --jq '.[] | "\(.startedAt | split("T")[0]) \(.name): \(.conclusion)"'
Validation:
If step fails:
Purpose: Push commit and tag to trigger automated publishing
⚠️ POINT OF NO RETURN: Once you push the tag, GitHub Actions will automatically publish to npm. Verify everything in Steps 1-9 before proceeding.
Commands:
# Push commit and tag together
git push origin main --follow-tags
# Immediately check that push succeeded
git status
git ls-remote --tags origin | grep "$(npm pkg get version | tr -d '"')"
Validation:
If step fails:
git pull --rebase origin main then retrygit push origin vX.Y.ZPurpose: Watch the automated publish workflow complete
Commands:
# Open Actions page in browser
VERSION=$(npm pkg get version | tr -d '"')
gh run watch --repo tnez/docent
# Or check status from CLI
gh run list --workflow=publish.yml --limit 5
# View specific run details
gh run view --log
What the Publish Workflow Does:
npm run buildnpm testnpm publish --access publicExpected Timeline:
Monitoring Checklist:
If workflow fails:
See Troubleshooting section below for common issues and recovery procedures.
Purpose: Confirm package is available and installable
Commands:
# Wait for npm propagation (30-60 seconds)
sleep 30
# Check package on npm
VERSION=$(npm pkg get version | tr -d '"')
npm view @tnezdev/docent@${VERSION} version
# View full package info
npm view @tnezdev/docent
# Test installation in temporary directory
mkdir -p /tmp/test-npm-install
cd /tmp/test-npm-install
npm install @tnezdev/docent
./node_modules/.bin/docent --version 2>/dev/null || echo "Binary check"
ls -la node_modules/@tnezdev/docent/
# Cleanup
cd -
rm -rf /tmp/test-npm-install
Validation:
If step fails:
Purpose: Confirm GitHub release was created correctly
Commands:
# View release in browser
VERSION=$(npm pkg get version | tr -d '"')
gh release view "v${VERSION}" --web
# Or check from CLI
gh release view "v${VERSION}"
# Verify release notes
gh release view "v${VERSION}" --json body --jq '.body' | head -20
Validation:
If step fails:
VERSION=$(npm pkg get version | tr -d '"')
awk "/## \[${VERSION}\]/,/## \[/" CHANGELOG.md | head -n -2 | tail -n +3 > /tmp/release-notes.md
gh release create "v${VERSION}" --title "Release v${VERSION}" --notes-file /tmp/release-notes.md
rm /tmp/release-notes.md
Purpose: Final checks and cleanup
Commands:
# Verify CI is passing on main after push
gh run list --branch main --limit 3
# Check for any issues opened immediately after release
gh issue list --label "bug" --limit 5
# Verify no uncommitted changes
git status
# Pull any changes made by GitHub Actions (if any)
git pull origin main
Validation:
Post-Release Tasks:
Purpose: Notify users and contributors of new release
Commands:
# Get release URLs
VERSION=$(npm pkg get version | tr -d '"')
echo "GitHub Release: https://github.com/tnez/docent/releases/tag/v${VERSION}"
echo "npm Package: https://www.npmjs.com/package/@tnezdev/docent/v/${VERSION}"
Announcement Channels (as applicable):
Announcement Template:
🎉 docent v${VERSION} is now available!
**Highlights:**
- [Key feature 1]
- [Key feature 2]
- [Important fix]
**Install/Update:**
`npm install @tnezdev/docent@latest`
**Full changelog:** https://github.com/tnez/docent/releases/tag/v${VERSION}
Symptoms:
Resolution:
gh run view --loggh run rerunSymptoms:
Resolution:
NPM_TOKEN exists and is not expiredgh run rerun --failedSymptoms:
Resolution:
This means the version was already published (possibly from previous attempt).
Option 1: Skip npm publish (if version is correct)
# Version is already on npm - just verify
npm view @tnezdev/docent version
# If correct, just create GitHub release manually
VERSION=$(npm pkg get version | tr -d '"')
gh release create "v${VERSION}" --title "Release v${VERSION}" --notes "See CHANGELOG.md"
Option 2: Bump version again (if version was wrong)
# Delete remote tag
git push origin :refs/tags/vX.Y.Z
# Delete local tag
git tag -d vX.Y.Z
# Bump version again
npm version patch --no-git-tag-version
git add package.json
git commit --amend --no-edit
git tag -a "vX.Y.Z" -m "Release vX.Y.Z"
git push origin main --follow-tags --force-with-lease
Symptoms:
Resolution:
Create GitHub release manually:
VERSION=$(npm pkg get version | tr -d '"')
# Extract release notes from CHANGELOG
awk "/## \[${VERSION}\]/,/## \[/" CHANGELOG.md | head -n -2 | tail -n +3 > /tmp/release-notes.md
# Create release
gh release create "v${VERSION}" \
--title "Release v${VERSION}" \
--notes-file /tmp/release-notes.md
# Cleanup
rm /tmp/release-notes.md
Symptoms:
Resolution:
Immediate action:
# Deprecate the incorrect version
npm deprecate @tnezdev/[email protected] "Breaking changes - use X+1.0.0 instead"
# Create proper major version
npm version major --no-git-tag-version
# Update CHANGELOG to reflect proper versioning
git add package.json package-lock.json CHANGELOG.md
git commit -m "chore: release vX+1.0.0 (correcting semver violation)"
# Restart from Step 8
If critical bug discovered immediately after publish:
# 1. Deprecate the broken version
npm deprecate @tnezdev/[email protected] "Critical bug - use X.Y.Z+1"
# 2. Pull the tag locally
git fetch --tags
git checkout "vX.Y.Z"
# 3. Create hotfix branch
git checkout -b hotfix/vX.Y.Z+1
# 4. Fix the bug and test
# ... make fixes ...
npm run build && npm test
# 5. Merge to main and create new release
git checkout main
git merge hotfix/vX.Y.Z+1
npm version patch --no-git-tag-version
git add package.json package-lock.json CHANGELOG.md
git commit -m "chore: hotfix vX.Y.Z+1"
git tag -a "vX.Y.Z+1" -m "Hotfix vX.Y.Z+1"
git push origin main --follow-tags
# 6. Monitor new publish workflow
gh run watch
Note: Cannot unpublish from npm after 72 hours. Deprecation + new version is the only option.
Escalate if:
Escalation Contact:
After completing all steps:
Local:
Remote:
npm:
GitHub:
# Pre-flight
git checkout main && git pull origin main
git status # Must be clean
npm test && npm run build # Must pass
# Version and changelog
npm version patch --no-git-tag-version # or minor/major
$EDITOR CHANGELOG.md
# Final validation
npm run build && npm test
npm pack --dry-run
# Commit and tag
VERSION=$(npm pkg get version | tr -d '"')
git add package.json package-lock.json CHANGELOG.md
git commit -m "chore: release v${VERSION}"
git tag -a "v${VERSION}" -m "Release v${VERSION}"
# Push (triggers automated publish)
git push origin main --follow-tags
# Monitor
gh run watch
# Watch workflow progress
gh run watch
# Check workflow status
gh run list --workflow=publish.yml --limit 5
# View workflow logs
gh run view --log
# Check npm publication
npm view @tnezdev/docent version
# Test installation
npm install @tnezdev/docent
Important:
Gotchas:
--follow-tags only pushes annotated tags (created with -a)vX.Y.Z (lowercase v prefix)Related Procedures:
| Date | Author | Changes |
|---|---|---|
| 2025-10-17 | @tnez | Combined prepare-release and publish-package into single GitOps workflow |