agentleFS
XindaanXindaan/claude-skills/skills/public-mirror/SKILL.md

public-mirror

Skill1 starsChanged 31 days agoMITView on GitHub

Baut und pflegt oeffentliche Ableger privater Arbeits-Repos — Neuanlage, Sync und das Pre-Push-Leak-Gate. Verwende diesen Skill bei "mach ein public Repo aus ...", "sync das public Repo", "pruefe vor dem Push", "public Ableger aktualisieren", "kann das public werden", "Leak-Check vor Veroeffentlichung", "oeffentlichen Snapshot bauen". Auch wenn ein bestehendes Paar privat/public auseinanderzulaufen droht oder ein Audit der public History gefragt ist.

  • Reads credentials
  • Commits and pushes

The file

We split this skill into the rules it gives an agent

4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈3

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Allowlist, nicht Blocklist: Default ist *privat*. Eine neu angelegte Datei landet draussen, bis jemand sie ausdruecklich freigibt.

    line 17
  2. Distinctive:

    Commit ist noch abwendbar, ein gepushter nicht.

    line 143
  3. Distinctive:

    Test ins private Repo.

    line 272
  4. Very specific:

    Default-Arm *) return 1 ;;, also public.

    line 450

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Public-Mirror

Ein privates Arbeits-Repo bleibt privat. Der oeffentliche Ableger ist ein eigenes GitHub-Repo mit eigener Wurzel-History — nie ein Filter-Zweig des privaten.

Nicht verhandelbar

  1. Frische History. Der Ableger startet mit eigenem Wurzel-Commit. Kein filter-repo-Abkoemmling des privaten Repos, nie push --mirror, nie push refs/*.
  2. Allowlist, nicht Blocklist. Default ist privat. Eine neu angelegte Datei landet draussen, bis jemand sie ausdruecklich freigibt.
  3. Zwei Gates, eine Marker-Quelle. Inhalts-Gate vor dem Commit + fail-closed pre-push-Hook. Beide sourcen dieselbe Marker-Datei.
  4. Quelle ist git ls-files. Nie den Worktree kopieren — sonst wandern untracked Dateien mit.
  5. Read-only-Regel bei Audits. Auf einem bereits publizierten Repo nie ungefragt filter-repo, force-push oder gc. Rewrite ist eine Einzelfreigabe pro Repo.

Sonderfall: Repo hat gar kein privates Elternteil

Nicht jede Veroeffentlichung ist ein Ableger. Ein Repo, das von Anfang an allein stand und nur auf private steht, wird durch einen Sichtbarkeits- Flip public — kein Sync-Skript, keine Allowlist, kein zweites Repo. Die Mirror-Maschinerie waere hier Ballast; es gilt stattdessen eine Veroeffentlichungs-Checkliste:

  1. Alle Leak-Klassen aus patterns.md gegen alles scannen, was der Server kennt — nicht gegen den Worktree: main, alle Tags, und refs/pull/*/head. Lokale, nie gepushte Branches werden nicht public.
  2. LICENSE. Ohne Lizenz heisst public "alle Rechte vorbehalten" — das Repo ist sichtbar, aber fuer Dritte unbenutzbar. Meist der eigentliche Zweck der Veroeffentlichung und trotzdem der haeufigste Fehlbetrag.
  3. Steuerdateien (STATE.md/TASK.md) untracken und aus der History entfernen. Ein blosses git rm laesst sie in allen Alt-Commits lesbar. Danach .gitignore + Verweise in verbleibender Doku aufloesen, sonst zeigt sie auf Dateien, die es im Repo nicht gibt.
  4. Rewrite VOR dem Flip, nie danach — solange privat, ist jeder Fehler noch folgenlos korrigierbar. Reihenfolge: Inhalt committen → Rewrite → force-push → Remote verifizieren → dann erst umschalten.
  5. Restrisiko benennen: nach dem force-push bleiben die alten Commits serverseitig unerreichbar liegen und sind per SHA noch eine Weile abrufbar. Airtight waere nur ein frisches Repo — Preis: Stars, Issues und PR-History. Bewusste Abwaegung des Owners, keine stille Entscheidung.

History-Strategie — Entscheidungsbaum

Wird der Ableger aus dem privaten Repo REGENERIERT?
├─ ja  → Squash-Snapshot: genau 1 Commit, Folge-Syncs per
│        `git commit --amend --reset-author`
│        + `git reflog expire --expire=now --all && git gc --prune=now`
│        Vorteil: ein spaeter enger gezogener Filter wirkt RUECKWIRKEND.
│        Preis: jeder Folge-Sync ist ein force-push.
│        **`--reset-author` ist nicht optional.** `--amend` allein tauscht nur
│        den COMMITTER und laesst den Author stehen — eine spaeter umgestellte
│        `user.email` (z. B. auf `<id>+<user>@users.noreply.github.com`) wirkt
│        deshalb nie, und die alte Klarnamen-Mail bleibt in jedem Folge-Sync
│        stehen. Nach dem Sync pruefen, nicht annehmen:
│        `git log --format='%an %ae|%cn %ce' --all | sort -u`
│        **CHANGELOG ist hier PFLICHT, nicht Kuer.** Ein Snapshot hat genau
│        einen Commit — die History traegt fuer einen fremden Leser null
│        Information darueber, was sich je geaendert hat. Der CHANGELOG ist
│        das einzige Artefakt, das Entwicklung ueberhaupt sichtbar macht.
│        Gemessen 27.07.2026: drei Ableger, alle 1 Commit, zwei ohne CHANGELOG.
└─ nein → Der Ableger wird eigenstaendig weiterentwickelt (CI, Issues, PRs).
          Organische History ist dann richtig — aber sie ist UNWIDERRUFLICH:
          alles muss beim ersten Push stimmen. Pflicht: Guard + CHANGELOG.

NIE: akkumulierende Snapshot-History (jeder Sync ein Commit obendrauf, Inhalt
komplett neu erzeugt). Das ist die schlechteste Kombination — der Sync denkt
in "aktueller Stand", die History haelt jeden frueheren fest. Realfall: ein
Wohnort stand 151x in zwei Snapshots; der Scrub kam einen Tag spaeter und
konnte nichts mehr retten.

A) Neuen Ableger anlegen

  1. Inventur. git -C <priv> ls-files | wc -l. Jede Datei genau einer Klasse zuordnen: public, privat, gescrubbter Override.
  2. tools/sync-public.sh anlegen mit ist_privat() als case — Default-Arm *) return 0 ;; (= privat). Public wird nur, was eine explizite Zeile freigibt. Praefix-Muster (analysis/site-pool*), nicht exakte Pfade: Varianten entstehen spaeter.
  3. Overrides nach tools/public/ (README, LICENSE, .env.example, Beispiel-Configs). Achtung: Overrides sind selbst eine Leak-Quelle — sie muessen durch dasselbe Gate wie alles andere (siehe C).
  4. Entkopplung statt Divergenz. Fehlende private Module ueber importlib.util.find_spec erkennen und Features gar nicht erst registrieren — besser als kaputte Knoepfe oder ein zweiter Code-Zweig.
  5. tools/leak_markers.sh als einzige Marker-Quelle anlegen (Muster: patterns.md nebenan).
  6. Sync laufen lassen, Gate muss gruen sein, Tests im Snapshot gruen.
  7. Repo zuerst privat anlegen, pushen, Guard verifizieren, Inhalt durchsehen — dann auf public schalten.

B) Bestehenden Ableger syncen

cd <privat> && git status --porcelain     # sauber?
tools/sync-public.sh                      # Gate bricht VOR dem Commit ab
cd <public> && git push                   # Guard laeuft als pre-push
  • Erst git add, dann syncen. Quelle ist git ls-files — eine neue, noch nicht geaddete Datei ist fuer den Sync unsichtbar und fehlt im Snapshot, ohne Warnung.
  • Source: <sha> in die Commit-Message. Ohne diesen Trailer ist der Drift nicht bestimmbar. Damit: git -C <priv> rev-list --count <sha>..HEAD Ein privates commit --amend am Quell-Commit verwaist den Trailer. Der Source:-SHA im Ableger zeigt danach auf einen Commit, den es nicht mehr gibt — und der naechste Sync repariert das NICHT, weil der Inhalt unveraendert ist ("nichts geaendert, kein Commit"). Die Drift-Rechnung bricht dann still. Vor jeder Drift-Aussage den Trailer-SHA auf Existenz pruefen, sonst nachziehen: git -C <priv> cat-file -e "<trailer-sha>^{commit}" || echo "Trailer verwaist". Realfall: ein Message-Fix per Amend, danach zeigte der Trailer ins Leere. Der Trailer misst Commit-Distanz, nicht Content-Drift. Schreitet das private Repo durch public-irrelevante Commits fort (privates tools/, private Seiten), meldet rev-list --count <sha>..HEAD eine Drift, die inhaltlich keine ist. Die verlaessliche Currency-Probe ist der No-op-Sync selbst: laeuft er durch und meldet "nichts geaendert", ist der Ableger nachweislich aktuell — billiger und ehrlicher als jede Trailer-Distanz. Den Trailer fuer Nachvollziehbarkeit fuehren, die Aktualitaetsfrage mit dem Sync beantworten.
  • Der Sync ist tree-gated — Message- und Identitaets-Aenderungen traegt er nicht. Er committet nur, wenn git diff --cached nicht leer ist. Alles, was ausschliesslich in der Commit-Message oder in Author/Committer lebt — ein nachgeruesteter Source:-Trailer, eine korrigierte Message, eine per git config umgestellte Mail — wird von einem Re-Sync nie aufgegriffen, solange der Tree gleich bleibt. Solche Aenderungen brauchen ein manuelles git commit --amend --reset-author im Ableger plus force-push. Realfall: ein nachgeruesteter Trailer, Sync meldete "nichts geaendert" und haette ihn nie gelandet.
  • Lokal != publiziert. Vor jeder Aussage ueber "was ist oeffentlich": git ls-remote <url> main gegen git rev-parse main. Ein ungepushter Commit ist noch abwendbar, ein gepushter nicht.
  • Der lokale Klon des Ablegers kann hinter dem Remote stehen. Im Squash-Modus kann ein Sync aus einem anderen Klon gekommen sein; dann zeigt git log lokal einen ueberholten Snapshot, und ein Amend darauf wuerde den neueren per force-push wegwerfen. Vor jedem Sync git fetch und git rev-parse main origin/main vergleichen; pushen nur mit --force-with-lease=main:<erwarteter-sha>. Realfall 18.09.2026: lokal 09.08., remote 13.08.
  • Snapshot-Tests im sauberen Export, nicht im Arbeitsbaum des Klons. Ignorierte Reste (__pycache__-Ordner) lassen lokal Tests gruen laufen, die im frischen CI-Klon rot sind. git checkout-index -a --prefix=<scratch>/ exportiert genau den Index; dort pytest. Realfall 18.09.2026: Test setzte einen Ordner voraus, der lokal nur als .pyc-Rest existierte, erster Push lief in der CI rot.
  • Kein --no-verify. Der Schalter kippt ALLE Pruefungen, nicht die eine, die meldet — und wirkt am staerksten beim ersten Push. Ein unerklaerlicher Guard-Fehler ist ein Grund abzubrechen, nicht zu umgehen.
  • Snapshot-Tests im Snapshot laufen lassen, nicht aus tools/public/. Tests, die Konfig-/Fixture-Pfade relativ zu __file__ aufloesen, melden aus dem Quellbaum Fehlschlaege, die wie echte Defekte aussehen — reine Diagnose-Falle. Realfall 27.07.2026: 22 Pfad-Artefakt-Fehlschlaege, alle folgenlos. Erst syncen, dann im Zielbaum testen.
  • Erst die History-Strategie feststellen, dann syncen. git log --oneline im Ableger UND git ls-remote <url>: genau 1 Commit auf beiden Seiten heisst Squash-Snapshot, und dann ist der Sync git commit --amend --reset-author
    • force-push, nicht "Commit obendrauf". Wer das verwechselt, baut aus einem Squash-Repo genau die akkumulierende Snapshot-History, die der Entscheidungsbaum verbietet. Die Instanz-Tabelle unten ist eine KOPIE dieser Tatsache und kann veraltet sein (Realfall 23.07.2026: sie behauptete "organische History" fuer ein Squash-Repo) — im Zweifel gilt das Repo.

B2) Portieren statt Diffen — wenn der Ableger divergiert ist

Ein Ableger, der laenger lebt, ist irgendwann kein Spiegel mehr: uebersetzte Bezeichner, eigene Weiterentwicklung, Features die public frueher ankamen als privat. Dann ist git diff zwischen den Repos wertlos und ein Diff-Apply gefaehrlich — die private Aenderung muss auf die public Struktur abgebildet werden. Reihenfolge, die sich bewaehrt hat:

  1. Erst den public Ist-Stand feststellen, nicht den privaten Diff anwenden. Was hat der Ableger von der Aenderung schon? Wo ist er eigenstaendig weitergegangen? Realfall: eine gemeinsame Hilfsschicht war public bereits da, aber an einer Stelle anders implementiert — ein Diff-Apply haette einen Test gebrochen, den es privat gar nicht gibt.
  2. Aenderung als Spezifikation lesen, nicht als Patch — welches Verhalten, welche Felder, welche Einfuegestelle. Das Diff-Lesen laesst sich delegieren; die leak-sensible Anwendung nicht.
  3. Einfuegestelle im Ziel verifizieren, nicht raten (Nachbarzeilen lesen), dann Feature fuer Feature portieren, jeweils mit gespiegeltem Test in der Zielsprache des Ablegers.
  4. Vorbestehende Defekte im Ziel sind nicht Teil des Ports. Faellt beim Portieren ein Bug auf, der schon vorher da war: melden, nicht im Sync-Commit mitfixen — sonst vermischt sich Port und Reparatur, und der Commit wird unpruefbar.

Ein Task-Ticket spannt oft Portierbares UND Nicht-Portierbares. Die Ausschlussliste ist datei-basiert und trifft deshalb die falsche Einheit: eine Aenderung kann eine generische Haelfte haben, die raus darf, und eine personenbezogene, die nicht darf (Realfall: derselbe Task lieferte einen generischen Steuer-Guard und Konto-Varianten-Strategien). Die Portier-Frage deshalb pro Hunk stellen, nicht pro Ticket — und im Sync-Bericht ausdruecklich benennen, welche Haelfte bewusst drinnen blieb.

C) Pre-Push-Gate — Checkliste

Fail-closed: fehlt die Marker-Quelle, wird jeder Push verweigert.

Die Installation darf nicht am Erinnern haengen. .git/hooks wird weder versioniert noch mitgeklont — ein frischer Klon des Ablegers hat keinen Guard, und das faellt niemandem auf. Ein Satz in der Doku ("nach dem Clone neu installieren") ist dafuer keine Kontrolle, sondern eine Hoffnung. Richtig: das Sync-Skript installiert den Guard bei jedem Lauf selbst und verifiziert die Kopie per shasum; schlaegt das fehl, bricht der Sync ab. Der Sync ist der einzige Weg, auf dem ein Snapshot entsteht, also kann keiner ohne aktuellen Guard existieren.

Dabei die Reihenfolge beachten: die Installation gehoert vor die Inhalts-Gates. Steht sie dahinter, bleibt ein frischer Klon ausgerechnet dann ungeschuetzt, wenn der Sync an einem Fund abbricht — also im Fehlerfall. Realfall 23.07.2026: genau so zuerst gebaut und im Test aufgefallen. Den Zeilenvergleich (Aufruf vor Gate) als Testfall festhalten; beim naechsten Umbau geht die Reihenfolge sonst leise verloren.

PRIV=<privat>; PUB=<public>
cp "$PRIV/tools/public_push_guard.sh" "$PUB/.git/hooks/pre-push"
cp "$PRIV/tools/leak_markers.sh"      "$PUB/.git/hooks/leak_markers.sh"
printf '%s\n' "$PRIV/tools/leak_markers.sh" > "$PUB/.git/hooks/leak_markers.source"
chmod +x "$PUB/.git/hooks/pre-push"
shasum -a 256 "$PUB/.git/hooks/pre-push" "$PRIV/tools/public_push_guard.sh"  # muss gleich sein

Der Guard muss:

  • jeden Commit im Push-Bereich scannen (git rev-list "$local_oid" --not --remotes), nicht nur die Spitze — ein Marker, der in Commit A auftaucht und in B verschwindet, landet trotzdem im Objectstore des Remotes;
  • Commit-Messages mitpruefen;
  • Dateinamen gegen eine Verbotsliste pruefen;
  • Binaerdateien/Bilder gesondert melden.

Vor jedem Push zusaetzlich, wenn es um eine Erstveroeffentlichung geht:

git log --format='%an %ae|%cn %ce' --all | sort -u   # Klarnamen/Mails?
git log --diff-filter=D --name-only --all            # geloescht != weg
git rev-list --objects --all | awk '{print $2}' | grep -iE '<verbotsmuster>'
git fsck --unreachable --dangling; git reflog --all  # Amend-Reste?

Muster fuer den Inhalts-Scan: patterns.md im selben Ordner.

Das Push-Gate ist delta-basiert — Drift akkumuliert daran vorbei. Es prueft den aktuellen Batch, nie den Bestand. Was ein frueherer Sync durchgelassen hat, faellt keinem spaeteren mehr auf: es steht im Baum, aber in keinem Delta. Realfall: drei deutsche Runtime-Strings aus alten Syncs in einem Ableger, der English-only sein soll — von jedem Push-Gate seither uebersehen, weil niemand sie mehr anfasste. Deshalb zusaetzlich zum Push-Gate in groesseren Abstaenden einen Ganzbaum-Scan fahren (alle Marker gegen git ls-tree -r HEAD, nicht gegen den Diff) und das Ergebnis mit Datum in der Instanzdatei festhalten. Der Ganzbaum-Scan findet die Klasse, fuer die das Push-Gate strukturell blind ist.

Regeln aus dem Audit vom 21.07.2026

  • Test-Fixtures nie aus der Produktivdatei speisen. Der teuerste Fund des Audits war kein Secret, sondern Zahlen: zwei echte Depotpositionen (Stueckzahl, Stop-, Hochwert) standen bis auf die Nachkommastelle identisch in zwei public Testdateien. Kein Marker, kein Pfadmuster und kein Secret-Scanner schlaegt darauf an — nur ein wertbasierter Abgleich gegen die private Datenquelle (patterns.md §4). Fixtures kommen aus *.example.* mit erfundenen Werten; muss eine Zahl echt sein, gehoert der Test ins private Repo.
  • Guard-Regexe brechen an der Schreibweise. Derselbe Guard hatte eine Positionsgroessen-Pruefung — sie suchte "shares": <bruch> (JSON, Doppelquote) und uebersah 'shares': 24 (Python, Singlequote, ganzzahlig). Formatbasierte Pruefungen immer gegen die echte Zielschreibweise testen. Als Muster nachnutzbar: Quote- Klasse ["'] statt fester Doppelquote, Feldklasse (shares|stk|stueck), und der Wert-Check deckt jetzt jedes numerische Feld der Depotdatei ab statt der vier, die der letzte Leak zufaellig benutzte. Zwei Lehren daraus:
    • Ganzzahlen sind Depotdaten, nur nicht ueberall. Ein Wert-Check, der Ganzzahlen ausschliesst (sonst ruft er Wolf), ist blind fuer jede ganzzahlige Stueckzahl — und genau eine solche war der Fund. Loesung: das PAAR suchen, nicht die Zahl. 'shares': 24 ist Depotdatum, ein loses 24 nicht. Damit faellt die Wolf-Frage weg und die Klasse ist trotzdem zu.
    • Der Riegel gehoert eine Ebene frueher — und ist nicht optional. Der Guard blockt den Push, also erst nachdem der Wert schon abgeschrieben ist. Jedes Paar braucht deshalb im PRIVATEN Repo (a) einen billigen pytest, der die Testsuite gegen tools/leak_markers.sh grept, und (b) einen wertbasierten Abgleich der Fixtures gegen die echte Datenquelle — inklusive namentlicher Ausnahmeliste fuer Tests, die gegen einen Broker-Beleg validieren und deshalb nie portiert werden duerfen. Zweiter Beleg: fehlt dieser private Test, kommt dieselbe Fixture-Datei Tage spaeter mit denselben echten IDs zurueck — der Push-Guard faengt die Wiederkehr nicht, er blockt sie nur jedes Mal erneut.
  • Overrides durch dasselbe Gate. Eine echte Geraete-UUID stand in einem gescrubbten Public-README-Override. Weil der Override die Quelle ist, re-publiziert ihn jeder kuenftige Sync. Ein Fix im public Repo allein haelt nicht — immer die Override-Datei korrigieren.
  • Gates nie an exakte Literale binden. Ein GPS-Gate, das auf die sechsstellige Schreibweise der echten Koordinaten gebunden war, liess dieselben Werte in gerundeter Form durch. Musterklassen matchen (Koordinatenpaare, Ortsnamen), nicht Einzelwerte.
  • Keine --include-Endungslisten im Gate. Ein Gate ueber py|yaml|md|ts|sh uebersieht json|csv|svg|html. Alle Textdateien scannen, nur Binaeres ueberspringen.
  • Marker koennen nur blocken, was sie kennen. Eine Pseudonym-Liste faengt keinen unbekannten Klarnamen. Zusaetzlich generisch pruefen (Vorname-Nachname-Paare, @-Handles) und die Liste gegen die realen Datenquellen gegenpruefen.
  • Namensbasierte .gitignore-Muster sind kein Schutz. Ein neuer Dateiname rutscht durch (Realfall: Klartext-API-Key in einem neuen Skript). Deshalb Allowlist.
  • Der Sync scrubbt den Baum, nicht die History. Wer nachtraeglich scrubbt, muss die History mitdenken — sonst ist der Fund nur unsichtbar, nicht weg.

Weitere Regeln aus einem Sync eines hardware-nahen Ablegers

  • Ein hartkodierter Echtwert ist selten nur ein Leak — das Gate ist zugleich eine Code-Qualitaets-Sonde. Ein realer Ortsname stand als Default-Wert in einem Job-Modul; dahinter ein latenter Bug: das genutzte Attribut sitzt auf einer anderen Konfig-Klasse als der, die abgefragt wurde, also liefert der getattr(obj, "feld", None)-Zugriff immer None und der hartkodierte Fallback greift immer (im Fund folgenlos, weil die betroffenen Objekte vorher uebersprungen wurden — ein zweiter Fall bekaeme still den falschen Wert). Hartkodierte Echtwerte markieren oft einen fehlenden Konfig-Zugriff. Den Leak verhaltenserhaltend fixen; die dahinterliegende Verhaltensaenderung an einem Live-System ist eine getrennte Owner-Entscheidung, nicht Teil des Syncs.
  • Begruendungs-Kommentare sind eine eigene Leak-Klasse (Muster: patterns.md §5b). Docstrings, die warum erklaeren, zitieren den realen Fall ("Objekt X (<echte-id>) fiel 77 -> 30"). Kein Secret- oder Fixture-Muster trifft. Drei von fuenf Fundstellen dieses Syncs waren von dieser Art.

Die andere Richtung: die oeffentliche Doku

Alle Gates oben pruefen, ob zu VIEL rausgeht. Die zweite Fehlerklasse ist, dass zu WENIG rausgeht: der Ableger ist leak-sauber und trotzdem unbrauchbar, weil die Doku den Stand nicht traegt. Kein Gate meldet das je — es ist immer Handarbeit beim Sync.

Der Leser ist ein Fremder. Er hat deine Hardware nicht, deine Datendateien nicht, dein Betriebssystem vielleicht nicht — und er kann nicht nachfragen. Die private README darf Kontext voraussetzen, die oeffentliche nie.

  1. Der Quickstart muss auf einer fremden Maschine laufen. Als woertliche Anweisung lesen, nicht als Erinnerungsstuetze. Realfall 27.07.2026: ein Quickstart endete auf open <datei> — macOS-only, bei ausdruecklich internationaler Zielgruppe. Pruefpunkte: plattformspezifische Befehle (open, pbcopy, Pfadtrenner), private Datendateien, die public gar nicht existieren, vorausgesetzte Env-Variablen ohne .env.example-Eintrag.
  2. Entkoppelte Features muessen benannt sein. Ein Feature, das public per find_spec gar nicht erst registriert wird (§A4), ist fuer den Leser ununterscheidbar von einem Defekt. Ein Satz, was fehlt und warum ("laeuft gegen private Hardware"), verwandelt einen scheinbaren Bug in eine nachvollziehbare Grenze.
  3. Nutzerbemerkbare Aenderung → README-Abschnitt, nicht nur CHANGELOG-Zeile. Neue Config-Keys, neue Parameter, geaendertes Verhalten. Mechanisierbar: neue Keys gegen README und *.example.* diffen, bei Fehlbetrag warnen. Realfall 27.07.2026 zweimal am selben Tag — einmal fehlte die Dosis-Semantik in README und Beispiel-Config komplett, einmal wurde sie korrekt als eigener Abschnitt ergaenzt.
  4. Ehrlichkeit ist Teil der Qualitaet. Was das Verfahren NICHT kann, Limitationen, negative Ergebnisse, Datenherkunft und Lizenzen. Ein Backtest, der auch die Verlustfaelle zeigt, ist glaubwuerdig; einer ohne sie ist Werbung.
  5. Einen guten Text nicht umschreiben. Ist die README stark, ist die Aenderung das Risiko, nicht der Stillstand. Dann nur den belegten Fehler fixen und das im Bericht sagen — "ich habe sie gelesen und nichts gefunden" ist ein vollwertiges Ergebnis.

Reihenfolge beim Sync: lesen → Delta bestimmen → gezielt aendern, nie "README neu schreiben, weil Sync". Und die Aenderung gehoert in den Override unter tools/public/, nie in den Ableger — sonst ueberschreibt sie der naechste Sync.

Wenn doch etwas publiziert wurde

Reihenfolge, nicht verhandelbar: 1. rotieren, 2. dann erst rewriten. Ein Secret gilt ab dem Push als kompromittiert — Clones, Forks und Crawler sind nicht einholbar. Rewrite (filter-repo + force-push) ist Kosmetik fuer den Objectstore, kein Ersatz fuer Rotation, und immer Einzelfreigabe des Owners. Vorher gh repo view --json forkCount,stargazerCount — bei 0 Forks ist ein Rewrite noch weitgehend wirksam.

Ein force-push loescht nichts — gemessen, nicht vermutet

Der ueberschriebene Commit bleibt bei GitHub liegen und wird per SHA weiter ausgeliefert. Realfall 23.07.2026: nach commit --amend --reset-author + push --force-with-lease lieferte

gh api repos/<owner>/<repo>/commits/<alter-sha> --jq '.commit.author.email'

die alte Klarnamen-Mail unveraendert zurueck — Author und Committer. Erst nach Loeschen und Neuanlegen des Repos antwortet dieselbe Abfrage mit HTTP 422 No commit found.

Erst die Gabelung pruefen: benigner oder gefaehrlicher Waise? Nicht jeder ueberschriebene Commit ist eine Leak-Sorge — ein Message-only-Amend (etwa das Nachruesten des Source:-Trailers) hinterlaesst einen Waisen, dessen Tree byte-identisch und dessen Identitaet schon sauber ist. Bevor jemand wegen eines abrufbaren alten SHA an Neuanlage denkt, die zwei Vergleiche laufen lassen:

git rev-parse "<alt>^{tree}" "<neu>^{tree}"          # gleicher Tree?
git log -1 --format='%an %ae|%cn %ce' <alt>          # schon Noreply?

Gleicher Tree und saubere Identitaet = kein Handlungsbedarf, nur benennen. Erst wenn einer der beiden abweicht, gilt der Rest dieser Sektion. Ohne diese Gabelung loest jeder Trailer-Fix einen Fehlalarm aus — und Fehlalarme sind der Weg zur unnoetigen Repo-Neuanlage.

Konsequenzen fuer die Praxis:

  • Ein Amend/Rewrite bereinigt den sichtbaren Stand, nicht die Historie des Servers. Wer "X ist jetzt weg" behauptet, muss die Abfrage oben gelaufen sein lassen. Das ist der einzige Beleg; git log im Klon zeigt sie nie.
  • Muss etwas wirklich weg, ist die Neuanlage das einzige Mittel. Preis sind Stars, Forks, Issues und PR-History — bei einem frischen Showcase-Repo also oft null. Vorher description, topics, has_issues/has_projects sichern (gh api repos/<o>/<r> --jq '{description,topics,has_issues,has_projects}'); LICENSE, CI-Workflows und Issue-Templates liegen im Tree und kommen mit dem Push von selbst zurueck.
  • Das Loeschen gehoert dem Owner, nicht dem Agenten. Es braucht ausserdem den delete_repo-Scope, den ein normaler gh-Token nicht hat (gh auth refresh -h github.com -s delete_repo, oder Weboberflaeche → Settings → Danger Zone). Den Scope hinterher wieder abraeumen.
  • Reihenfolge: loeschen → privat neu anlegen → pushen → verifizieren → erst dann auf public schalten. Nie in ein bereits oeffentliches Repo hinein sanieren, wenn die Neuanlage ohnehin ansteht.

Instanzdaten — nicht hier, sondern am Repo

Dieser Skill ist agnostisch. Welches Paar existiert, welche History-Strategie es faehrt, ob der Guard installiert ist und was offen steht, steht beim Repo:

  • Ableger mit privatem Elternteil → tools/public-mirror.md im privaten Repo, neben sync-public.sh und leak_markers.sh.
  • Repo ohne privaten Elternteil (Sichtbarkeits-Flip) → .private/public-mirror.md plus .gitignore-Eintrag: git check-ignore -v .private/public-mirror.md

Verlass dich nicht auf den Default, pruefe den Ausschluss am Objekt. Regel 2 oben fordert eine Allowlist — ob das Sync-Skript sie tatsaechlich implementiert, ist eine andere Frage. Realfall 23.07.2026: zwei Ableger fuhren einen Default-Arm *) return 1 ;;, also public; in einem davon gingen fuenf neu angelegte Dateien ohne Freigabe raus. Ein dritter hat gar kein Sync-Skript (manueller Port) — dort schuetzt nur Handarbeit. Deshalb nach dem Anlegen der Instanzdatei immer einmal:

tools/sync-public.sh --dry-run   # oder Sync in einen Wegwerf-Zielordner
grep -rl "Instanzdaten" <ziel>   # muss leer sein

Lies diese Datei, bevor du an einem Paar arbeitest. Ohne sie kennst du die History-Strategie nicht — und ein Sync mit der falschen Strategie ist genau der Fehler, den der Entscheidungsbaum oben verhindern soll.

Mindestinhalt: Repo-Paar mit aktueller Sichtbarkeit, History-Strategie, Guard-Zustand, Besonderheiten (nicht rotierbare Datenklassen, Personendaten Dritter), offene Punkte mit Datum, Stand-Datum, projektspezifische Markerwerte.

Warum getrennt: Instanzdaten veralten in dem Mass, in dem sie von ihrem Gegenstand entfernt liegen. Eine Tabelle in ~/.claude/skills/ wird gepflegt, wenn jemand daran denkt; eine Datei im Repo wird gepflegt, wenn das Repo sich aendert. Realfall 23.07.2026: die fruehere Tabelle an dieser Stelle fuehrte einen Ableger als publiziert, der laengst auf privat stand, und meldete einen fehlenden Guard, den es gab — beides wurde geglaubt und war falsch. Und 27.07.2026: die prominenteste Warnung derselben Instanzdatei behauptete vier Tage lang Blocklist-Default, obwohl das Skript laengst auf Allowlist (*) return 0) stand. Regel darum verallgemeinert: jede Behauptung der Instanzdatei am Objekt pruefen, mit dem Befehl daneben — nicht nur die History-Strategie, auch Guard-Zustand, Default-Arm und Sichtbarkeit.

Fehlt dem Ableger der Source:-Trailer, ist sein Drift nur ueber Datum schaetzbar — beim naechsten Sync nachruesten.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.