Quickstart#
logg generates beautiful changelogs from your GitHub releases using AI. Connect a repo, sync your releases, and publish changelogs that can be embedded anywhere.
Sign in with GitHub
Go to logg.sh/login and authenticate. We request read access to your repositories.
Create a project
Pick a GitHub repository or create a manual project. Set a slug — it becomes your public URL: logg.sh/your-slug
Sync releases
Hit Sync in the dashboard. AI analyzes commits between each release and generates structured changelogs with categories.
Publish and embed
Publish entries from the editor. Embed with React components, an iframe, or fetch from the REST API.
Concepts#
Project
A link between logg and a GitHub repository, or a standalone manual project. Each project has a unique slug used in public URLs, API endpoints, and embed configs.
Changelog entry
One version's release notes. Contains a version, title, AI-generated markdown with categories (features, fixes, improvements, breaking), and a publish state. Only published entries appear on public pages and the API.
Slug
A URL-safe identifier for your project (lowercase letters, numbers, hyphens). Auto-generated from the repo name, editable in project settings. Used in: logg.sh/slug, /api/v1/changelogs/slug, <Changelog slug="..." />.
React Components@logg/react#
npm install @logg/reactImport the stylesheet once in your app's entry point. If you use shadcn/ui, the components automatically pick up your theme via CSS variables.
import '@logg/react/styles.css'<Changelog />#
Renders a full changelog timeline for a project. Fetches data from the public API on mount.
import { Changelog } from '@logg/react'
import '@logg/react/styles.css'
export default function WhatsNew() {
return <Changelog slug="my-project" maxEntries={5} />
}| Name | Type | Default | Description |
|---|---|---|---|
| slug | string | — | Project slug from your logg dashboard |
| baseUrl | string | "https://www.logg.sh" | API base URL |
| maxEntries | number | all | Maximum number of entries to display |
| className | string | — | Additional CSS class on the root element |
| renderEntry | (entry) => ReactNode | — | Custom render function per entry (overrides default UI) |
| theme | "adaptive" | "logg" | "adaptive" | adaptive inherits your shadcn variables; logg applies logg's own monochrome palette |
By default the widget is theme-agnostic — it reads your shadcn variables and blends into whatever surrounds it. Pass theme="logg" when you would rather it look like logg than like your site.
<Changelog slug="my-project" theme="logg" />Custom rendering example:
<Changelog
slug="my-project"
renderEntry={(entry) => (
<div key={entry.version}>
<h3>v{entry.version} — {entry.title}</h3>
<p>{entry.summary}</p>
</div>
)}
/><ChangelogNotification />#
A fixed-position "What's new" button with a dot badge that appears when there's a new version. Tracks seen state in localStorage.
import { ChangelogNotification } from '@logg/react'
<ChangelogNotification
slug="my-project"
position="bottom-right"
/>| Name | Type | Default | Description |
|---|---|---|---|
| slug | string | — | Project slug from your logg dashboard |
| baseUrl | string | "https://www.logg.sh" | API base URL |
| position | "bottom-right" | "bottom-left" | "top-right" | "top-left" | "bottom-right" | Fixed position on screen |
| className | string | — | Additional CSS class on the root element |
| children | ReactNode | "What's new" | Custom trigger button content |
| theme | "adaptive" | "logg" | "adaptive" | adaptive inherits your shadcn variables; logg applies logg's own monochrome palette |
Hooks#
Use hooks directly if you need full control over rendering.
import { useChangelog } from '@logg/react'
function MyChangelog() {
const { data, error, loading } = useChangelog('my-project')
if (loading) return <p>Loading...</p>
if (error) return <p>Error: {error}</p>
return (
<div>
<h1>{data.project.name}</h1>
{data.changelogs.map(entry => (
<div key={entry.version}>
<h2>v{entry.version}</h2>
<p>{entry.title}</p>
{entry.categories?.features?.map((f, i) => (
<li key={i}>{f}</li>
))}
</div>
))}
</div>
)
}import { useLatestChangelog } from '@logg/react'
function NewVersionBanner() {
const { data, isNew, markSeen } = useLatestChangelog('my-project')
if (!isNew || !data) return null
return (
<div>
New: v{data.version} — {data.summary}
<button onClick={markSeen}>Dismiss</button>
</div>
)
}Styling#
Components use CSS variables from shadcn/ui. If your project uses shadcn, everything matches automatically. Otherwise, dark-theme fallback values are applied.
shadcn variables used
Override specific styles with --logg-* custom properties:
.logg-root {
--logg-accent: #f3f3f3;
--logg-accent-text: #f3f3f3;
--logg-border: rgba(255, 255, 255, 0.08);
--logg-text: rgba(255, 255, 255, 0.9);
--logg-text-muted: rgba(255, 255, 255, 0.4);
}REST API#
Public read-only API. No authentication required. Rate limited to 60 requests per minute per IP.
GET /api/v1/changelogs/:slug#
Returns all published changelogs for a project.
curl https://www.logg.sh/api/v1/changelogs/my-project{
"project": {
"name": "My Project",
"slug": "my-project",
"description": "An awesome project",
"repo": "owner/my-project"
},
"changelogs": [
{
"version": "1.2.0",
"title": "Dark mode and performance improvements",
"summary": "Added dark mode support and improved load times by 40%",
"content": "## New Features\n- Dark mode support...",
"contentHtml": "<h2>New Features</h2><ul><li>Dark mode support...</li></ul>",
"categories": {
"features": [
"Dark mode with system preference detection",
"Keyboard shortcuts for common actions"
],
"improvements": [
"Reduced bundle size by 40%",
"Faster page transitions"
],
"fixes": [
"Fixed auth redirect loop on Safari"
]
},
"publishedAt": "2026-02-10T12:00:00.000Z",
"releaseDate": "2026-02-10T12:00:00.000Z"
}
]
}GET /api/v1/changelogs/:slug/latest#
Returns only the latest published changelog entry.
curl https://www.logg.sh/api/v1/changelogs/my-project/latest{
"version": "1.2.0",
"title": "Dark mode and performance improvements",
"summary": "Added dark mode support and improved load times by 40%",
"publishedAt": "2026-02-10T12:00:00.000Z",
"releaseDate": "2026-02-10T12:00:00.000Z"
}Response headers include X-RateLimit-Remaining and Cache-Control: public, s-maxage=60, stale-while-revalidate=300.
iframe Embed#
Embed your changelog on any page with a simple iframe. The embed sends a postMessage with its height so you can auto-resize.
<iframe
src="https://www.logg.sh/my-project/embed"
width="100%"
height="600"
frameborder="0"
style="border: none;"
></iframe>Auto-resize with JavaScript:
<script>
window.addEventListener('message', (e) => {
if (e.data?.type === 'logg-sh-resize') {
document.querySelector('iframe').style.height = e.data.height + 'px'
}
})
</script>Detection & versioning#
logg watches your repo and decides when a changelog entry should exist. Pick the mode that matches how you ship — the project wizard analyzes your last 90 days and recommends one:
Release published — GitHub or GitLab releases drive entries.
Tag pushed — any tag (optionally filtered by a glob like v*) cuts an entry — no releases needed.
PR merged — every merge into the watched branch becomes an entry.
Just commits — pushes accumulate into a window that cuts after 8 quiet hours (7-day max). Flush anytime with the Cut now button or `logg cut`.
Manual — entries come only from the dashboard, CLI, or MCP.
When a trigger carries no tag, the project's versioning scheme names the entry: mirror existing tags, CalVer (2026.08.15), inferred SemVer from conventional commits, or a plain counter. A version bump in package.json, pyproject.toml, or Cargo.toml always cuts an entry with that exact version. Entries are drafts by default — flip the publish policy to auto-publish when you trust the pipeline. Drafts flag AI guesses ("needs review") so you know what to check before publishing.
Webhooks#
logg can automatically generate and publish changelogs when you create a GitHub release. Set up a webhook in your repo settings:
Go to repo Settings > Webhooks > Add webhook
Payload URL
https://www.logg.sh/api/github/webhookContent type
application/json
Secret
Set your GITHUB_WEBHOOK_SECRET value. Used for HMAC-SHA256 signature verification.
Events
Select "Releases", "Pushes", and "Pull requests" — which events matter depends on your project's detection mode. logg gathers the evidence, writes the entry, and publishes it (or drafts it for review) per your publish policy. New projects register this webhook automatically; set it up manually only if that failed.
Outbound webhooks#
logg can also call your endpoint on every publish: add a webhook channel in project settings and you'll get a signed POST with the entry. Verify it by recomputing HMAC-SHA256 with your signing secret over {timestamp}.{body} and comparing to the x-logg-signature header (sha256=<hex>). Deliveries carry an x-logg-idempotency-key that stays stable per entry and channel, so replays are safe to deduplicate.
Agent-readable feeds#
Every public changelog is also served in formats agents and scripts can consume directly: /your-project/llms.txt (compact index), /your-project/changelog.md (full markdown), and /your-project/changelog.json (JSON Feed 1.1). All CORS-open and cached.
CLI@logg/cli#
Manage changelogs from the terminal. Authenticate once, then create, publish, and sync changelogs without leaving your shell. Zero token overhead compared to MCP.
npm install -g @logg/cliOr use without installing:
npx @logg/cli <command>Authentication#
The CLI uses GitHub OAuth via a browser redirect. Run logg login to authenticate — it opens your browser, you sign in with GitHub, and the CLI receives a 365-day token stored in ~/.config/logg/credentials.json.
logg login # opens browser for GitHub OAuth
logg whoami # show current user and token expiry
logg logout # clear stored credentialsCommands#
All commands use --project to reference a project by its slug.
# List all projects
logg project list
# Create a manual project
logg project create --name="My App" --slug=my-app
# Create a project linked to GitHub
logg project create --name="My App" --slug=my-app --github=owner/repo# List changelogs
logg changelog list --project=my-app
# Add a changelog with inline content
logg add --project=my-app --version=1.2.3 --content="## Changes\n- Fixed bug"
# Add from a file
logg add --project=my-app --version=1.2.3 --file=CHANGELOG.md
# Publish / unpublish
logg publish --project=my-app --version=1.2.3
logg unpublish --project=my-app --version=1.2.3# Sync releases and generate changelogs with AI
logg sync --project=my-app
# Regenerate AI content for a specific version
logg generate --project=my-app --version=1.2.3
# Cut the open commit window into an entry (commit detection mode)
logg cut --project=my-appCLI vs MCP#
| CLI | MCP | |
|---|---|---|
| Token cost | Zero per-message overhead | ~1,500 tokens/message |
| Auth | One-time login, 365-day token | Re-auth on token expiry |
| Usage | Direct terminal commands | Natural language via AI tools |
| Best for | CI/CD, scripts, quick actions | Conversational workflows |
Both use the same API endpoints and can be used interchangeably.
MCP Server#
Manage changelogs from AI coding tools via the Model Context Protocol. Supports OAuth 2.1 with PKCE — your tool handles the flow automatically.
Server URL
https://www.logg.sh/api/mcpClaude Code#
{
"mcpServers": {
"logg": {
"url": "https://www.logg.sh/api/mcp"
}
}
}Claude Code will detect OAuth, open a browser for GitHub sign-in, and store the token. After that, tools like list_projects and sync_project are available in conversations.
Cursor#
{
"mcpServers": {
"logg": {
"url": "https://www.logg.sh/api/mcp"
}
}
}Codex#
{
"mcpServers": {
"logg": {
"url": "https://www.logg.sh/api/mcp"
}
}
}Available Tools#
| Tool | Params | Description |
|---|---|---|
| create_project | name, slug, description?, githubOwner?, githubRepo? | Create a new project (omit GitHub fields for manual) |
| list_projects | — | List all your projects |
| get_project | projectId | Get project details |
| list_changelogs | projectId | List changelogs for a project |
| get_changelog | projectId, changelogId | Get full changelog content |
| create_changelog | projectId, version, content, title? | Create a new changelog entry |
| update_changelog | projectId, changelogId, title?, content?, summary?, categories? | Update an existing entry |
| publish_changelog | projectId, changelogId | Make entry visible on public page |
| unpublish_changelog | projectId, changelogId | Hide entry from public page |
| sync_project | projectId | Sync GitHub releases and generate with AI |
| generate_changelog | projectId, changelogId | Regenerate AI content for an entry |
Example — publish all draft changelogs from Claude Code:
Use logg to list my projects, then list changelogs for "my-project"
and publish any that are still in draft.OAuth Details#
The MCP server implements OAuth 2.1 with PKCE (S256). Most MCP clients handle this automatically. If you're building a custom integration:
GET /.well-known/oauth-authorization-serverGET /.well-known/oauth-protected-resourcePOST /api/oauth/registerGET /api/oauth/authorizePOST /api/oauth/tokenTokens expire after 1 hour. Clients re-authenticate automatically when tokens expire.