dotfiles/agents/AGENTS.md
mwiegand dd2f65a13f
docs(agents): md-Eintrag ohne Pfadangabe — das Tool liegt im PATH
Der Verweis auf ~/.local/bin/md und das ai-Repo war zum Aufrufzeitpunkt
irrelevant und machte den Eintrag von einem zweiten Repo abhängig.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014Jmx1FL5pssYBKsCjj2pJr
2026-09-03 23:55:46 +02:00

10 KiB

Personal preferences

Workflow

  • Specs, plans, and design docs go into the repo they describe. When brainstorming, plan-mode, or any flow produces a persistent document (design spec, implementation plan, ADR, etc.), the final destination is always the working tree of the project it belongs to — typically under docs/ (or wherever the project conventionally keeps them). Scratch locations like ~/.claude/plans/<slug>.md are fine during plan mode, but the moment plan mode exits with an approved artifact, copy it into the repo and git commit it. Don't ship a feature while its spec or plan still lives only in a scratch file. If a project's AGENTS.md / CLAUDE.md specifies a different directory, that wins.

Code health

Strategic over tactical, with follow-through. Each change should leave the codebase at least as coherent as it was — don't just flag messiness, address it.

  • Default to acting on cleanups, not just mentioning them. If you notice duplication, a band-aid, or an inconsistency, fix it as part of the work rather than leaving it as an observation. "I noticed X but didn't do it" is the anti-pattern — it leaves the user with both the mess and the homework of cleaning it up.
  • Scope boundary for inline cleanups: on-path AND reversible AND within files already being touched. Inline when all three hold. If the cleanup crosses files, would be hard to undo, or is parallel to the task — surface it in 2-3 sentences and ask before pursuing.
  • Tolerate duplication until the pattern is real. Removing existing duplication is welcome; inventing new abstractions speculatively is not. Rule of three: don't unify two instances, wait for the third.
  • Treat friction as architectural data. Awkward expression, edits that ripple across files, patterns that recur with subtle variations, structure fighting the task — these are the architecture telling you something, not just noise to push through. Propose architectural changes when they'd make the code more sustainable. Frame as proposals with a clear ask ("now, or follow-up?"), not silent rewrites.

Interpreting requests

Treat vague input and question-back responses critically, not as instructions.

  • Vagueness is not authorization. "Make it cleaner", "maybe X?", "looks good but…" are signals to ask one clarifying question, not green lights to pick an interpretation and run.
  • A tangent is not an answer. If you ask "A or B?" and get "maybe X?", that's a new question, not a pick. Surface the mismatch and ask which the user meant — don't bundle the tangent into the active task as if it were direction.

Team memory (cognee)

cognee is a real memory, not an archive: unlike MEMORY.md it is not injected automatically, so it only works if you fetch from it and write to it on your own. The rules below are events, not attitudes — check them when the event happens, not "when it feels right".

Read: recall before you start

Run recall before the first tool call, not after you are already deep in the task, when any of these is true:

  • the task touches infrastructure, a server, a service, a ticket or a tool we run ourselves
  • an error looks like it could have happened before ("this smells familiar")
  • you are about to pick between options where a decision may already exist
  • the task will plausibly take more than a handful of tool calls

recall <question> — no flags. It reads every readable dataset including the team one. --team exists on remember only; on recall it is a usage error, and --dataset team-it fails too because the team dataset is shared rather than owned (it would need its UUID). Neither is needed: plain recall covers everything.

Treat what comes back like a colleague's note: useful, possibly outdated. If a memory names a file, flag or host, verify it still exists before acting on it.

Write: remember at these moments

Announce it in one line, never ask first. Write as the insight appears, not at the end of the session — by then the detail that made it worth saving is gone.

  • a bug is fixed and the cause was not visible in the code (config, limits, environment, an API that lies)
  • a decision is made and an alternative was rejected — save the why, that is what the code cannot tell later
  • a measurement contradicts an assumption, mine or yours
  • you correct me, or I correct myself after being wrong
  • a tool, API or service behaves differently than its docs claim

What does not belong there: anything the repo already records, anything that only matters inside this one conversation, and never secrets, credentials or customer-personal data.

Routing and hygiene

  • Team bucket (remember --team): everything concerning team IT — Seibert IT-Infra, ISAC/bw, monitoring, INFRA board, shared services, servers, team processes. Ask yourself: would a colleague hitting this next month benefit?
  • Personal dataset (plain remember): my preferences, workflow feedback, context that is only relevant to me.
  • On recurring topics recall first and extend the existing note instead of adding a second one — two notes on one topic are worse than none, because the older one keeps surfacing.
  • Write notes that answer a question, not headlines. Include the concrete numbers, the error message verbatim, and the fix. A note that says "there was a problem with X" costs more time than it saves.
  • No need to economize on characters: cognee has no size limit, so write notes comprehensively and self-contained.
  • Always keep the external references and source links in the note — they matter: Confluence, Jira, TeamVault, and, for notes that grew out of a Google Chat discussion, the source-thread URLs (https://chat.google.com/room/<SPACE-ID>/<THREAD-ID>, for individual messages append the <MESSAGE-ID>) so the original discussion stays traceable — not just a separate index.

Sandbox

  • Always run commands sandboxed first. Only use dangerouslyDisableSandbox: true as a last resort after a sandbox-related failure — never preemptively.
  • On sandbox failure: analyze the error message for the blocked path, then suggest adding it to sandbox.filesystem.allowWrite in ~/.claude/settings.json. Only fall back to dangerouslyDisableSandbox: true if the path can't be determined or the user prefers it.

Temporary Files

  • Use $TMPDIR or .tmp/ (project-local) for temporary files. Never use /tmp directly or paths like /Library/Application Support — those are not in the sandbox allowlist and trigger permission prompts.
  • $TMPDIR is set by the sandbox to a writable path. .tmp/ inside the project directory is always writable without prompts.
  • Ensure .tmp/ is listed in .gitignore when creating temp files in a tracked repo.

Shell — literal ! in Bash commands

  • Never put a literal ! in an inline Bash command. Claude Code's Bash tool escapes every ! to \! at the transport layer before any shell sees it — even inside single/double quotes and in non-interactive shells (anthropics/claude-code#61121, a regression of a fix shipped in 2.1.87). The stray backslash corrupts downstream tools: Python != → SyntaxWarning + broken string, jq, Jira JQL (status != Done → server 400), branch names, etc. bash -c '...' and quoted heredocs do not avoid it.
  • One rule covers everything: if a command needs a !, write the command/code to a file with the Write tool under .tmp/ and run the file. .tmp/ is prompt-free via the Edit(.tmp/**) allow rule in ~/.claude/settings.json. Do not create the file with inline printf/echo > — that re-escapes the !.
  • Need a literal ! inline anyway: ANSI-C hex $'\x21' (e.g. B=$'\x21'; cmd "${B}=…") yields a real ! with no literal ! in the command.

Tooling

  • Sourcebot MCP for org repos without a local checkout. The mcp__sourcebot__* tools (instance sourcebot.it.seibert.diy) search the indexed Seibert codebases — Bitbucket DC/Cloud, Forgejo, seibert-external on GitHub. Reach for them when a question touches a repo that isn't cloned locally (other teams' code, cross-repo lookups, PR context): grep, glob, read_file, list_tree, list_commits, get_diff, find_symbol_definitions/_references answer in seconds and return file:line plus web links. A local checkout stays first choice when it exists. Never call ask_codebase on your own — it spawns a nested server-side agent (minutes per call, shared vLLM); use it only when explicitly asked.
  • ccc for semantic code search. Repos containing a .cocoindex_code/ directory are indexed by ccc. Reach for it on conceptual questions ("where is X used / which files do Y / what handles Z"), where a keyword grep would miss indirect usage: ccc search '<concept>'. Results are filtered to the current working directory's subtree, so run the search from the project root — that is the cheap way to see everything. --path '**' achieves the same from a subdirectory, but from the root it is a no-op and about three times slower (measured 2026-09-02 on a 1005-file index: 0.35 s against 0.12 s, identical hits), so pass it only when you cannot control the cwd. Embeddings only, no keyword component: searching an exact string (a UUID, a ticket ID, an error message) does not return the file that contains it — verified. grep/rg/find own exact-string lookups. A low score is a warning, not a hit. The ccc skill has the full reference.
  • ccc index / ccc init are read-safe maintenance. They only write to the gitignored .cocoindex_code/ directory, never to source. Run them without confirmation prompts — at session start, after refactors, or before a search when the index may be stale. Treat like grep for permission purposes, not like a code edit.
  • md für lange Markdown-Dateien statt head/grep -n '^#'. md outline <datei> gibt den Überschriftenbaum mit Zeilennummer und Größe pro Abschnitt ([164 Zeilen, ~2.1k Tok]) — daraus die Lese-Entscheidung treffen, dann md section <datei> "<Überschrift>" für genau diesen Teilbaum (Query auch als Slug oder L48; --range liefert offset limit fürs Read-Tool, --depth 0 schneidet Unterabschnitte ab). Der Parser kennt Code-Fences und Frontmatter, findet also kein # Kommentar aus einem ```bash-Block als Überschrift — der Grund, grep hier nicht zu nehmen. Bei Dateien unter ~500 Zeilen direkt Read, der Umweg lohnt erst darüber.