A canonical, deterministic changelog framework with JSON IR and Markdown rendering.
Structured Changelog provides a machine-readable JSON Intermediate Representation (IR) as the source of truth for your changelog, with deterministic Markdown generation for human readability. It supports optional security metadata (CVE, GHSA, SARIF) and SBOM information.
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ CHANGELOG.json │ ───► │ Renderer │ ───► │ CHANGELOG.md │
│ (Canonical IR) │ │ (Deterministic) │ │ (Human-Readable)│
└─────────────────┘ └─────────────────┘ └─────────────────┘
- JSON IR is canonical — Markdown is derived, not the source of truth
- Deterministic rendering — Same input always produces identical output
- Keep a Changelog format — Compatible with keepachangelog.com -
github.com/olivierlacan/keep-a-changelog - Semantic Versioning — Follows semver.org conventions
- Extensible metadata — Optional security (CVE/GHSA/SARIF) and SBOM fields
- Spec + tooling together — Single source of truth for humans and machines
Keep a Changelog is the de-facto standard for human-readable changelogs. Structured Changelog implements this specification with a machine-readable JSON layer:
Keep a Changelog is the human spec; Structured Changelog is the structured implementation.
The generated CHANGELOG.md conforms to Keep a Changelog 1.1.0 formatting conventions, while adding JSON schema for machine parsing, security fields (CVE/GHSA/CVSS), and SBOM metadata.
Several tools generate changelogs from git history. Here's how Structured Changelog differs:
| Feature | Structured Changelog | conventional-changelog | git-cliff | chyle | semverbot |
|---|---|---|---|---|---|
| GitHub stars | — | ~8.4k | ~5.5k | ~160 | ~144 |
| Workflow | LLM/Human-assisted | Fully automated | Fully automated | Fully automated | Fully automated |
| Source of truth | JSON IR | Git commits | Git + templates | Git commits | Git tags |
| Output format | JSON → Markdown | Markdown | Markdown | Flexible | Tags only |
| Rendering | Deterministic | Template-based | Template-based | Configurable | N/A |
| Machine-readable | ✓ (JSON IR) | ✗ | ✗ | ✗ | ✗ |
| I18N/Localization | ✓ (6 languages) | ✗ | ✗ | ✗ | ✗ |
| Security metadata | ✓ (CVE/GHSA/CVSS) | ✗ | ✗ | ✗ | ✗ |
| SBOM metadata | ✓ | ✗ | ✗ | ✗ | ✗ |
| LLM optimization | ✓ (TOON format) | ✗ | ✗ | ✗ | ✗ |
| Version bumping | ✗ | ✓ | ✗ | ✗ | ✓ |
| Conventional commits | ✓ | ✓ | ✓ | ✓ | ✓ |
| Custom templates | ✗ (deterministic) | ✓ | ✓ | ✓ | ✗ |
| Language | Go | Node.js | Rust | Go | Go |
The key architectural difference is how the changelog is populated:
Traditional tools (git-cliff, conventional-changelog):
Git Commits → Template/Parser → Markdown
└─ Runs in CI/CD, fully automated, pattern-based
Structured Changelog:
Git Commits → LLM/Human → JSON IR → Markdown
└─ Semantic understanding, judgment calls, better prose
Why LLM-assisted? Pure automation works well for simple cases, but changelogs benefit from intelligence:
- Grouping: Consolidate 5 related commits into one meaningful entry
- Context: Explain why something changed, not just what
- Judgment: Categorize ambiguous changes correctly
- Quality: Write user-friendly descriptions, not commit messages
- Edge cases: Handle non-conventional commits gracefully
The parse-commits command outputs token-optimized TOON format (~8x reduction vs raw git log), making it practical to feed git history to an LLM for changelog generation.
When to use Structured Changelog:
- You want LLM-assisted changelog generation with human-quality prose
- You need a machine-readable changelog for automation or APIs
- You want deterministic output (same input → identical output)
- You track security vulnerabilities with CVE/GHSA identifiers
- You need SBOM integration for compliance
When to use other tools:
- conventional-changelog: You're in a Node.js ecosystem and want automatic version bumping
- git-cliff: You want maximum template customization with Rust performance
- chyle: You need to enrich changelog data from external APIs (Jira, GitHub)
- semverbot: You primarily need automated semantic version tagging
Note: git-chglog was previously the most popular Go-based changelog generator (~2.9k stars), but the project has been archived. Its maintainers recommend git-cliff as the successor.
brew tap grokify/tap
brew install structured-changelogThis installs the schangelog CLI (also available as structured-changelog).
go install github.com/grokify/structured-changelog/cmd/schangelog@latestgo get github.com/grokify/structured-changelog{
"irVersion": "1.0",
"project": "my-project",
"releases": [
{
"version": "1.0.0",
"date": "2026-01-03",
"added": [
{ "description": "Initial release with core features" }
]
}
]
}package main
import (
"fmt"
"os"
"github.com/grokify/structured-changelog/changelog"
"github.com/grokify/structured-changelog/renderer"
)
func main() {
// Load changelog from JSON
cl, err := changelog.LoadFile("CHANGELOG.json")
if err != nil {
panic(err)
}
// Render to Markdown
md := renderer.RenderMarkdown(cl)
fmt.Println(md)
}Validate a changelog:
schangelog validate CHANGELOG.jsonGenerate Markdown:
# Output to stdout
schangelog generate CHANGELOG.json
# Output to file
schangelog generate CHANGELOG.json -o CHANGELOG.md
# Full output (default: includes commit links and reference linking)
schangelog generate CHANGELOG.json
# Minimal output (no references/metadata/commit links)
schangelog generate CHANGELOG.json --minimalShow version:
schangelog versionCombine releases from multiple CHANGELOG.json files:
# Merge two changelog files
schangelog merge base.json additions.json -o CHANGELOG.json
# Prepend a single release file
schangelog merge CHANGELOG.json --release new-release.json -o CHANGELOG.json
# Skip duplicate versions
schangelog merge base.json additions.json --dedup -o CHANGELOG.jsonGenerate a skeleton CHANGELOG.json from git tag history:
# Create changelog from all semver tags
schangelog init --from-tags -o CHANGELOG.json
# Skip tags that aren't valid semver (e.g., v0.2.19.3)
schangelog init --from-tags --skip-invalid -o CHANGELOG.jsonGenerate changelogs in multiple languages:
# Generate in French
schangelog generate CHANGELOG.json --locale=fr -o CHANGELOG.md
# Generate in Japanese
schangelog generate CHANGELOG.json --locale=ja -o CHANGELOG.md
# Use custom translation overrides
schangelog generate CHANGELOG.json --locale=fr --locale-file=./custom-fr.jsonBuilt-in locales: English (en), German (de), Spanish (es), French (fr), Japanese (ja), Chinese (zh).
See the Localization Guide for customization options.
The CLI includes tools optimized for AI-assisted changelog generation. Commands default to TOON format (Token-Oriented Object Notation) for ~8x token reduction:
schangelog parse-commits --since=v0.3.0 # Structured git history (TOON)
schangelog parse-commits --since=v0.3.0 --format=json # JSON output
schangelog parse-commits --since=v0.3.0 --changelog=CHANGELOG.json # Mark external contributors
schangelog suggest-category "feat: ..." # Category suggestions
schangelog validate --format=toon CHANGELOG.json # Rich error outputSee the LLM Guide for prompts and workflows.
When a repository URL is provided, references (issues, PRs, commits) are automatically linked by default:
# Generate with linked references (default behavior)
schangelog generate CHANGELOG.jsonExample output:
- Add OAuth2 support ([#42](https://github.com/example/repo/issues/42), [`abc123d`](https://github.com/example/repo/commit/abc123def))Supports GitHub and GitLab URL formats.
External contributors are automatically attributed when an author field is set and maintainers are defined:
{
"maintainers": ["grokify"],
"releases": [{
"added": [{ "description": "New feature", "author": "@contributor" }]
}]
}Generates: - New feature by [@contributor](https://github.com/contributor)
Common bots (dependabot, renovate, etc.) are auto-detected and excluded from attribution.
By default, only notable releases are included in the generated output. Maintenance-only releases (those with only dependencies, documentation, build, tests, etc.) are excluded to keep changelogs focused on user-facing changes.
# Default: notable releases only
schangelog generate CHANGELOG.json -o CHANGELOG.md
# Include all releases
schangelog generate CHANGELOG.json -o CHANGELOG.md --all-releases
# Customize what's considered notable
schangelog generate CHANGELOG.json --notable-categories "Security,Added,Fixed"Notable categories: Highlights, Breaking, Upgrade Guide, Security, Added, Changed, Deprecated, Removed, Fixed, Performance, Known Issues
Non-notable (maintenance): Dependencies, Documentation, Build, Tests, Infrastructure, Observability, Compliance, Internal, Contributors
When using --all-releases, consecutive maintenance-only releases are automatically grouped:
## Versions 0.71.1 - 0.71.10 (Maintenance)
10 releases: 8 dependency update(s), 2 documentation change(s).Use --full to include all releases expanded (disables both notable-only filtering and grouping).
Structured Changelog supports 20 change types organized into 4 tiers. The core tier contains the standard Keep a Changelog categories, while higher tiers provide extended functionality.
| Tier | Description |
|---|---|
| core | Standard types defined by Keep a Changelog (KACL) |
| standard | Commonly used by major providers and popular open source projects |
| extended | Change metadata for documentation, build, and acknowledgments |
| optional | For deployment teams and internal operational visibility |
The following table shows all change types in canonical order, grouped by purpose:
┌─ OVERVIEW & CRITICAL ─────────────────────────────────────────┐
│ 1. Highlights standard Release summaries/key takeaways│
│ 2. Breaking standard Backward-incompatible changes │
│ 3. Upgrade Guide standard Migration instructions │
│ 4. Security core Vulnerabilities/CVE fixes │
├─ CORE KACL ───────────────────────────────────────────────────┤
│ 5. Added core New features │
│ 6. Changed core Modified functionality │
│ 7. Deprecated core Future removal warnings │
│ 8. Removed core Removed features │
│ 9. Fixed core Bug fixes │
├─ QUALITY ─────────────────────────────────────────────────────┤
│ 10. Performance standard Speed/efficiency improvements │
│ 11. Dependencies standard Dependency updates │
├─ DEVELOPMENT ─────────────────────────────────────────────────┤
│ 12. Documentation extended Docs updates │
│ 13. Build extended CI/CD and tooling │
│ 14. Tests extended Test additions and coverage │
├─ OPERATIONS ──────────────────────────────────────────────────┤
│ 15. Infrastructure optional Deployment/hosting changes │
│ 16. Observability optional Logging/metrics/tracing │
│ 17. Compliance optional Regulatory updates │
├─ INTERNAL ────────────────────────────────────────────────────┤
│ 18. Internal optional Refactors only (not tests) │
├─ END MATTER ──────────────────────────────────────────────────┤
│ 19. Known Issues extended Caveats and limitations │
│ 20. Contributors extended Acknowledgments │
└───────────────────────────────────────────────────────────────┘
Use tiers to control which change types to include:
# Validate: ensure changelog covers at least core types
schangelog validate --min-tier core
# Validate: require core + standard coverage
schangelog validate --min-tier standard
# Generate: output only core types (KACL-compliant)
schangelog generate --max-tier core
# Generate: include everything up to extended
schangelog generate --max-tier extendedEntries can include security-specific fields:
{
"description": "Fix SQL injection vulnerability",
"cve": "CVE-2026-12345",
"ghsa": "GHSA-xxxx-xxxx-xxxx",
"severity": "high"
}Track component changes with SBOM fields:
{
"description": "Update dependency",
"component": "example-lib",
"version": "2.0.0",
"license": "MIT"
}Structured Changelog addresses CHANGELOG.md specifically. Understanding the difference between changelogs and release notes is important:
| Aspect | CHANGELOG.md | RELEASE_NOTES_vX.Y.Z.md |
|---|---|---|
| Purpose | Cumulative history of all changes | Version-specific upgrade guide |
| Format | Concise bullet points | Detailed narrative with examples |
| Audience | Scanning/discovery | Users upgrading to specific version |
| Content | What changed | Why it changed + how to migrate |
| Scope | All versions in one file | Single version per file |
| Examples | Brief or none | Code samples, migration guides |
| Structure | Standardized (Keep a Changelog) | Flexible, project-specific |
| Content Type | CHANGELOG.json | RELEASE_NOTES |
|---|---|---|
| Breaking change flag | ✓ "breaking": true |
Detailed explanation |
| Migration guide | ✗ | ✓ With code examples |
| Code examples | ✗ | ✓ Before/after blocks |
| API changes | Brief description | Full context + examples |
| Dependency updates | Version numbers | Implications + upgrade steps |
Example: Breaking change workflow
In CHANGELOG.json — flag it concisely:
{
"changed": [
{ "description": "Module renamed to go-opik", "breaking": true }
]
}In RELEASE_NOTES_v0.5.0.md — provide migration details:
## Migration
Update all imports:
```go
// Before
import opik "github.com/example/old-name"
// After
import opik "github.com/example/go-opik"
```CHANGELOG.md:
- Quick reference for all historical changes
- Automated tooling (version bumps, release automation)
- Scanning to find when a feature was added/removed
RELEASE_NOTES_vX.Y.Z.md:
- Breaking change migration guides with before/after code
- Detailed feature explanations with usage examples
- Dependency change implications
- File-level change lists for major releases
See docs/guides/release-notes-guide.md for recommended release notes structure.
structured-changelog/
├── README.md
├── LICENSE
├── go.mod
├── changelog/ # JSON IR structs + validation
│ ├── changelog.go
│ ├── entry.go
│ ├── release.go
│ └── validate.go
├── gitlog/ # Git log parsing for LLM workflows
│ ├── commit.go
│ ├── conventional.go
│ ├── category.go
│ ├── parser.go
│ └── tags.go
├── renderer/ # Deterministic Markdown renderer
│ ├── markdown.go
│ └── options.go
├── cmd/schangelog/ # CLI tool (Cobra-based)
│ ├── main.go
│ ├── root.go
│ ├── validate.go
│ ├── generate.go
│ ├── parse_commits.go
│ ├── suggest_category.go
│ ├── list_tags.go
│ ├── init.go
│ └── merge.go
├── schema/ # JSON Schema definitions
│ └── changelog-v1.schema.json
├── docs/ # Documentation source (MkDocs)
│ ├── index.md
│ ├── changelog.md
│ ├── specification/
│ ├── guides/
│ ├── prd/
│ └── releases/
└── examples/ # Example changelogs
├── basic/
├── security/
└── full/
Contributions are welcome! Please read our contributing guidelines and submit pull requests.
MIT License - see LICENSE for details.