Skip to content

Latest commit

 

History

History
251 lines (204 loc) · 25.2 KB

File metadata and controls

251 lines (204 loc) · 25.2 KB
description Java Chat - AI-powered Java learning with streaming responses, citations, and knowledge augmentation
alwaysApply true

Java Chat Agent Rules

Document Organization [ORG]

  • [ORG1] Purpose: keep every critical rule within the first ~250 lines; move long examples/notes to Appendix.
  • [ORG2] Structure: Rule Summary first, then detailed sections keyed by short hashes (e.g., [GT1a]).
  • [ORG3] Usage: cite hashes when giving guidance or checking compliance; add new rules without renumbering older ones.
  • [ORG4] Directive language: rules use imperative/prohibitive phrasing ("do X", "no Y", "never Z"); no discretionary hedges ("prefer", "consider", "try to", "ideally", "when possible") that give agents interpretive latitude.
  • [ORG5] Sole policy owner: AGENTS.md is the only repository policy source. Never create, retain, or cite a separate policy mirror, manifest, catalog, contract, or registry.

Rule Summary [SUM]

  • [ZA1a-c] Zero Tolerance Policy (zero assumptions, validation workflow, forbidden practices)
  • [GT1a-o] Git, history safety, hooks/signing, dirty paths, worktrees, and clean commits
  • [CC1a-d] Clean Code & DDD (Mandatory)
  • [SS1a-j] Direct Ownership & Boundary Locality
  • [ID1a-d] Idiomatic Patterns & Defaults
  • [EV1a-f] Secrets and Env Vars (no secrets in properties; OpenAI/Qdrant via .env/env)
  • [RC1a-f] Root Cause Resolution (single implementation, no fallbacks, no shims/workarounds)
  • [FS1a-l] File Responsibility & Clean Architecture (direct owner, deletion first, strict types)
  • [TY1a-d] Type Safety (strict generics, no raw types, no unchecked casts)
  • [FV1a-h] Frontend Validation (Zod schemas, discriminated unions, never swallow errors)
  • [AB1a-d] Abstraction Discipline (reuse-first, no anemic wrappers)
  • [NO1a-e] Null/Optional Discipline (no null returns, use Optional/empty collections)
  • [AR1a-f] Architecture & Boundaries (canonical roots, layer rules, framework-free domain)
  • [CS1a-h] Code Smells (primitive obsession, data clumps, magic literals)
  • [VR1a-c] Verification Loops (build/test/run)
  • [JD1a-h] Javadoc Standards (mandatory, why > what)
  • [ND1a-h] Naming Discipline (intent-revealing, banned generics, constant naming, type names)

[ZA1] Epistemic Humility (Zero Assumptions)

  • [ZA1a] Assume Blindness: Your training data for APIs/versions is FALSE until verified.
  • [ZA1b] Scout Phase: Before coding, use tools (context7, perplexity) and check local sources (~/.m2, ~/.gradle, node_modules) to verify existence/signatures of APIs.
  • [ZA1c] Source Verification: For dependency code questions, inspect ~/.m2 JARs or ~/.gradle/caches/ (for Java) or frontend/node_modules (for frontend) first; fallback to upstream GitHub; never answer without referencing code.
  • [ZA1d] Forbidden Practices:
    • No Map<String, Object>, raw types, unchecked casts, @SuppressWarnings, or eslint-disable in production.
    • No trusting memory—verify every import/API/config against current docs.
  • [ZA1e] Mandatory Research: You MUST research dependency questions and correct usage. Never use legacy or @deprecated usage from dependencies. Ensure correct usage by reviewing related code directly in node_modules or Gradle caches and using online tool calls.
  • [ZA1f] Dependency Search: To search node_modules efficiently with ast-grep, target specific packages: ast-grep run --pattern '...' frontend/node_modules/<package>. Do NOT scan the entire node_modules folder.
  • [ZA1g] No empty confirmations ("You're right", "Absolutely") before investigation; verify then cite evidence

[GT1] Git, History, Hooks, Lock Files

  • [GT1a] Never bypass pre-commit hooks or commit signing. Hooks are managed by lefthook (brew install lefthook, then make hooks).
  • [GT1b] If hooks fail, fix the environment; do not force the commit.
  • [GT1c] Read-only git commands (e.g., git status, git diff, git log, git show) never require permission. Any git command that writes to the working tree, index, or history requires explicit permission.
  • [GT1d] Commit message standards: one logical change per commit; describe the change and purpose; no tooling/AI references; no Co-authored-by or AI attribution.
  • [GT1e] Do not amend or rewrite history (no --amend, no force pushes) without explicit user permission.
  • [GT1f] Do not change branches (checkout/merge/rebase/pull) unless the user explicitly instructs it.
  • [GT1g] Destructive git commands are prohibited unless explicitly ordered by the user (e.g., git restore, git reset, force checkout).
  • [GT1h] Never delete lock files automatically (including .git/index.lock). Stop and ask for instruction.
  • [GT1i] Treat existing staged/unstaged changes as intentional unless the user says otherwise; never “clean up” someone else’s work unprompted.
  • [GT1j] Git commands that write to the working tree, index, or history require elevated permissions; never run without escalation.
  • [GT1k] Do Not Block On Baseline Diffs: If git status already shows modified files when you start, assume those changes are intentional and continue the requested task without stopping to ask about them. Avoid touching unrelated files.
  • [GT1l] Stop Only On Concurrent Drift: Only stop and ask for direction if a file changes unexpectedly during your work in a way that conflicts with edits you are actively making (e.g., a file you are editing changes on disk between reads/writes). Otherwise, proceed and keep changes scoped.
  • [GT1m] Repository-Local Writes Only: NEVER commit or push to this repository from a temporary clone, alternate checkout/worktree, or any other directory copy of the same repo. All git writes must be executed from this exact working tree.
  • [GT1n] Dirty-Path Integrity: Never rewrite, restore, replace, regenerate, or copy a dirty path from HEAD, the index, cached copies, an alternate worktree, or a temporary clone. Read the live path and apply the smallest in-place edit.
  • [GT1o] Writable Agent Root: Each worktree has exactly one writable agent root. All other agents remain read-only in that worktree or use a distinct worktree; never share write authority.

[CC1] Clean Code & DDD (Mandatory)

  • [CC1a] Mandatory Principles: Clean Code principles (Robert C. Martin) and Domain-Driven Design (DDD) are mandatory and required in this repository.
  • [CC1b] DRY (Don't Repeat Yourself): Avoid redundant code. Reuse code where appropriate and consistent with clean code principles.
  • [CC1c] YAGNI (You Aren't Gonna Need It): Do not build features or abstractions "just in case". Implement only what is required for the current task.
  • [CC1d] Clean Architecture: Dependencies point inward. Domain logic has zero framework imports.
  • [CC1e] Tracer bullet: Build one tiny end-to-end slice through all layers first; validate it works; then expand — never build horizontal layers in isolation.
  • [CC1f] KISS: Simplest solution that works; achieve by removing, not adding; use platform/framework defaults unless deviation is proven necessary

[SS1] Direct Ownership & Boundary Locality (Mandatory)

  • [SS1a] Direct Owner: Put each behavior and business rule with its closest production owner. Do not introduce a central owner merely because multiple consumers have equivalent shapes.
  • [SS1b] No Invented Schema Machinery: Never create a manifest, catalog, contract, registry, or equivalent metadata layer merely to claim SSOT, enumerate a field inventory, share equivalent shapes across languages, prove parity, or support tests.
  • [SS1c] Boundary-Local Duplication: Duplicate a small, stable declaration at a genuine boundary (HTTP, persistence, CLI, frontend, or test) when direct typed code is clearer and avoids invented schema machinery. Keep it local to that boundary and delete it when it no longer serves the boundary.
  • [SS1d] No Semantic Aliases: Outside a boundary's actual protocol, plural/singular variants, compatibility aliases, label identifiers, alternate display-name identifiers, and convenience transport names for the same concept are prohibited.
  • [SS1e] Boundary Fidelity: Use the names required by each real boundary. Do not add aliases or cross-layer transport names solely to imitate another representation.
  • [SS1f] Stop-Work Trigger: If repeated declarations stop being small and boundary-local, delete obsolete copies or place the behavior or rule with its direct owner. Never resolve the problem by adding an inventory artifact.
  • [SS1g] No Positional-Null Sludge: Constructor/factory calls with repeated placeholder nulls or low-legibility optional argument trains are prohibited; use named factories, builders, or parameter objects.
  • [SS1h] Whole-List Smell: A whole-list declaration is valid only when local runtime behavior uses the whole list. Delete stale or test-only inventory copies; never maintain an all-purpose list merely to prove ownership or coverage.
  • [SS1i] Policy Owner: AGENTS.md is the sole policy owner. Do not move or mirror policy into documentation, manifests, catalogs, contracts, registries, tests, or generators.
  • [SS1j] No Fabricated Sharing: Cross-language code uses native boundary types. Do not add shared metadata, a generated mirror, or a parity test merely because fields align.

[ID1] Idiomatic Patterns & Defaults

  • [ID1a] Defaults First: Always prefer the idiomatic, expected, and default patterns provided by the framework, library, or SDK (Spring Boot, Java 21+, etc.).
  • [ID1b] Custom Justification: Custom implementations require a compelling reason. If you can't justify it, use the standard way.
  • [ID1c] No Reinventing: Do not build custom utilities for things the platform already does (e.g., use standard Optional, Stream, Spring RestTemplate/WebClient).
  • [ID1d] Dependencies: Make careful use of dependencies. Do not make assumptions—use the correct idiomatic behavior to avoid boilerplate.

[EV1] Secrets and Env Vars

  • [EV1a] No Secrets In Properties/YAML: Secrets are PROHIBITED in .properties and .yml/.yaml (including examples). Do not add secret-looking keys with blank defaults to property files.
  • [EV1b] Secrets Source Of Truth: Secrets MUST be provided via .env (local) and environment variables (deployment). Deployment uses Coolify containers with BuildKit secrets; keep secrets out of tracked config.
  • [EV1c] Non-Secret Defaults In Properties: All non-secret defaults and environment-specific overrides MUST live in Spring property files (src/main/resources/application*.properties) and Spring profiles.
  • [EV1d] Allowed .env/Env Vars For External Services: Shared-gateway inference and Qdrant connectivity MUST come from .env/environment variables:
    • LLM (model/base-url/api-key): OPENAI_API_KEY, OPENAI_BASE_URL, OPENAI_MODEL
    • Qdrant (host/ports/tls/api-key): QDRANT_HOST, QDRANT_PORT, QDRANT_REST_PORT, QDRANT_SSL, QDRANT_API_KEY
  • [EV1e] No New Env Var Settings: Do not introduce any additional env-var-driven settings without explicit written approval.
  • [EV1f] Dotenv Handling: .env loading MUST remain supported for local development and scripts. Do not add dotenv libraries into the Java runtime; load env vars at the process level (Makefile/scripts/Coolify).

[RC1] Root Cause Resolution — No Fallbacks

  • [RC1a] One Way: Ship one proven implementation—no fallback paths, no "try X then Y", no silent degradation.
  • [RC1b] No Shims: NO compatibility layers, shims, adapters, or wrappers that hide defects.
  • [RC1c] Fix Roots: Investigate → understand → fix root causes. Do not add band-aids to silence errors.
  • [RC1d] Dev Logging: Dev-only logging is allowed to learn (must not change behavior, remove before shipping).
  • [RC1e] Exceptions: Use typed exception handling patterns; propagate meaningful errors, never swallow silently.
  • [RC1f] Explicit Violations: Any of the following is a violation that must be removed, not justified:
    • Returning "best effort" results after a dependency failure (LLM, embeddings, vector store, database, filesystem).
    • Catching and logging an exception while continuing as if the operation succeeded.
    • Adding a secondary retrieval/indexing path that runs only when the primary path fails.
  • [RC1g] BANNED slop indirection: no *Adapter, *Transformer, *Normalizer, *Bridge, *Converter, *Mapper, *Compatibility, *Transition modules that exist solely to reshape data between equivalent types; fix the type mismatch at source (architectural adapters at genuine boundaries per [AR1] are fine)

[FS1] File Responsibility & Clean Architecture

  • [FS1a] Search and Direct Owner: Search exhaustively for existing logic and identify its direct owner. Reuse or extend that owner, or delete obsolete logic, before creating a type.
  • [FS1b] Responsibility, Not File Count: Put behavior in its closest existing owner when it shares that owner's responsibility. Create a new file only for a genuinely independent responsibility; never require a new file merely because a feature is new.
  • [FS1c] Canonical Roots: boot/, application/, domain/, adapters/, support/.
  • [FS1d] Convention over Configuration: Prefer Spring Boot defaults and existing utilities.
  • [FS1e] No Generic Utilities: Reject *Utils/*Helper/*Common. Banned: BaseMapper<T>, GenericRepository<T,ID>, SharedUtils.
  • [FS1f] Deletion-First Scope: Line count never determines design. Delete dead, duplicate, or accidental complexity first; extract only when an independent responsibility needs a clearer direct owner, never merely to meet a file-size threshold.
  • [FS1g] Domain Value Types: Identifiers, amounts, slugs wrap in records with constructor validation; never raw primitives across API boundaries.
  • [FS1h] Single Responsibility Methods: No dead code; no empty try/catch that swallows exceptions.
  • [FS1i] Dependency Injection: Never manually instantiate ObjectMapper, RestTemplate, or HttpClient; always inject the Spring-managed bean.
  • [FS1j] Custom Properties: Custom app.* properties require @ConfigurationProperties binding in AppProperties.
  • [FS1l] Policy Location: Consult AGENTS.md for repository policy. Never create or maintain a separate code-change policy contract.

[TY1] Type Safety

  • [TY1a] Strict Generics: No raw types (e.g., List without <T>).
  • [TY1b] No Unchecked Casts: If a cast is unavoidable, guard with explicit conversions (e.g., Number::intValue) instead of suppressing.
  • [TY1c] No Suppressions: Never use @SuppressWarnings to resolve lint issues; fix the code.
  • [TY1d] No Map<String, Object>: Use typed records or classes.

[FV1] Frontend Validation (Zod)

  • [FV1a] Mandatory Validation: All external data (API responses, SSE events, localStorage) MUST be validated through Zod schemas before use. External data is unknown until validated.
  • [FV1b] No as Casts: Never use as Type assertions for external data. Use Zod safeParse() with proper error handling.
  • [FV1c] Discriminated Unions: Return { success: true, data } or { success: false, error }, never null. No silent fallbacks.
  • [FV1d] Never Swallow Errors: Every validation failure MUST be logged with full context via logZodFailure(). No empty catch blocks.
  • [FV1e] Record Identification: Every error log MUST identify WHICH record failed (slug, ID, URL, endpoint name).
  • [FV1f] Single Source of Truth: All schemas live in frontend/src/lib/validation/schemas.ts. Types are inferred via z.infer<>, never duplicated.
  • [FV1g] No parse(): Use safeParse() exclusively. parse() throws and can crash rendering.
  • [FV1h] Schema Matches API: Schema optional()/nullable()/nullish() MUST match the actual API contract. Verify against real responses.

[AB1] Abstraction Discipline

  • [AB1a] No Anemic Wrappers: Do not add classes that only forward calls without domain value.
  • [AB1b] Earn Reuse: New abstractions must earn reuse—extend existing code first; only add new type/helper when it removes real duplication.
  • [AB1c] Behavior Locality: Keep behavior close to objects: invariants live in domain model/services, not mappers or helpers.
  • [AB1d] Delete Unused: Delete unused code instead of keeping it "just in case."

[NO1] Null/Optional Discipline

  • [NO1a] No Null Returns: Public methods never return null; singletons use Optional<T>; collections return empty, never null.
  • [NO1b] Domain Invariants: Domain models enforce invariants; avoid nullable fields unless business-optional and documented.
  • [NO1c] Empty Collections: Return List.of(), Set.of(), Map.of() instead of null.
  • [NO1d] No Optional Params: Optional parameters prohibited in business logic: accept nullable T, check internally; call sites unwrap with .orElse(null).
  • [NO1e] Usage: Use Optional.map/flatMap/orElseThrow; avoid isPresent()/get() chains.

[AR1] Architecture & Boundaries

  • [AR1a] Controllers (adapters/in/web): Translate HTTP to domain, delegate to one use case, return ResponseEntity; no repo calls, no business logic.
  • [AR1b] Use Cases (application/): Transactional boundary, single command, orchestrate domain/ports.
  • [AR1c] Domain (domain/): Invariants/transformations, framework-free, no Spring imports.
  • [AR1d] Adapters (adapters/out/): Implement ports, persist validated models, no HTTP/web concerns.
  • [AR1e] Composition: Favor composition over inheritance; constructor injection only; services stateless.
  • [AR1f] Catch-Alls: A multi-concern catch-all is a monolith regardless of line count. Delete misplaced or dead code and split only when an independent responsibility needs its own direct owner.

[CS1] Code Smells

  • [CS1a] Primitive Obsession: Wrap IDs/amounts/business values in domain types when they carry invariants.
  • [CS1b] Data Clumps: When 3+ parameters travel together, extract into a record (DateRange, PageSpec, SearchCriteria).
  • [CS1c] Long Params: >4 parameters use parameter object or builder; never add 5th positional argument.
  • [CS1d] Feature Envy: If method uses another object's data more than its own, move it there.
  • [CS1e] Switch on Type: Replace with polymorphism when branches >3 or recur.
  • [CS1f] Temporal Coupling: Enforce call order via state machine, builder, or combined API.
  • [CS1g] Magic Literals: No inline numbers (except 0, 1, -1) or strings; define named constants.
  • [CS1h] Comment Deodorant: If comment explains what, refactor until self-documenting; comments explain why only.

[VR1] Verification Loops

  • [VR1a] Build: make build or ./gradlew build; expect success.
  • [VR1b] Tests: make test or ./gradlew test; targeted runs use --tests ClassName.
  • [VR1c] Runtime: make run &, hit /actuator/health and changed endpoints; then stop.
  • [VR1d] Validate each slice: After completing an end-to-end slice ([CC1e]), run make build and make test before starting the next slice.
  • [VR1e] Direct-Owner Cleanup Handoff: Name the direct production owner, list redundant artifacts deleted, identify each intentional small boundary-local duplication and why it avoids schema machinery, and cite tests that exercise the behavior. Do not create a manifest, catalog, contract, registry, or parity report for handoff.

[JD1] Javadoc Standards

  • [JD1a] Mandatory: Javadocs mandatory on public/protected classes, methods, and enums.
  • [JD1b] Why > What: Focus on "why" (purpose, rationale, constraints) over "what".
  • [JD1c] Summary: First sentence is the summary: complete sentence, present tense, third person.
  • [JD1d] Tags: Use @param only when name isn't self-documenting; use @return only for non-obvious values.
  • [JD1e] Throws: Include @throws for checked exceptions and runtime exceptions callers should handle.
  • [JD1f] Evidence: Cite sources inline (e.g., "Per RFC 7231").
  • [JD1g] Deprecation: @Deprecated annotation AND @deprecated tag with migration path.
  • [JD1h] No Filler: Ban "This method...", "Gets the...". Start with verb or noun directly.

[DS1] Dependency Source Verification

  • [DS1a] Locate: Find source JARs in Gradle cache: find ~/.gradle/caches/modules-2/files-2.1 -name "*-sources.jar" | grep <artifact>.
  • [DS1b] List: View JAR contents without extraction: unzip -l <jar_path> | grep <ClassName>.
  • [DS1c] Read: Pipe specific file content to stdout: unzip -p <jar_path> <internal/path/to/Class.java>.
  • [DS1d] Search: To use ast-grep on dependencies, pipe content directly: unzip -p <jar> <file> | ast-grep run --pattern '...' --lang java --stdin. No temp files required.
  • [DS1e] Efficiency: Do not extract full JARs. Use CLI piping for instant access.
  • [DS1f] Ensure Sources: If sources are missing, assume standard dev environment has them or instruct user to run ./gradlew downloadSources (if alias exists).

[TL1] Tooling & Environment

  • [TL1a] Commands: make run, make dev, make test, make build, make compose-up, make compose-down.
  • [TL1b] Docker: docker compose up -d for Qdrant vector store.
  • [TL1c] Ingest: curl -X POST http://localhost:8080/api/ingest ....
  • [TL1d] Stream: curl -N http://localhost:8080/api/chat/stream ....
  • [TL1e] Secrets: Never commit secrets. Secrets MUST live in .env (local) and environment variables (deployment). Secrets are PROHIBITED in .properties/.yml files.

[LM1] LLM & Streaming

  • [LM1a] Settings: Do not change any LLM settings without explicit written approval.
  • [LM1b] No Fallback: Do not auto-fallback or regress models across providers; surface error to user.
  • [LM1c] Config: Generative inference MUST use exact gpt-5.4 through the shared OpenAI-compatible gateway. Its model/base-url/api-key MUST come from .env/environment variables (see [EV1d]). All other LLM settings MUST come from Spring property files and @ConfigurationProperties.
  • [LM1d] Behavior: Allowed: logging diagnostics. Not allowed: silently changing LLM behavior.
  • [LM1e] Streaming: TTFB < 200ms, streaming start < 500ms.
  • [LM1f] Events: text, citation, code, enrichment, suggestion, status.
  • [LM1g] Errors: onErrorContinue for partial failures; never drop entire response on single failure.
  • [LM1h] Heartbeats: Maintain connection with periodic events during long operations.
  • [LM1i] GitHub Models Prohibited: Never add GitHub Models provider selection, endpoints, credentials, SDKs, tests, documentation, or fallback behavior. Preserve unrelated GitHub repository ingestion, citations, source links, and Actions.

[MD1] Markdown & Parsing

  • [MD1a] No Regex: No regex for HTML/Markdown processing; use proper parsers (Flexmark, DOM APIs).
  • [MD1b] Structured Data: Parse to objects, transform, serialize.
  • [MD1c] Idiomatic: Use Java Streams, Optional, proper HTML APIs.
  • [MD1d] Separation: Backend handles structure, frontend handles presentation.
  • [MD1e] Fail-safe: Graceful degradation when parsing fails; never crash on malformed input.

[ND1] Naming Discipline

  • [ND1a] Intent-Revealing: Every identifier (variable, parameter, method, class, constant) must be domain-specific and intent-revealing; a reader must understand purpose without context from surrounding code.
  • [ND1b] Banned Single-Letter Variables: a, b, c, d, n, o, p, s, t, v, x, y, z are prohibited as variable/parameter names. Exceptions: i, j, k in trivial indexed for loops; single-char lambda params only when the type is unambiguous in a one-expression pipeline (e.g., list.stream().map(e -> e.name())); e in catch blocks.
  • [ND1c] Banned Generic Nouns: These names (and close variants) are prohibited as variable, parameter, or field names: data, info, value, val, item, items, obj, object, result, results, response, payload, content, stuff, thing, entry, element, record, temp, tmp, misc, foo, bar, baz, dummy, sample. Use domain-specific names that describe what the variable holds (e.g., embeddingVector not data; chatMessage not item; rankedDocuments not results).
  • [ND1d] Banned Abbreviations: No abbreviated variable names: val, res, req, resp, msg, str, num, cnt, idx, len, buf, ctx, cfg, mgr, impl, proc, ref, desc, doc, col, cb. Use full words: message, request, response, count, index, length, buffer, context, configuration, manager, description, document, column, callback.
  • [ND1e] Constants: UPPER_SNAKE_CASE with domain-qualifying prefix; no bare generic constant names like VALUE, DATA, DEFAULT, THRESHOLD, LIMIT, SIZE, TIMEOUT, COUNT, MAX, MIN without a qualifying domain noun (e.g., EMBEDDING_DIMENSION not SIZE; RERANKER_TIMEOUT_MS not TIMEOUT; MAX_RETRIEVAL_RESULTS not MAX).
  • [ND1f] Type Names: No generic suffixes *Data, *Info, *Object, *Item, *Wrapper, *Holder, *Container, *Manager (unless the class genuinely manages a lifecycle); class and record names declare their domain role.
  • [ND1g] Alias Consistency: The same concept uses the same name across method signatures, variable assignments, log messages, and documentation; do not alias the same thing with different names in the same scope or call chain.
  • [ND1h] Legacy Fix-on-Touch: When editing code that uses banned or generic names, rename them in the same edit; never introduce new generic names into existing code.