log-changes — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited log-changes (Agent Skill) and scored it 45/100 (orange). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 2 high-severity and 1 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 3 flagged
A base64 string of 128+ characters appears in a documentation file. Encoded prompt injection hides the hostile instruction in base64 — invisible to keyword filters — and relies on the agent's ability to decode it at runtime. There is no normal authoring reason to embed a multi-hundred-byte base64 blob in skill docs.
*.sig, SIGNATURES) outside the documentation.The text {match} tells the agent to skip the normal "ask the user first" gate. Used adversarially it removes the human-in-the-loop check before destructive or sensitive actions, turning a normally-gated agent into a fire-and-forget executor.
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
The changelog records notable changes to the distributed software. Every entry must answer: "Does this change affect someone who uses, upgrades, deploys, or integrates with the project?" If not, omit it.
Write for the project's consumers, not its implementers. Infer the audience and public product surface from usage documentation: a library's supported API can be the product, while an application's internal functions are not. Readers must understand what changed without reading source code or opening the linked issue. Default to one concise sentence stating the outcome. A changelog announces a change; documentation explains how to use it. A short sentence count does not excuse a long list of reasons, conditions, or caveats. Mention a critical compatibility consequence or limitation briefly and link to documentation for instructions.
Two formats are supported: Keep a Changelog 1.1.0, the default, and the highlights format in references/highlights-format.md. Versions follow Semantic Versioning 2.0.0 or a calendar scheme. Step 1 detects both; never assume them.
Detect the following constants from the project itself - do not ask the user unless detection fails. Inspect, in order: existing CHANGELOG.md entries, project documentation (README.md, CONTRIBUTING.md, docs/), and recent git commit messages.
Seven constants: the GitHub repository slug, the issue tracker with its base URL and key prefix, the subsystem labels, the entry unit, the bullet order within a category, the audience, and the product surface. How to detect each one, and what to fall back to when the first probe fails, is in references/project-constants.md.
Use the detected values everywhere a project key, tracker URL, or GitHub URL is needed. If a constant cannot be determined with confidence, ask the user once before proceeding. Do not guess or invent values.
Read the project's changelog (normally root CHANGELOG.md) and its current diff first; preserve existing entries, including uncommitted work. Use the project's established path throughout this workflow. If it has no changelog, create CHANGELOG.md from assets/changelog-template.md (see Step 5).
Detect the format and version scheme before writing anything. Read the preamble, any comment addressed to agents, and the headings under [Unreleased] and the newest release. ### Highlights or ### Improvements and fixes means the highlights format: follow references/highlights-format.md, which replaces Steps 4 to 6. ### Added, ### Fixed and the other Keep a Changelog categories mean Keep a Changelog. A file that switched formats keeps older releases in the old one; the preamble and the newest release decide, and older sections are never converted. When they disagree, ask once. State the detected format in your report.
For a single task, inspect its request, issue or PR when available, and implementation diff; skip the release-wide inventory in 2a-2c. For a release-wide update, inspect each PR as a whole rather than turning its commits into bullets. PRs supply evidence; independently meaningful user outcomes determine entries.
Add a dedicated entry for the current task's distinct user-facing outcome by default. Sharing a component, feature, epic, or release does not make two outcomes one change. Preserve previous entries and their references; a new issue is not a reason to extend an old bullet. Combine implementation steps only when they deliver the same outcome, with no independently meaningful capability or fix. An explicit request for a dedicated entry takes precedence over grouping conventions.
Refine a draft created for the current task as needed, not any entry written during the same session. If prior wording already covers exactly the same outcome or would become inaccurate, explain the overlap and ask before editing it; do not silently merge or add a duplicate. Release preparation alone does not authorize consolidation of existing entries.
#### 2a: Identify the release window
# Last tag, its date (window start), and recent tags for context
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null)
git log -1 --format="%ai" "$LAST_TAG"
git tag --sort=-version:refname | head -10If no tags exist, treat the entire git history as the unreleased window. The release window is: tag date (exclusive) → today.
#### 2b: List merged PRs in the window
Primary: milestone-based (when the project sets milestones on PRs; replace MILESTONE_PREFIX with the prefix the project uses, e.g. M10):
gh pr list --state merged --limit 100 \
--json number,title,mergedAt,milestone,labels \
--jq '.[] | select(.milestone != null and (.milestone.title | startswith("MILESTONE_PREFIX")))
| "\(.number)\t\(.mergedAt | split("T")[0])\t\(.title)"' \
| sort -t$'\t' -k2Fallback: date-based (when milestones are not set; replace YYYY-MM-DD with the tag date):
gh pr list --state merged --limit 200 \
--json number,title,mergedAt,labels \
--jq '.[] | select(.mergedAt >= "YYYY-MM-DDT00:00:00Z")
| "\(.number)\t\(.mergedAt | split("T")[0])\t\(.title)"' \
| sort -t$'\t' -k2For non-GitHub trackers, also fetch resolved tasks within the same window using the tracker's search API or web UI - see references/trackers.md for the section matching the detected tracker.
#### 2c: Inspect individual PRs and link to tracker tasks
# PR title, body (scope/intent), and constituent commits
gh pr view <NUMBER> --json title,body --jq '"\(.title)\n\(.body)"' | head -40
gh pr view <NUMBER> --json commits --jq '.commits[].messageHeadline'Extract issue/task references from the PR body using the extraction commands in references/trackers.md for the tracker detected in Step 1. Read each linked issue/task for the user-facing problem statement: PR titles are implementation-focused, tracker items are user/operator-focused.
Use the PR body's Scope & Context section (when present) to understand the user-facing or operator-facing impact. Do not rely on git log --oneline - it shows commits, not logical changes.
If the user describes changes verbally, use that as the primary source.
Before drafting, reduce the evidence to four facts:
The changelog records notable changes to the distributed software. A change is notable when it alters what a consumer of the project can observe: new capabilities, changed behavior, fixed bugs, security patches, removed features, or deprecation notices.
Apply the following filter to every commit or change before writing an entry.
The signals that always belong, the noise that never does, and the edge cases with their thresholds are tabulated in references/entry-filter.md. Open it before drafting, and again for any change you cannot place from the paragraph above.
When in doubt, ask: "If I were a consumer of this project reading this before upgrading, would I need to know this?" If the answer is no, leave it out.
Keep a Changelog only. Place every surviving entry under exactly one category:
| Category | When to use |
|---|---|
| Added | New user-facing capability: CLI command, integration, config option, API surface, UI capability |
| Changed | Existing behavior altered in a way consumers can observe |
| Deprecated | Still works but scheduled for removal in a future version |
| Removed | Previously available feature or interface deleted |
| Fixed | Bug fix - incorrect behavior corrected |
| Security | Vulnerability patch, dependency CVE fix |
The writing rules and audience-specific examples are in references/entry-style.md. They govern how much of the change survives into prose, when a CLI flag or API symbol earns its name, entry boundaries, and issue references. Read it before drafting any bullet.
Use assets/changelog-template.md as the structural template when creating CHANGELOG.md from scratch or adding the first versioned section. The template covers the preamble, [Unreleased] placeholder, a versioned section, and bottom comparison links.
Structural rules:
[Unreleased] section always present at the top.YYYY-MM-DD).### Removed if nothing was removed).Dated release sections are shipped history and are not edited when logging new work. New entries go under ## [Unreleased] only.
This collides with how a changelog is laid out: ### Added, ### Fixed, and the rest repeat once per version, so the first ### Fixed in the file usually belongs to the newest release, not to [Unreleased]. An edit anchored on a bare category heading lands in shipped history. Anchor instead on text unique to the Unreleased window - the preceding bullet's tracker URL, or the pair of the category heading and the following ## [x.y.z] header. When [Unreleased] lacks the category you need, create it inside that window rather than reusing a released version's heading.
When a deliberate edit does span released sections - a policy change such as purging a class of sentence from every entry - treat prose integrity as part of the operation. Removing a sentence from the middle or end of a bullet leaves dangling connectors and punctuation (... and never falls back to it. No new OAuth scope,), and a sweep leaves trailing whitespace behind. Re-read every bullet you touched as a whole sentence, not as a diff.
When cutting a release, choose the version number. Under a calendar scheme, follow the version rule in references/highlights-format.md; this table is for Semantic Versioning:
| Bump | Trigger |
|---|---|
| Major | Breaking API/CLI change for users or operators, removed public functionality |
| Minor | New feature, backward-compatible behavior change |
| Patch | Bug fix, security patch |
To cut a release:
## [Unreleased] with ## [X.Y.Z] - YYYY-MM-DD.## [Unreleased] section above it.git diff -- CHANGELOG.md touches only [Unreleased] (or, when cutting a release, only the section being released). Zero changes to any other dated section.,, ;, and, or so.prettier --check CHANGELOG.md, markdownlint, or the project's equivalent).#NNN.( or [.https://github.com/OWNER/REPO/issues/NNN links are present in the changelog.Reviewing someone else's changelog edit is not the authoring workflow run backwards. The rules above are enforced by where the insert is anchored, and a reviewer never sees the anchor - only the result. The result hides the one fact that decides whether the edit is legal.
The procedure for resolving every added hunk to its enclosing ## [ heading, and the placement, order, and width checks that travel with a misanchored bullet, are in references/reviewing-diffs.md. Open it before approving any pull request that touches CHANGELOG.md.
The recovery table for a changelog that is already in a bad state (missing comparison links, duplicate entries, a dated section edited by mistake, bullet order mixed across sections, a dangling clause left by a removed sentence) is in references/anti-patterns.md. Open it the moment you find the file wrong rather than the entry wrong.
One entry per commit, mechanical PR-to-entry mapping, merging distinct outcomes, git log --oneline as the primary source, mini user guide, implementation report, vague minimalism, diagnostic catalog, plain #NNN references, bare tracker keys, stating that nothing is required, anchoring an edit on a bare ### Added heading, silently rewriting a prior entry, and reading a hunk header as proof of the section. Each one's failure mode and its correction are in references/anti-patterns.md.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.