Skip to content

About

One-way mirror of https://gitlab.com/soundsystems/simple-changes; development and merge requests are on GitLab.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Simple Changes

Keep working. Merge when ready.

Simple Changes is an open-source, agent-neutral skill that turns ready work in a Git repository into focused, verified change proposals while preserving paused and concurrent work. Its first release provides a credential-free vertical slice: inspect a repository, classify stable and changing work, propose focused units, and validate the result without mutating Git or contacting a provider.

Quick start

Requires Bun 1.2 or later and Git. The CLI is a Bun TypeScript entry point; Node alone cannot run it.

Development happens on GitLab at https://gitlab.com/soundsystems/simple-changes, and a read-only mirror is kept in sync at https://github.com/soundsystems/simple-changes. Install from the mirror: older Skills CLI releases, and lock entries without a recorded source URL, re-resolve a stored source as GitHub shorthand, so a GitLab install may not update in place, while an install from the mirror records sourceType: github and skills update works with every release. The commands below therefore use the mirror; the installed tree is byte-identical either way.

Clone this repository, then from its root:

git clone https://github.com/soundsystems/simple-changes.git
cd simple-changes
bun install
bun run simple-changes initialize --mode sync
bun run simple-changes initialize --mode queue
bun run simple-changes preview
bun run simple-changes preview --json
bun run simple-changes release-notes
bun run simple-changes release-notes --check --repo .

Install it once globally with the Skills CLI:

bunx skills add https://github.com/soundsystems/simple-changes --skill simple-changes -g

Or copy it from the clone into the portable global Skills directory (a copy is not tracked by the Skills CLI, so update it the same way):

mkdir -p ~/.agents/skills
cp -R skills/simple-changes ~/.agents/skills/simple-changes

Agents with their own global skill directory can point to that one installation instead of keeping another copy. For example:

mkdir -p ~/.codex/skills ~/.claude/skills
ln -s ~/.agents/skills/simple-changes ~/.codex/skills/simple-changes
ln -s ~/.agents/skills/simple-changes ~/.claude/skills/simple-changes

Keep repository-local installations only for repository-specific forks. A repository can still commit .simple-changes.json; repository policy is independent of where the skill is installed and overrides global personal preferences. Before creating a symlink, move or remove any existing copy at its destination so an older installation is not left nested beneath it.

A compatible changelog provider declares itself with a machine-readable changelog-provider.json beside its SKILL.md (distribution, guidance version, and protocol capabilities); discovery falls back to installation-name inference only when no marker is present.

The installed directory is self-contained. Its release-note surface is read-only: release-notes displays Simple Changes' packaged public history. It does not author changelogs or provide release-writing guidance to users' agents, and does not contain the repository's release harness or model adapters. When simple-changelogs is available, Simple Changes can delegate a focused changelog unit and validate its handoff receipt; the changelog skill still owns classification and writing.

Repository-specific forks

Install Simple Changes globally once. Configure each repository first; create a fork only when its behavior cannot be expressed through settings or repository instructions.

What you want to change Use Why
Review, merge, deploy, question, or migration preferences Repository .simple-changes.json The shared skill already supports these choices.
Local commands, providers, deployment targets, or project conventions Repository instructions and supported config Project context does not require copying the skill.
Additional gates or workflow behavior that settings cannot express A repository-specific fork The skill's instructions or runtime need to change.
The same custom workflow across several projects A maintained shared fork Keep one customized source and update its consumers.
Refresh an existing fork while preserving its customizations update-local-forks Reconcile the fork with its pinned base and the updated global install.

From the target repository, create a fork with a distinct skill name and a short description of the behavior you intend to customize:

bun ~/.agents/skills/simple-changes/scripts/simple-changes.ts fork create \
  --name product-simple-changes \
  --deltas "Product-specific release gates and verification"

The command copies the complete installed skill to .agents/skills/product-simple-changes, renames its skill identity, and records the exact upstream commit after verifying every source file's bytes (a mismatch names the differing files; Finder .DS_Store files are ignored). The fork's description starts with its name and tells agents to use it instead of the global simple-changes skill in that repository (product here, taken from a <project>-simple-changes name), and its Codex metadata names and invokes the fork, so an agent that sees both skills loads the fork. It always writes inside the Git repository that contains the working directory or --repo, refuses an existing destination or a name that matches an installed skill, and leaves the global installation untouched. Pass --destination skills/product-simple-changes for a different repository-local location, --repo /path/to/repository to select a repository, or --json for machine-readable output. Upstream verification needs GitLab connectivity; --upstream /path/to/simple-changes uses a complete source checkout offline. An altered or incomplete global install must be refreshed before it can be forked with a verified pin.

The new copy starts with the same behavior as upstream. Edit its SKILL.md and runtime to implement the stated deltas, verify those changes, and commit the fork in its owning repository. The fork's own runtime checks that skill discovery can still load it (strict frontmatter, a name matching its directory, Claude Code and Codex invocation parity, and relative links that resolve):

bun .agents/skills/product-simple-changes/scripts/simple-changes.ts skill check

Use the fork by its distinct skill name; if you choose a location outside .agents/skills, point repository instructions to its SKILL.md. Claude Code loads project skills from .claude/skills, so for Claude Code create the fork with --destination .claude/skills/<name> or link that path to the fork. The provenance line below its title lets the updater find it:

Forked from `simple-changes` @ `<sha>`. Fork-specific deltas: ...

Then keep the fork current with the update-local-forks skill, which ships in this package and is meant for anyone who forked, not only maintainers:

bunx skills add https://github.com/soundsystems/simple-changes --skill update-local-forks -g

Ask an agent to update your local forks, or run the helper directly. It scans global skill roots and conventional project folders (Developer, Projects, Code, and src); pass --root for forks elsewhere. It plans one fork at a time against the fork's pinned upstream base and the global install, applies portable upstream changes, keeps every fork-specific edit and file, three-way merges files both sides changed, and reports conflicts for review instead of overwriting them. An upstream reference added or changed since the pin that the fork neither carries nor lists under ## Intentional omissions in its references/fork-maintenance.md holds the pin until the fork carries or records it, so new guidance cannot be skipped silently. It also advances the provenance pin only to the exact release commit the global install matches, and rewrites the pin, guidance version, and upstream version literals the fork's own checks pin. It never commits or pushes; the fork repository's own Simple Changes policy ships the update. Guidance updates therefore reach a fork's users the same way they reach everyone else: through the next write-capable run's one-time notice.

bun ~/.agents/skills/update-local-forks/scripts/update-local-forks.ts discover
bun ~/.agents/skills/update-local-forks/scripts/update-local-forks.ts plan \
  --fork path/to/fork --json > plan.json
bun ~/.agents/skills/update-local-forks/scripts/update-local-forks.ts apply --plan plan.json

In a source checkout, the maintainer drift checker still works for a quick pin comparison:

tooling/simple-changes/check-fork-sync.sh \
  path/to/fork/SKILL.md /path/to/simple-changes origin/main

What the current source provides

  • Resolves the canonical primary checkout across linked worktrees.
  • Treats sync, pull latest, and get us in line with main as a guarded local-only mode: exact-target fetch, fast-forward-only target updates, and conflict-preflighted feature-branch integration without push or history rewrite.
  • Detects first write-capable use and requires onboarding when neither repository nor personal preferences exist.
  • Detects changelog relevance separately from skill availability, negotiates exact protocol/schema capabilities, and coordinates delegation through closed classify, prepare, and final read-only verify transactions.
  • Treats every Web production deployment as a product release, requires a digest-bound version decision and verified full revision lineage, and emits a composite receipt binding that release to the observed deployment revision.
  • Recognizes run-only Emergency Ship intent: urgency selects an expedited path that preserves pre-deploy review, while only explicit deploy-before-review direction enables break-glass. Both retain durable reconciliation debt and avoid a second deployment only when the final canonical result is already live or immutable artifact equivalence is proven.
  • Inventories branches, stashes, local changes, worktrees, policy, and Git capabilities using argument-array subprocess calls.
  • Takes two read-only snapshots and preserves work that appeared or changed between them.
  • Holds one atomic active-loop lease for write-capable integration runs, persists a content-sensitive opening worktree manifest, runs local mutations under the lock from preflight through post-verification, awaits asynchronous callbacks, tracks guarded command process groups, terminates and rejects background descendants before normal lease release, and recovers only locks whose recorded processes are proven dead. Each new authoring agent receives one branch-bound, resumable isolated worktree from a pinned clean revision.
  • Records a lease heartbeat on every operation that already writes lease state, reports live, stale, or unknown liveness in loop status, and clears only a provably stale lease through an approved loop recover --stale-lease that preserves every worktree, branch, claim, and receipt.
  • Prunes proven-obsolete local checkouts, stale worktree metadata, and merged local branches without a lease through prune, so cleanup no longer depends on a run reaching loop finalize. It requires an approver and reason, supports --dry-run, names the containment method for each removal, and refuses to touch anything a lease that is not provably stale registers.
  • Builds a deterministic preview plan for stable work and validates path conservation, authority, and closed JSON schemas.
  • Classifies database and data-system changes without prescribing a provider, ORM, query language, or migration tool.
  • Audits proposal Markdown, including accidentally escaped newlines outside code, and with proposal audit checks a stored description against the Summary, Evidence, and Merge danger body shape (or a repository template's headings), its one-way, two-way, or unknown door and blast radius, and a signature block that ends the body.
  • Displays Simple Changes' packaged public release notes without exposing private HTML comments, unreleased notes, or developer history.
  • Checks that the latest public and developer release headings agree with the root package version in source-repository maintainer mode.
  • Normalizes forge and deployment evidence without assuming a numeric PR/MR ID or a particular delivery model.
  • Requires production receipts to cover the complete configured canonical-target inventory, then uses a bounded promote/recheck/provider-managed-target recovery sequence for verified artifacts instead of creating duplicate deployments.
  • Records explicit parity dispositions for repository-defined counterpart surfaces without forcing platform-identical interfaces or inferring separate release authority.
  • Treats requests for all proposals as complete-corpus operations that must paginate every relevant provider state.
  • Starts Ship runs with a concise proceed-without-waiting scope brief when authority already exists, then closes with exact shipped receipts and any review-driven changes made after the original proposal head.
  • Emits human-readable or JSON reports with stable exit codes.

The deterministic CLI creates only explicitly requested, lease-registered, branch-bound authoring worktrees for agents assigned to the same integration unit. Independent agents claim their own distinct worktrees and may keep editing and committing concurrently by default; only shared integration actions remain single-controller. Interrupted registration resumes only from a clean checkout on the recorded branch and revision. loop exec can run one explicitly supplied local argument-array command while the lease lock is held, but it does not decide to commit, push, merge, deploy, apply migrations, change secrets, update DNS, or clean branches. Those decisions remain capability- and authority-gated extensions followed by agents and provider adapters.

CLI

simple-changes fork create --name NAME --deltas TEXT
  [--destination PATH] [--upstream PATH] [--json] [--repo PATH]
simple-changes initialize --mode MODE
  [--ready] [--handoff ask|automatic|user-signaled]
  [--instruction-pointer add|leave] [--instruction-file PATH]
  [--scratch-file-rule add|leave]
  [--ui-artifacts]
  [--ui-versioning repository|number-and-date|date-only|number-only]
  [--changelog delegate-if-available|preserve-and-report|ask]
  [--changelog-install now|after-shipment|later|decline]
  [--concurrent-work allow-claimed|strict]
  [--production ask|allow|deny]
  [--shipping-mode standard|expedited]
  [--proposal-scheduling balanced|consecutive|parallel]
  [--questions blocking-only|always|never]
  [--scope user|repository|run] [--yes] [--json] [--repo PATH]
simple-changes setup [--finish review|integrate|ship]
  [--handoff ask|automatic|user-signaled]
  [--instruction-pointer add|leave] [--instruction-file PATH]
  [--scratch-file-rule add|leave]
  [--ui-artifacts]
  [--ui-versioning repository|number-and-date|date-only|number-only]
  [--changelog delegate-if-available|preserve-and-report|ask]
  [--changelog-install now|after-shipment|later|decline]
  [--concurrent-work allow-claimed|strict]
  [--production ask|allow|deny]
  [--shipping-mode standard|expedited]
  [--proposal-scheduling balanced|consecutive|parallel]
  [--questions blocking-only|always|never]
  [--scope user|repository|run] [--yes] [--json] [--repo PATH]
simple-changes acknowledge-update --guidance-decision accepted|reviewed|deferred
  [--agent-id ID] [--json] [--repo PATH]
simple-changes inventory [--json] [--repo PATH]
simple-changes status [--all [--root DIR ...]] [--json] [--repo PATH]
simple-changes preview [--json] [--repo PATH] [--settle-ms N]
simple-changes remote-inventory build --pages PAGES_FILE
  [--opening-remote-inventory FILE [--decisions FILE]] [--output FILE] [--json]
simple-changes loop start --mode MODE --agent-id ID [--changelog-required]
  [--opening-remote-inventory FILE] [--json] [--repo PATH]
simple-changes loop status [--json] [--repo PATH]
simple-changes loop verify --run-id ID [--json] [--repo PATH]
simple-changes loop guard --run-id ID --agent-id ID [--json] [--repo PATH]
simple-changes loop record-scope --run-id ID --agent-id ID
  --receipt FILE [--json] [--repo PATH]
simple-changes loop refresh-scope --run-id ID --agent-id ID
  --receipt FILE [--json] [--repo PATH]
simple-changes loop draft-outcome --run-id ID [--changelog-receipt FILE]
  [--output FILE] [--json] [--repo PATH]
simple-changes loop record-outcome --run-id ID --agent-id ID
  --receipt FILE [--approved-by USER --approval-reference REFERENCE]
  [--json] [--repo PATH]
simple-changes loop exec --run-id ID --agent-id ID [--json] [--repo PATH]
  -- COMMAND [ARG ...]
simple-changes loop recover --agent-id ID [--json] [--repo PATH]
simple-changes loop recover --stale-lease --run-id ID --agent-id ID
  --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop takeover --run-id ID --agent-id ID
  --manifest-digest SHA256 --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop allow --run-id ID --agent-id ID --worktree PATH
  --status-digest SHA256 --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop dispose-worktree --run-id ID --agent-id ID --worktree PATH
  --status-digest SHA256 --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop retain-worktree --run-id ID --agent-id ID --worktree PATH
  --status-digest SHA256 --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop retire-absent-worktree --run-id ID --agent-id ID
  --worktree PATH --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop adopt-worktree --run-id ID --agent-id ID
  --pause-receipt ID [--json] [--repo PATH]
simple-changes loop accept-paused-change --run-id ID --agent-id ID
  --pause-receipt ID [--json] [--repo PATH]
simple-changes loop reconcile-remote-branches --run-id ID --agent-id ID
  --receipt FILE [--json] [--repo PATH]
simple-changes loop recover-post-cleanup --run-id ID --agent-id ID
  --receipt FILE [--json] [--repo PATH]
simple-changes loop close-equivalent --run-id ID --agent-id ID
  --approved-by ID --reason TEXT [--evidence FILE ...] [--json] [--repo PATH]
simple-changes loop replan-status [--json] [--repo PATH]
simple-changes loop replan --run-id ID --agent-id ID
  --manifest-digest SHA256 --status-digest SHA256
  --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop archive-recorded --run-id ID --agent-id ID
  --manifest-digest SHA256 --status-digest SHA256
  --approved-by ID --reason TEXT [--json] [--repo PATH]
simple-changes loop end --run-id ID --agent-id ID [--reason TEXT]
  [--json] [--repo PATH]
simple-changes loop finalize --run-id ID --agent-id ID --reason TEXT
  [--json] [--repo PATH]
simple-changes worktree status [--json] [--repo PATH]
simple-changes worktree observe [--json] [--repo PATH]
simple-changes worktree request --claim-id ID --run-id ID
  --request-action request-pause|request-detach|notify-resume
  [--json] [--repo PATH]
simple-changes worktree claim --agent-id ID --worktree PATH --adapter ID
  [--owner-ref REF] [--json] [--repo PATH]
simple-changes worktree pause --agent-id ID --worktree PATH --run-id ID
  --disposition preserve-in-place|detach-clean-checkout --reason TEXT
  [--json] [--repo PATH]
simple-changes worktree detach --agent-id ID --worktree PATH
  --pause-receipt ID [--json] [--repo PATH]
simple-changes worktree attach --agent-id ID --claim-id ID [--json] [--repo PATH]
simple-changes worktree resume-ready --run-id ID --agent-id ID --claim-id ID
  [--json] [--repo PATH]
simple-changes worktree release --agent-id ID --claim-id ID [--json] [--repo PATH]
simple-changes worktree takeover --claim-id ID --agent-id NEW_OWNER
  --head SHA|none (--branch NAME | --detached) --status-digest SHA256
  --approved-by ID --reason TEXT [--release] [--json] [--repo PATH]
simple-changes worktree equivalence --worktree PATH [--target REF]
  [--json] [--repo PATH]
simple-changes branch audit --head REF --target REF [--json] [--repo PATH]
simple-changes prune --approved-by ID --reason TEXT [--target REF]
  [--dry-run] [--json] [--repo PATH]
simple-changes prepare-agent --run-id ID --agent-id ID --purpose SLUG
  [--json] [--repo PATH]
simple-changes workdir --agent-id ID [--json] [--repo PATH]
simple-changes workdir remove PATH [--json] [--repo PATH]
simple-changes scratch-file-rule refresh --instruction-file PATH
  [--json] [--repo PATH]
simple-changes release-notes [--check] [--json] [--repo PATH] [--version VERSION]
simple-changes negotiate-changelog CAPABILITIES_FILE [--json]
simple-changes validate-changelog-transaction REQUEST_FILE RECEIPT_FILE [--prior-receipt FILE] [--json]
simple-changes validate-changelog-release-set RECEIPT_FILE RECEIPT_FILE... [--json]
simple-changes release-gate --request FILE --receipt FILE [--prior-receipt FILE]
  --production ask|allow|deny [--already-live] [--production-authorized]
  [--version-authorized] [--json]
simple-changes release-delivery --changelog-receipt FILE --provider-receipt FILE
  [--request FILE] [--json]
simple-changes release-tag --run-id ID --agent-id ID --request FILE
  --receipt FILE [--prior-receipt FILE] --production ask|allow|deny
  [--production-authorized] [--already-live] [--tag-automation-authorized]
  [--dry-run] [--json] [--repo PATH]
simple-changes proposal-signatures --agent NAME --role authored|reviewed|merged
  [--base REF --head REF] [--changelog-receipt FILE] [--json] [--repo PATH]
simple-changes proposal audit --file FILE [--template FILE] [--json]
simple-changes skill check [--skill-dir PATH] [--json]
simple-changes validate KIND FILE [--json]
simple-changes verify-markdown FILE [--json]
simple-changes help

KIND is one of repo-policy, changelog-capabilities, changelog-request, changelog-receipt, emergency-shipping, initialization, inventory, change-plan, run-state, permission-bundle, provider-receipt, release-delivery-receipt, release-tag-receipt, remote-branch-reconciliation, remote-branch-ancestry, remote-branch-supersession, remote-inventory-pages, remote-inventory-decisions, release-consistency, release-notes, release-notes-pointer, proposal-audit, ready-work-receipt, ship-holds, loop-lease, loop-close-equivalent, migration-review, migration-pending, migration-apply-plan, post-cleanup-recovery, shipment-outcome, stale-lease-recovery, worktree-cleanup, worktree-coordination, worktree-takeover, worktree-equivalence, or branch-audit (the schema filenames under skills/simple-changes/evals/schemas/).

Before reapplying an old branch, use branch audit from the primary checkout to discover possible rebased or squashed replacements already reachable from the target. Full Original-Commit trailers provide explicit lineage; legacy discovery looks for matching subjects and shared paths. Results are advisory, bounded, and require independent review—not cleanup permission. See replacement lineage for preserving provenance and handling incomplete evidence.

Worktree claims and pause receipts are local, mode-0600 coordination evidence stored beneath the repository's common Git directory. A claim records only an opaque provider-neutral owner reference; it never stores prompts, message bodies, credentials, or provider tokens. loop adopt-worktree converts an exact owner-paused concurrent worktree into immutable preserved state. loop accept-paused-change refreshes an opening preserved baseline only from an exact receipt. worktree detach is deliberately separate from disposal: it allows a clean non-primary checkout with unique commits to be removed without force while retaining its branch at the exact HEAD, and worktree attach recreates only that recorded branch and path.

Host integrations must probe their capabilities before automating owner contact. worktree request returns the portable bounded request in state constructed, the owner adapter's capability profile listing the exact conditions the host layer must verify before automating, and a structured blocker, without sending anything or changing coordination or Git state. The runtime cannot see the executing host's delivery tools, so automatic is always false and an automatable profile returns a host-transport-unverified blocker: deliver through a tool your own host verifiably has for that exact owner, or relay the message, then wait for the owner's exact pause receipt. Codex desktop task tooling and qualifying same-host Claude Code installations (cross-session messaging enabled on macOS or Linux) can support exact discovery, delivery, and waiting once the host verifies every probe condition; native-Windows and cross-machine Claude Code sessions return a manual blocker. Cursor Cloud/SDK, Hermes TUI gateway, and controller-owned Grok Build sessions are supported only within their proven scopes. Every other mode returns a structured manual coordination blocker and leaves Git and the active lease unchanged.

Exit codes are stable: 0 success, 2 usage, 3 invalid input or contract, 4 inventory failure, 5 unsafe repository state, and 6 release notes older than the installed window (a link was printed instead; not an error).

release-notes renders the latest released section of the packaged Simple Changes CHANGELOG.md and omits pending Unreleased content and HTML comments. Use --version VERSION for an older published release or --json for automation. The installed copy carries the releases of the last six guidance versions; for an older release, --version prints a link to it in the full CHANGELOG.md with the notices of the guidance versions it introduced and exits 6. Maintainers regenerate the installed window at release with bun tooling/simple-changes/package-changelog.ts. An explicit --repo PATH may read another checkout without writing it. The source-maintainer-only --check mode requires --repo PATH and validates the latest public changelog, developer changelog, root package version, and the packaged SKILL.md metadata.version without changing them.

Policy

Write-capable Simple Changes tasks automatically initialize onboarding when no repository or personal policy exists, except Sync: it uses fixed local-only guardrails and never starts workflow-preference onboarding. Run the same checkpoint directly:

bun run simple-changes initialize --mode queue

Or establish global personal defaults explicitly, including outside a Git repository:

bun run simple-changes setup --scope user

On first use, it explains why onboarding appeared, shows the exact recommended workflow, and makes clear that nothing has been pushed, merged, deployed, or saved yet. The first choice is:

  1. Use recommended setup: Apply the safe, request-aware defaults and show a receipt before saving them.
  2. Customize: Explain and ask only unresolved preferences, one at a time.
  3. Use recommended setup for this run only: Continue without a preference file and ask again next time.

Customized setup uses small workflow and storage diagrams where they make a boundary clearer. It then asks:

  1. How far should I usually take ready work? Stop with a checked proposal, merge after approval, or also deploy and verify.
  2. For shipping, What should happen with production? Confirm first, deploy automatically when repository rules permit it, or stop before production.
  3. When relevant, How should changelog work be handled? Delegate when a compatible skill exists, preserve and report the work, or ask first.
  4. When saving multiple UI artifact iterations, How should their version names be chosen? Follow the repository convention (recommended), use a number and ISO date, use an ISO date only, or use a number only.
  5. When should I ask for permission or help? Only when blocked, before major steps, or skip unauthorized work without interrupting.
  6. Where should these preferences live? Visible repository policy, private personal fallback defaults, or this run without writing a preference file.
  7. When that scope has an existing instruction file, whether to add a short, managed Simple Changes pointer to the exact file.
  8. When adding the pointer, whether to ask if completed work is ready (recommended), hand it off automatically after implementation and checks, or wait until the user says it is ready.

Personal preferences are saved under the platform configuration directory and apply only when the repository has no policy. Teams may commit .simple-changes.json:

{
  "schemaVersion": 1,
  "guidance": {
    "disposition": "accepted",
    "version": 3
  },
  "changelogHandling": "delegate-if-available",
  "defaultFinish": "open-change-request",
  "handoffTiming": "confirm-ready",
  "proposalSignatures": "agent-and-version",
  "uiArtifactVersioning": "repository-convention",
  "questions": "blocking-only",
  "review": "repository-policy",
  "productionDeploy": "ask",
  "concurrentWork": "allow-claimed"
}

Meaningful installed-skill updates pause the next write-capable run once and explain the practical Simple Changes behavior or setting changes. Users can review the affected settings, keep their current choices, defer the update for that guidance version, or view detailed Simple Changes release notes. The decision is remembered so the same version does not prompt again.

When Simple Changelogs is also present, Simple Changes may offer a separate handoff for that skill to review its own settings or existing release notes. Simple Changes never performs that historical review itself, and no changelog action appears when the companion skill is absent.

allow-claimed is the default: independent agents may keep editing and committing on distinct, non-primary claimed worktrees while one integration controller handles push, proposal, merge, deployment, and cleanup operations. Create the claim immediately after git worktree add and before any project inspection, setup, generation, formatting, or editing in the new checkout. If a lease recorded the worktree as preserved before the claim appeared, its next guarded observation promotes the valid active claim to concurrent-author; ordinary claimed concurrency never requires loop allow or user approval. Set concurrentWork to strict to require repository-wide pauses. The legacy preserve value remains accepted and now follows the safe concurrent default.

A committed policy may also declare execGuard, an argv array such as ["bun", "scripts/exec-guard.ts"] that runs with the exec command appended before every loop exec child; a nonzero exit refuses the command before it starts. Use it, for example, to refuse a merge until hosted CI passes. It is repository code that runs with the agent's permissions, and personal preferences never supply one.

The active request overrides repository policy, repository policy overrides personal preferences, and personal preferences override the safe defaults. Run-only setup writes no file. Policy stores decisions, never credentials or transient run state. Resumable state for future mutation adapters belongs under .git/simple-changes/.

Instruction setup edits only an existing exact AGENTS.md, CLAUDE.md, or runtime-established global instruction file after confirmation. It never creates a missing file or duplicates its managed block. The recommended pointer asks whether implementation and checks are complete before Simple Changes takes over. A completed-work agent can inspect the saved behavior with initialize --mode handoff --agent-id <owner>; after confirmation, --ready resolves the normal queue, integrate, ship, or preview boundary. The exact claim owner identity lets a completed handoff release its own worktree claim.

UI iteration naming is conditional and applies only to deliberately preserved screenshots, design exports, static previews, or similar artifacts. Repository conventions always win. It does not rename UI source files or set Git, deployment, package, or release versions.

For non-interactive setup:

bun run simple-changes setup \
  --finish ship \
  --changelog delegate-if-available \
  --production ask \
  --questions blocking-only \
  --scope user \
  --instruction-file /exact/existing/AGENTS.md \
  --instruction-pointer add \
  --handoff ask \
  --yes

For a task that will preserve multiple UI iterations, add --ui-artifacts and --ui-versioning repository|number-and-date|date-only|number-only.

Add --scratch-file-rule add to also write an optional managed rule, in its own block, that gives every agent one scratch folder of its own for scratch files, captured output, proof bundles, and handoff notes, outside every project folder: the folder its brief names, the work directory a Simple Changes run reports, or a new folder under the session's scratch directory or the system temporary directory. An agent that starts another agent creates and names a folder for it, or names the one a Simple Changes run prepared for it, and when the task ends each agent deletes exactly its own folder, never another agent's and never by pattern across a shared directory, and leaves a folder a Simple Changes run reported for the run to remove. During a run, simple-changes workdir --agent-id ID prints that folder for the files an agent passes to the CLI, prepare-agent reports one per delegated author, and a clean finalization removes them. The block's markers never change, so initialize reports a block an earlier release wrote as stale, with a scratch-file-rule refresh --instruction-file PATH command that rewrites it in place; setup with the flag does the same.

Even an automatic ship preference does not authorize remote migrations, backfills, secrets or environment changes, DNS changes, store releases, or history rewrites. Those operations still require explicit, exact-target permission.

Before an authorized Ship run mutates repository or provider state, the agent summarizes the ready scope, planned checks/merge/release/deploy path, separate authority boundaries, and preserved work. This update is delivered while the run proceeds; it does not add a redundant permission prompt. The final response reports what actually shipped and identifies every material change made during review, including the new exact head and re-verification.

Security model

Simple Changes runs as the user who starts it, with no credential setting of its own: Git, SSH, and glab authenticate with whatever the user already configured, and the CLI runs its own network Git commands with terminal prompts disabled. Inventory and leases record remote URLs with any embedded credential removed. The CLI starts every program from an argument array, never through a shell. Each Git command it starts also runs with the user's own Git configuration, hooks, and helpers, which can widen what the command does: git status can refresh the index or run a configured filesystem monitor, and push.followTags adds annotated tags to a push. The statements below describe what Simple Changes itself asks for. Preview mode plans no mutation and itself commits, pushes, and records nothing. Each behaviour below reaches past an ordinary Git command in the current checkout, so it is listed with what triggers it, what it can touch, how to opt out, and the check that enforces the boundary. To report a vulnerability, see SECURITY.md.

Turn-end Stop hook (opt-in).

  • Triggered by: simple-changes harness stop-hook --harness claude-code|codex --write, which an agent runs only after the user agrees. initialize only reports whether the hook is installed. Once installed, the harness runs it at the end of every turn, in every repository.
  • Can touch: the write merges one Stop handler into ~/.claude/settings.json or ~/.codex/hooks.json (CLAUDE_CONFIG_DIR and CODEX_HOME are honored) and keeps every other setting. At each turn end the hook reads the harness's hook input, a per-user index of the runs each session controls (beside the personal preferences file), and each named run's lease, controller binding, and Git worktree records. It removes stale index entries and writes nothing else. It blocks the turn once while the session still controls an active run, then only warns.
  • Opt out: never pass --write, or delete the handler whose command contains loop turn-check from that file.
  • Enforced by: stopHookStatus in turn-guard.ts writes only with --write and refuses a script inside a linked worktree. The handler quotes its paths and ends in || exit 0, so a missing script or a failed check lets the turn end.

Repository execGuard.

  • Triggered by: an execGuard argv array in the primary checkout's .simple-changes.json, committed or not. It runs, with the command appended, before each command loop exec starts and before each fetch and write (mktag, push, update-ref) that release-tag runs inside its lease.
  • Can touch: whatever the agent's own permissions reach, like any repository script. It runs in the checkout with SIMPLE_CHANGES_RUN_ID and SIMPLE_CHANGES_REPOSITORY set, and its exit code only decides whether the command starts.
  • Opt out: remove execGuard from the repository policy. Personal preferences never supply one.
  • Enforced by: execGuardFor in exec-guard.ts reads it only from repository policy, the policy schema accepts only a non-empty array of strings, and assertExecGuardAllows runs it without a shell after every lease check. A guard can only refuse a command, so it applies without the policy trust receipt; that receipt gates the settings that grant authority (persistent push permission, automatic migration apply, break-glass ordering, and automatic production deploy). Review a guard as you would any script the agent runs.

Migration adapter executables.

  • Triggered by: simple-changes migration apply, which runs an adapter only when the decision it computes, the one migration decision reports, is auto-apply. That needs an auto-apply-* migrationHandling (which a repository policy gets only with its trust receipt), the exact provider, project, and environment in migrationTargets, a review with verified backup or rollback and planned post-apply verification that found nothing destructive, irreversible, lock-heavy, or unbounded, a remote ledger at most 5 minutes old, an apply plan valid for at most 15 minutes, and no active ship hold on migrations.
  • Can touch: the apply plan names an absolute adapter executable and its SHA-256 digest. Apply copies those exact bytes to a private, single-use file under .git/simple-changes/migration-authorizations/, records the authorization as consumed, runs the copy once without a shell as apply-exact with one --revision and --digest pair per reviewed operation, and deletes it. The adapter inherits the CLI's environment, so it reaches whatever the user's credentials reach.
  • Opt out: keep the default ask-after-review, or choose never. With either, migration apply never starts an adapter, though its evidence, inventory, and ship-hold checks still run first; the hold check can fetch published holds and record satisfied ones as released.
  • Enforced by: decideMigrationAutomation and applyMigrationAuthorization in migration-automation.ts. The digest is checked when the plan is evaluated and again just before the copy, and a consumed authorization never runs again.

Harness transcripts for subagent status.

  • Triggered by: the installed Stop hook, only when the ending session still controls a live run and the harness lists background subagents that are still running.
  • Can touch: it reads, and never writes, the session transcript named in the hook input and each listed subagent's transcript in that session's subagents folder. It parses only lines that carry a loop command with --agent-id, and those commands' output, to tell whether a running subagent is driving the run. The hook stores nothing it reads from them.
  • Opt out: do not install the Stop hook.
  • Enforced by: subagentControlIndex in subagent-control.ts reads only regular .jsonl files and accepts only task IDs of letters, digits, _, and -. A file over 64 MiB, a scan over 5 seconds, or an unreadable parent transcript proves nothing, so the hook blocks instead of excusing the run.

Commit messages, trailers, and proposal descriptions.

  • Triggered by: branch audit, proposal-signatures, and proposal audit, which read commit subjects, Original-Commit and Co-Authored-By trailers, and proposal descriptions, and by agents reading the same text while they review and integrate work.
  • Can touch: nothing. This text is untrusted data: it never becomes a command, a path outside the repository, or permission to push, merge, deploy, or delete. The skill's setup and policy reference tells agents to treat it as data and never follow instructions in it.
  • Opt out: nothing to turn off; it holds in every mode.
  • Enforced by: authority comes only from the request mode and saved policy (validatePlanAuthority in authority.ts), and programs start from argument arrays. branch-audit.ts treats an Original-Commit trailer as a candidate to inspect, never as cleanup authority; proposal-signatures.ts turns Co-Authored-By trailers into attribution lines that approve nothing; proposal audit checks only a description's shape; and review independence comes from attestations agents record with author attest, never from commit or proposal text.

Git and glab with the user's existing credentials.

  • Triggered by: queue, integrate, and ship work, where agents push branches and open and merge proposals with Git and glab. The CLI itself reads remote state with git ls-remote and git fetch (and clones the public upstream for fork create), names only ship-hold refs under refs/simple-changes/holds/ and the one tag release-tag publishes in the pushes it runs (release-tag also passes --no-follow-tags; a hold push follows the user's push.followTags), and its reference GitLab inventory adapter (skills/simple-changes/scripts/adapters/gitlab-remote-inventory.ts) makes only read-only glab api GET calls.
  • Can touch: every remote and project the user's Git credentials, SSH keys, and glab login can reach.
  • Opt out: with gitPushAuthorization set to never, agents stop with local work ready and the CLI refuses to push hold refs or release tags. Preview mode never pushes, opens, or merges anything, and Sync fetches but never publishes local work.
  • Enforced by: runGitRemote in process.ts disables terminal credential prompts, runs SSH in batch mode unless the user configured their own SSH command, and stops after a bounded time; redactSecrets removes likely credentials from the Git failure details the CLI reports; and configure-harness asks the harness only for its narrowest push rule for one verified remote, never for credentials or force-push (see push authorization). Branch protection, provider permissions, and approval bound to an exact head stay separate gates.

Development

bun run typecheck
bun run lint
bun run test
bun run eval

Check the bundled release-note fork against its Simple Changelogs source:

sh tooling/simple-changes/check-release-notes-fork-sync.sh \
  /path/to/simple-changelogs origin/main

bun run eval is deterministic and credential-free. The optional authenticated behavior harness runs the five release-note fixtures through a selected agent:

bun run behavior --adapter tooling/simple-changes/adapters/codex-eval.ts
bun run behavior --adapter tooling/simple-changes/adapters/claude-eval.ts
bun run behavior --adapter tooling/simple-changes/adapters/hermes-eval.ts
bun run behavior --adapter tooling/simple-changes/adapters/cursor-eval.ts
bun run behavior --adapter tooling/simple-changes/adapters/grok-eval.ts

See tooling/simple-changes/EVAL.md for isolation, authentication, model selection, and case-filtering details.

This repository is the production, open-source Simple Changes package. The portable skill, CLI, schemas, and references are tracked under skills/simple-changes. Fixtures, release-writing guidance, fork maintenance, and Codex, Claude Code, Hermes, Cursor, and Grok Build adapters are tracked under tooling/simple-changes for this repository's maintainers only. They are not packaged or installed with the public skill. Only interrupted adapter scratch files are ignored. The Simple Changelogs provenance pin and drift check provide a deliberate upstream mirror boundary without importing its app-specific surfaces.

Core contracts remain forge-, database-, and hosting-provider agnostic. Provider references translate those contracts into discoverable capabilities; they do not make any named provider, domain, branch convention, database, deployment command, or release channel mandatory.

Releases are numbered 0.<guidance>.<patch>. A release that advances the guidance checkpoint takes it as the minor version (0.27.0 introduces guidance 27), a fix that leaves guidance unchanged is a patch release, and each release is tagged v<version> on its merge commit.

See CONTRIBUTING.md for contribution guidance.

Credits

The proposal body shape (a smallest-view summary, before-and-after evidence, and a one-way or two-way door with its blast radius) adapts the pr skill from Matt Pocock's skills (v1.3.0, MIT), whose menu of summary views comes from Dex Horthy's show-me. The wording here is original, and the door is derived from this workflow's own migration, compatibility, and rollback evidence rather than judged from the diff. The separate Standards and Spec axes of an agent review adapt the same repository's code-review skill.

About

One-way mirror of https://gitlab.com/soundsystems/simple-changes; development and merge requests are on GitLab.

Resources

Code of conduct

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages