This file contains instructions for AI agents working in this Bazel-based polyglot monorepo.
CRITICAL: Use bazel for ALL operations. Do not use cargo, npm, mvn, or go directly unless explicitly instructed.
# Build entire repository
aspect build //...
# Run all tests
aspect test //...
# Update BUILD files (MUST run immediately after ANY source file edit)
bazel run //:gazelle
# Format changed files (Rust, Kotlin, Go, JS/TS, BUILD files)
aspect format
# Format the entire repository
aspect format --scope=all
# Run all linters
aspect lint
# Install/update NPM dependencies
bazel run @pnpm -- --dir $PWD install- Identify the test target in the relevant
BUILD.bazelfile - Run the specific test:
# Rust (test suite)
aspect test //nicknamer/server/lib/tests:tests
# Rust (specific test with filter)
aspect test //nicknamer/server/lib/tests:tests --test_filter="test_name_pattern"
# Update Rust snapshot tests
INSTA_UPDATE=always aspect test //nicknamer/server/lib/tests:tests
# Go (single test target)
aspect test //predix/internal/domain/circle:circle_test
# Go (specific test function)
aspect test //predix/internal/domain/circle:circle_test --test_filter="^TestCircleCreation$"
# Kotlin (JUnit 5)
aspect test //mindreadr/src/test/io/lowkeylab/mindreadr:MindreadrTest# Show all errors (don't stop at first failure)
aspect build //... --keep_going
# Investigate specific failure with verbose output
aspect build //path/to/target --verbose_failures
# Clean and rebuild
bazel clean && aspect build //...- Gazelle: MUST run
bazel run //:gazelleimmediately after editing ANY source file (.rs, .kt, .go, .ts, .js, .proto, etc.) and BEFORE formatting - Formatting: ALWAYS run
aspect format --scope=allbefore committing or completing a task - Minimal changes: Only modify what's strictly necessary
- Dependencies: Prefer existing libraries in
MODULE.bazel - BUILD files: Never manually edit BUILD files before running
bazel run //:gazelle - Verification: Run
aspect build //...to verify changes don't break the build - Security: NEVER hardcode secrets/credentials; use environment variables
Edition: 2024
Imports:
- Group imports:
std, external crates, internal modules - Use explicit paths, avoid glob imports
Types & Error Handling:
- Use
anyhow::Result<T>for applications/binaries - Use
thiserrorfor library error types - Prefer
?operator for error propagation
Async & Runtime:
- Use
tokioruntime exclusively - Prefer async/await patterns
- Use
tracingfor structured logging (notprintln!ordbg!)
Naming Conventions:
snake_casefor functions, variables, modulesPascalCasefor types, traits, enumsSCREAMING_SNAKE_CASEfor constants
Database:
- Use
SeaORMentities and migrations - Migrations in
nicknamer/migration/
Testing:
- Use
instafor snapshot testing - Integration tests use
testcontainersfor PostgreSQL
Style: Ktor framework patterns
Imports:
- Organized: wildcard (*), java., javax., kotlin.**, project imports (^)
- Configured in
.editorconfig
Formatting:
- 2-space indentation
- Max line length: 200 characters
- Run
aspect format(uses ktfmt)
Types & Naming:
- Use type inference when obvious
camelCasefor functions, variables, propertiesPascalCasefor classes, interfaces, objects- Avoid abbreviations
Async:
- Use Kotlin Coroutines for async operations
- Prefer
suspendfunctions over callbacks
Testing:
- JUnit 5 framework
- Test files mirror source structure in
src/test/
Style: Standard Go conventions (gofmt)
Imports:
- Grouped: stdlib, external, internal
- Use
gofumpt(viaaspect format)
Types & Naming:
camelCasefor unexported,PascalCasefor exported- Interfaces:
-ersuffix (e.g.,Reader,Handler) - Avoid stuttering (
user.UserService→user.Service)
Error Handling:
- Return errors as last return value
- Check errors immediately:
if err != nil - Wrap errors with context:
fmt.Errorf("operation failed: %w", err)
Context:
- ALWAYS propagate
context.Contextas first argument for I/O operations - Use
ctx context.Contextparameter name
Database:
- Use
sqlcfor type-safe SQL code generation - Schema in
predix/internal/sql/schema.sql - Run
cd predix && sqlc generateafter schema changes
Testing:
- Test files:
*_test.goin same package - Test functions:
func TestXxx(t *testing.T) - Use table-driven tests for multiple cases
Strictness: All projects use strict: true in tsconfig.json
Imports:
- Organize: framework, third-party, internal
- Use absolute imports from
tsconfig.jsonpaths - Avoid circular dependencies
Types:
- Use type inference when obvious
- Avoid
any; useunknownif uncertain - Prefer interfaces for object shapes
- Use
readonlyfor immutable data
Naming:
camelCasefor functions, variables, propertiesPascalCasefor classes, interfaces, typesSCREAMING_SNAKE_CASEfor constants
Angular Conventions:
- Use standalone components (no NgModules)
- Do NOT set
standalone: true(it's the default) - Use
inject()over constructor injection - Use signals for state:
input(),output(),signal(),computed() - Set
changeDetection: ChangeDetectionStrategy.OnPush - Native control flow:
@if,@for,@switch(not*ngIf,*ngFor) - Use
asyncpipe for observables - Prefer inline templates for small components
Services:
- Single responsibility
- Use
providedIn: 'root'for singletons
Formatting:
- 2-space indentation (Prettier)
- Run
aspect format
Style: Run bazel run //tools:buildifier for formatting
Conventions:
- Use
# keepcomments for lines that shouldn't be auto-modified by Gazelle - Run
bazel run //:gazellebefore manual edits to BUILD files - Verify changes:
aspect build //path/to/package/...
bazel-repo/
├── angular/ # Angular workspace (Mindreadr, Nicknamer, Predix frontends)
├── cowsay/ # Go demo service
├── mindreadr/ # Kotlin/Ktor backend
├── nicknamer/ # Rust/Axum backend
│ ├── migration/ # SeaORM migrations
│ └── server/ # Server implementation
├── predix/ # Go backend
│ └── internal/sql/ # sqlc schema and queries
├── tools/ # Formatters, linters, toolchains
├── MODULE.bazel # External dependencies
├── go.mod, go.sum # Go dependencies
├── pnpm-lock.yaml # Node.js dependencies
└── Cargo.lock # Rust dependencies
- Make code changes in appropriate project directory
- Run Gazelle immediately:
bazel run //:gazelle(REQUIRED after ANY source file edit) - Format code:
aspect format --scope=all(handles all languages) - Run tests:
aspect test //path/to/testsoraspect test //... - Test locally: Use project-specific run commands (see subproject AGENTS.md)
- Verify build:
aspect build //...(use--keep_goingto see all errors) - Run linters (optional but recommended):
aspect lint - Commit changes after ensuring tests pass and code is formatted
- Tool Management: Bazel manages Node.js, Rust, JDK, Go toolchains—do NOT install separately
- Bazelisk: Manages Bazel version from
.bazelversion - Context Switching: Be aware of language-specific idioms (this is a multi-language repo)
- Dependencies: Check
MODULE.bazelfor available libraries before adding new ones
For detailed project documentation, see:
- Nicknamer (Rust):
nicknamer/AGENTS.md - Angular Apps:
angular/AGENTS.md - Root Context:
GEMINI.md(comprehensive guide) - Copilot Instructions:
.github/copilot-instructions.md
# Build failures
bazel clean && aspect build //...
aspect build //... --keep_going # See all errors
# NPM dependencies out of sync
bazel run @pnpm -- --dir $PWD install
# Go dependencies missing
go get <package> && bazel mod tidy
# BUILD files out of sync
bazel run //:gazelle
# Bazel not found
which bazel # Should point to bazelisk
# Database migrations (Nicknamer)
bazel run //nicknamer/migration/bin -- up
# Regenerate sqlc code (Predix)
cd predix && sqlc generate- ❌ Using
cargo build/testinstead ofaspect build/test - ❌ Using
npm installinstead ofbazel run @pnpm -- --dir $PWD install - ❌ Forgetting to run
bazel run //:gazelleimmediately after editing source files - ❌ Running
aspect formatbefore runningbazel run //:gazelle - ❌ Editing BUILD files before running
bazel run //:gazelle - ❌ Forgetting to run
aspect format --scope=allbefore committing - ❌ Hardcoding secrets instead of using environment variables
- ❌ Creating new directories without understanding the project structure