Compare commits

..
16 Commits
Author SHA1 Message Date
martin f2b8bdd86b chore: Settings auf auto-Modus und herdr-Hook anpassen 2026-09-20 08:01:56 +02:00
martinandClaude Opus 5 012e87064a chore: herdr-SessionStart-Hook aufnehmen
Von herdr generiertes Script, das die Claude-Session an den herdr-Socket
meldet. Wird von herdr-Updates ueberschrieben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 07:52:54 +02:00
martinandClaude Opus 5 9302f0b222 docs: Erledigtes ersatzlos loeschen statt markieren
Abgehakte Eintraege und Mess-Metadaten ohne Aussagekraft blaehen
Dokumente auf, ohne Information zu tragen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 07:51:11 +02:00
martin e290dbe7a4 Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-09-20 07:49:59 +02:00
martinandClaude Opus 5 a7e9e0d55e feat: Superpowers-Plugin im Workflow verankern
Deklaration in settings.json statt Vendorn der Skill-Dateien, damit
Upstream-Updates weiter greifen. bootstrap.sh installiert das Plugin auf
neuen Maschinen und aktualisiert es bei jedem Lauf.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-20 07:49:30 +02:00
martinandClaude Opus 5 6c48cc423f docs: Zwischenmeldungen bei Werkzeugarbeit untersagen
Laufende Kommentare vor und zwischen Werkzeugaufrufen verwirren mehr,
als sie helfen.

- vor und zwischen Aufrufen nichts schreiben, erst arbeiten
- am Ende eine Antwort, bei mehreren Fragen nummeriert

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JMD2X7cCSHn17M2v641rXm
2026-09-20 07:45:23 +02:00
martinandClaude Opus 5 596831e753 docs: Commit-Body kurz halten — Satz plus Stichpunkte
Lange Fliesstext-Bodies wiederholen meist nur den Diff.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GPpQVyWBUiB7DzPwBoaCjL
2026-09-09 08:32:40 +02:00
martinandClaude Opus 5 156389dccc docs: Merge statt Rebase als Regel im Git-Workflow
Ein Rebase spielt jeden alten Commit einzeln neu ein und erzeugt Konflikte, die
inhaltlich nicht bestehen. Konkret im dotfiles-Repo: Commit 55d9733 vom 05.07.
setzt in settings.json den Modellnamen und ergaenzt tui. Auf origin/main stand
beides schon, nur an verschobener Position — der Rebase konnte den alten Patch
nicht mehr zuordnen und meldete Konflikt, obwohl die Datei in HEAD und
origin/main byte-identisch war. Zusaetzlich haette er vier vorhandene
Merge-Commits umgeschrieben.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 07:19:05 +02:00
martin d1e72419c3 Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-08-10 07:18:17 +02:00
martinandClaude Opus 5 767f2104c3 docs: Kommentare im Code auf eine Zeile begrenzen
Ein Kommentar beschreibt kurz, was an dieser Stelle passiert. Das Warum gehoert
in die Commit-Message und ist dort in der Git-Historie nachlesbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 07:15:01 +02:00
martin 2e37e356c6 Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-08-01 09:19:31 +02:00
martinandClaude Opus 4.8 345a0fdb9e docs: Prinzip "Explizit vor implizit" ergaenzen
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 21:29:40 +02:00
martin b3759b4b98 Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-07-09 07:23:19 +02:00
martin bd6c586aec Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-07-07 14:40:54 +02:00
martin c70f8a9f34 Merge branch 'main' of https://gitea.troeger-net.org/martin/claude-workflow 2026-07-05 10:37:41 +02:00
martin 55d973349f some settings 2026-07-05 10:37:11 +02:00
4 changed files with 146 additions and 4 deletions
+13
View File
@@ -145,6 +145,19 @@ echo ""
echo "=== Claude-Code-Integrationen ==="
if command -v claude &>/dev/null; then
if claude plugin list 2>/dev/null | grep -q "superpowers@superpowers-marketplace"; then
claude plugin marketplace update superpowers-marketplace &>/dev/null || true
claude plugin update superpowers@superpowers-marketplace &>/dev/null || true
echo " OK superpowers Plugin (aktualisiert)"
else
claude plugin marketplace add obra/superpowers-marketplace &>/dev/null || true
if claude plugin install superpowers@superpowers-marketplace &>/dev/null; then
echo " OK superpowers Plugin installiert"
else
echo " FEHLT superpowers Plugin -- claude plugin install superpowers@superpowers-marketplace"
fi
fi
if claude mcp list 2>/dev/null | grep -q "context7"; then
echo " OK context7 Plugin"
else
+8
View File
@@ -8,6 +8,8 @@ Alle Texte, Kommentare und Kommunikation auf Deutsch. Technische Begriffe und Co
**Immer AsciiDoc (`.adoc`) statt Markdown** für alle Dokumente (Analysen, Pläne, Berichte, Anfragen usw.). Neue Dokumente als `.adoc` anlegen. Bestehende `.md`-Dateien nur auf ausdrücklichen Wunsch konvertieren. Ausnahmen: von Tools erzwungene Dateien (`CLAUDE.md`, `MEMORY.md`, `README.md` wo vom Workflow verlangt) bleiben Markdown.
**Erledigtes wird gelöscht, nicht markiert.** In Listen offener Punkte einen erledigten Eintrag ersatzlos entfernen — kein „erledigt"-Vermerk, kein Durchstreichen. Ebenso keine Metadaten ohne Aussagekraft (Mess-/Erhebungsdatum), wenn nur der Wert zählt.
## Entwicklungsprinzipien
- **Single Responsibility:** Jede Datei, jede Funktion hat genau eine Aufgabe
@@ -16,12 +18,14 @@ Alle Texte, Kommentare und Kommunikation auf Deutsch. Technische Begriffe und Co
- **Keine Magic Numbers:** Konstanten mit Namen versehen
- **DRY mit Augenmass:** Shared Utilities nur bei echtem Mehrfachgebrauch
- **Fail Fast:** Fehlende/ungueltige Konfiguration muss beim Start eine Exception werfen
- **Explizit vor implizit:** Zustand oder Absicht nie implizit aus Momentanwerten ableiten (fragil/nicht robust). Trigger deklarieren ihre Absicht ueber ein dediziertes Item/Flag; die auswertende Logik liest dieses Item, statt den Zustand zu erraten
- **Keine generischen `try/except`:** Spezifische Exceptions fangen
- **Logging statt print:** `logger` verwenden
- **Testpflicht:** Kein Code ohne zugehoerigen Test
- **Security by Default:** Input-Validierung, Auth-Checks, sichere Defaults. Sicherheitskritische Pfade durch Tests absichern
- **String-Eingaben trimmen:** Alle String-Felder beim Anlegen/Update in Services/Schemas trimmen (leading/trailing Whitespace entfernen). Leerstrings werden zu `None`, wenn das Feld optional ist. Verhindert Sortier-/Vergleichs-/Suchfehler durch unsichtbare Zeichen
- **Kleine Funktionen, keine Kommentare fuer Offensichtliches**
- **Kommentare hoechstens eine Zeile:** Ein Kommentar beschreibt kurz, *was* an dieser Stelle passiert (z.B. `// Messwerte pruefen`, `// zu spaet fuer Sperre`, `// Ladestand unterhalb Reserve`). Niemals das *Warum*, keine Begruendungen, keine Messwerte, keine verworfenen Alternativen, keine Mehrzeiler. Das Warum gehoert in die Commit-Message und ist dort in der Git-Historie nachlesbar
- **Keine systemveraendernden Scripts zum Testen ausfuehren:** Scripts die Symlinks, Berechtigungen, Pakete oder Konfiguration aendern niemals "einfach so" ausfuehren. Stattdessen mit `bash -n` (Syntax) oder gezieltem `grep`/`cat` pruefen
## Code-Konventionen
@@ -62,10 +66,12 @@ Niemals direkt auf `main` committen. Alle Aenderungen ueber Feature-Branches und
- **Ausnahme `.commit-on-main`:** Vor dem Branchen im Repo-Root (`git rev-parse --show-toplevel`) auf die Marker-Datei `.commit-on-main` pruefen. Existiert sie, sind Direkt-Commits auf `main` erlaubt — dann kein Feature-Branch und kein PR, direkt auf `main` committen und pushen.
- **Kleinteilige Commits:** Pro Commit nur ein einziges Thema. Nur die zum Thema gehörenden Dateien committen — keine thematisch gemischten Commits.
- **Immer mergen, nie rebasen:** Divergierte Branches per `git pull` (Merge) zusammenfuehren, nicht per `git pull --rebase`. Ein Rebase spielt jeden alten Commit einzeln neu ein und erzeugt dabei Konflikte, die inhaltlich gar nicht bestehen — etwa wenn ein Wert am Ziel schon gesetzt, aber an eine andere Stelle der Datei gewandert ist. Ausserdem schreibt er vorhandene Merge-Commits um. Ein Merge vergleicht nur die Endzustaende. Rebase nur auf ausdruecklichen Wunsch.
- **Commit-Messages:** Conventional Commits, deutsche Beschreibung
- Subject: `<type>: <Beschreibung>` — max 72 Zeichen, kein Punkt am Ende
- Typen: `feat`, `fix`, `docs`, `refactor`, `test`, `chore`, `perf`, `ci`, `build`, `style`
- Body optional, durch Leerzeile getrennt — erklaert das Warum, nicht das Was
- Body kurz halten: ein einleitender Satz, danach knappe Stichpunkte — keine Fliesstext-Absaetze, keine Wiederholung des Diffs
## Fehlende Tools
@@ -129,6 +135,8 @@ Der User ist Informatiker/Techniker und will präzise Kommunikation mit den wese
- **Keine Doppelung Chat/Datei.** Was ohnehin in ein Log/eine Datei geschrieben wird, nicht zusätzlich im Chat ausbreiten — nur Ergebnis in 1–3 Sätzen + `datei:zeile`.
- **Analyse als Stichpunkte,** nicht als durchargumentierter Fließtext. Belege/Tabellen nur auf ausdrückliche Nachfrage.
- **Kein „nächste Schritte"-/Kontext-Recap,** außer explizit gewünscht.
- **Keine Zwischenmeldungen bei Werkzeugarbeit.** Vor und zwischen Werkzeugaufrufen nichts schreiben: kein „Ich prüfe jetzt …", keine Ankündigung dessen, was gleich abgerufen wird, keine Zwischenbefunde, keine Aufzählung des eigenen Vorgehens. Erst arbeiten, dann **eine** Antwort.
- **Antwort am Ende, bei mehreren Fragen nummeriert.** Reihenfolge der Fragen beibehalten, je Frage ein bis drei Sätze, Ergebnis zuerst. Belege nur, wenn sie das Ergebnis tragen.
## MCP
+25 -4
View File
@@ -60,8 +60,9 @@
"Bash(docker *)",
"Bash(which *)"
],
"defaultMode": "default"
"defaultMode": "auto"
},
"model": "opus",
"hooks": {
"UserPromptSubmit": [
{
@@ -105,6 +106,18 @@
}
]
}
],
"SessionStart": [
{
"matcher": "*",
"hooks": [
{
"type": "command",
"command": "bash '/home/martin/.claude/hooks/herdr-agent-state.sh' session",
"timeout": 10
}
]
}
]
},
"statusLine": {
@@ -117,11 +130,19 @@
"context7@claude-plugins-official": true,
"code-review@claude-plugins-official": true,
"code-simplifier@claude-plugins-official": true,
"skill-creator@claude-plugins-official": true
"skill-creator@claude-plugins-official": true,
"superpowers@superpowers-marketplace": true
},
"extraKnownMarketplaces": {
"superpowers-marketplace": {
"source": {
"source": "github",
"repo": "obra/superpowers-marketplace"
}
}
},
"language": "German",
"tui": "fullscreen",
"editorMode": "vim",
"terminalProgressBarEnabled": false,
"model": "opus"
"terminalProgressBarEnabled": false
}
+100
View File
@@ -0,0 +1,100 @@
#!/bin/sh
# installed by herdr
# managed by herdr; reinstalling or updating the integration overwrites this file.
# add custom hooks beside this file instead of editing it.
# HERDR_INTEGRATION_ID=claude
# HERDR_INTEGRATION_VERSION=9
set -eu
action="${1:-}"
hook_input_file="$(mktemp "${TMPDIR:-/tmp}/herdr-claude-hook.XXXXXX")" || exit 0
trap 'rm -f "$hook_input_file"' EXIT HUP INT TERM
cat >"$hook_input_file" 2>/dev/null || true
case "$action" in
session) ;;
*) exit 0 ;;
esac
[ "${HERDR_ENV:-}" = "1" ] || exit 0
[ -n "${HERDR_SOCKET_PATH:-}" ] || exit 0
[ -n "${HERDR_PANE_ID:-}" ] || exit 0
command -v python3 >/dev/null 2>&1 || exit 0
HERDR_ACTION="$action" HERDR_HOOK_INPUT_FILE="$hook_input_file" python3 - <<'PY'
import json
import os
import random
import socket
import time
source = "herdr:claude"
action = os.environ.get("HERDR_ACTION", "")
pane_id = os.environ.get("HERDR_PANE_ID")
socket_path = os.environ.get("HERDR_SOCKET_PATH")
hook_input_file = os.environ.get("HERDR_HOOK_INPUT_FILE")
if not pane_id or not socket_path:
raise SystemExit(0)
hook_input = {}
if hook_input_file:
try:
with open(hook_input_file, encoding="utf-8") as handle:
content = handle.read()
if content.strip():
hook_input = json.loads(content)
except Exception:
hook_input = {}
if "CURSOR_VERSION" in os.environ or "cursor_version" in hook_input:
raise SystemExit(0)
hook_event_name = str(hook_input.get("hook_event_name") or "")
if hook_event_name != "SessionStart":
raise SystemExit(0)
is_subagent = bool(hook_input.get("agent_id"))
if is_subagent:
raise SystemExit(0)
request_id = f"{source}:{int(time.time() * 1000)}:{random.randrange(1_000_000):06d}"
report_seq = time.time_ns()
session_id = hook_input.get("session_id")
agent_session_id = session_id if isinstance(session_id, str) and session_id else None
transcript_path = hook_input.get("transcript_path")
agent_session_path = transcript_path if isinstance(transcript_path, str) and transcript_path else None
session_start_source = hook_input.get("source") if hook_event_name == "SessionStart" else None
if not isinstance(session_start_source, str) or not session_start_source:
session_start_source = None
if agent_session_id:
params = {
"pane_id": pane_id,
"source": source,
"agent": "claude",
"seq": report_seq,
"agent_session_id": agent_session_id,
}
if agent_session_path:
params["agent_session_path"] = agent_session_path
if session_start_source:
params["session_start_source"] = session_start_source
request = {
"id": request_id,
"method": "pane.report_agent_session",
"params": params,
}
else:
raise SystemExit(0)
try:
client = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
client.settimeout(0.5)
client.connect(socket_path)
client.sendall((json.dumps(request) + "\n").encode())
try:
client.recv(4096)
except Exception:
pass
client.close()
except Exception:
pass
PY