This guide helps AI agents work efficiently on the brush codebase by providing essential context about architecture, patterns, and development workflows.
The brush project is organized into several key crates:
brush-core/: Core shell functionality, builtins, and runtimebrush-parser/: Shell script parsing (AST generation)brush-builtins/: Implementation of shell builtins (e.g., echo, cd)brush-interactive/: Interactive shell interfaces (readline, etc.)brush-shell/: Main CLI application and entry point
Critical files to understand first:
brush-core/src/shell.rs- MainShellstruct and creation logicbrush-core/src/lib.rs- Public API exportsbrush-shell/src/main.rs- CLI application entry point
Architecture patterns:
- Shell instances are created via
Shell::builder() - The project uses builder patterns for type-safe configuration
- We try to keep platform-specific code in
brush-coreunder thesysmodule - Follows Rust 2024 edition standards
brush-shell → brush-interactive → brush-core → brush-parser
↘ brush-builtins ↗
Recommended development workflow:
The project provides a cargo xtask command that centralizes common development tasks:
# Run quick inner-loop checks (~7s warm): fmt, build, lint, unit tests
cargo xtask ci quick
# Run full pre-commit checks (~45s warm): quick + deps, schemas, integration tests
cargo xtask ci pre-commit
# Run with --continue-on-error to see all failures at once
cargo xtask ci pre-commit -k
# Add -v for verbose output showing exact commands being run
cargo xtask -v ci pre-commit# Run unit tests (fast tests excluding integration binaries)
cargo xtask test unit
# Run integration tests (all workspace tests including compat tests)
cargo xtask test integration
# Run tests with coverage
cargo xtask test integration --coverage --coverage-output codecov.xmlFor finer-grained control:
- Quick validation:
cargo check --package <changed-package>- Fast syntax/type checking - Correctness validation:
cargo test --package <changed-package>- Target specific crates for faster feedback
- Compatibility tests:
cargo test --test brush-compat-tests- Bash compatibility validation - Full workspace tests:
cargo test --workspace- Complete test suite
Recommended: Run the xtask pre-commit workflow:
cargo xtask ci pre-commitManual approach: Before considering work complete, run these validation steps:
- Compatibility tests:
cargo test --test brush-compat-tests - Linting:
cargo clippy - Formatting:
cargo fmt --check - Security/License audit:
cargo deny check all - Full test suite:
cargo test --workspace
When tests fail:
- Focus on failures in the area you changed first
- Compatibility test failures often indicate shell behavior changes
- Check if new functionality needs corresponding test cases
- Format/clippy failures should be fixed before proceeding
Common pitfalls:
- Test scope mistakes: Running full test suite too early instead of targeting specific areas first
- Skipping test-driven development: Add tests that specify desired behavior before implementing
Test-driven development approach:
- When possible, write tests first that specify the desired behavior
- Use unit tests for logic changes, compatibility tests for shell behavior changes
- Use these tests as validation that your implementation is working correctly
Pro tip: For specific compatibility test cases, use:
cargo test --test brush-compat-tests -- '<name of test case>'Fast iteration strategies:
- Target specific crates:
cargo test --package <changed-package> - Target specific test cases:
cargo test <test-name>orcargo test --test <test-file> - Requires knowledge of which tests best exercise the code being changed
Testing approach:
- Follow good software engineering practice: start by validating the specific area being changed, then iteratively move to incrementally broader sets of tests
Testing expectations for new public APIs:
- Unit tests are expected if feasible
- Examples are nice to have and worthwhile for sufficiently critical APIs
Test patterns and conventions:
- Compatibility tests: For any compatibility-related fixes, it's critical to add new test cases to the compat tests (see docs/how-to/run-tests.md and section 3 for when breaking changes apply)
Test categories:
- Unit tests: In
src/files with#[cfg(test)] - Integration tests: In
tests/directories - Examples: In
examples/directories (must be runnable) - Shell script tests: YAML-based test cases in
brush-shell/tests/cases/
Performance regression testing:
- Not a chief concern for most changes
- For performance-specific work, benchmarks are available (see docs/how-to/run-benchmarks.md)
- Performance sensitivity will be identified in the initial brief if relevant
Breaking change policy:
- Non-backwards compatible changes to public APIs are considered breaking
- Breaking changes are still in consideration, but need to be highlighted and carefully reviewed
- Any APIs exported from crates are considered public because all of the crates are published to crates.io
Adding new fields to public structs:
- New optional fields are fine to add as long as the struct implements the Default trait and as long as the defaulted value is a sensible one
When changing public APIs in brush-core (see section 3 for breaking change policy):
- Check
brush-shell/src/main.rsfor struct initialization sites - Check
brush-interactive/for any usage
Rustdoc documentation standards:
- At minimum we must have good rustdoc documentation for exported types, functions, traits, etc. as well as on all exported modules and crates
- Documentation for internal components should be a best-effort, nice to have thing
Examples for new features:
- Unless explicitly requested, only major feature additions warrant an example.
Documentation style:
- Follow general best practices for Rust
Examples should:
- Be self-contained and runnable with
cargo run --package brush-core --example <name> - Include comprehensive error handling
- Demonstrate both basic and advanced usage patterns
- Include output examples in comments when helpful
The project uses several tools for code quality:
Using xtask (Recommended):
The project provides a cargo xtask command that centralizes common development tasks:
# Run all pre-commit checks (comprehensive)
cargo xtask ci pre-commit
# Individual checks
cargo xtask check fmt # Format check
cargo xtask check lint # Clippy
cargo xtask check deps # cargo-deny
cargo xtask check build # Compilation check
cargo xtask check schemas # Schema drift check
# Tests
cargo xtask test unit # Fast unit tests (excludes integration binaries)
cargo xtask test integration # All workspace tests (unit + compat)
# Analysis
cargo xtask analyze bench # Run benchmarksManual approach (Alternate):
- Standard cargo commands (e.g., check, test, build, run, clippy)
- You may need to reverse engineer some of the args looking at CI checks in .github/*.yml
Command frequency guidelines:
- Frequent (inner loop):
cargo xtask ci quick,cargo check,cargo test --package <pkg> - Regular (before commits):
cargo xtask ci pre-commitorcargo fmt+cargo clippy - Occasional (outer loop):
cargo xtask test integrationorcargo test --workspace - Rare (pre-finish only):
cargo xtask check depsorcargo deny check
Pre-commit validation:
- Recommended:
cargo xtask ci pre-commit - Quick check:
cargo xtask ci quickfor fast feedback - Manual: Run
cargo fmtandcargo clippybefore committing
Outer loop validation:
cargo deny check allshould pass (security/license auditing) - not for frequent use during development
Error handling patterns:
thiserroris used for implementing crate-specific errors- Use
anyhowonly in tests
Logging and tracing patterns:
- Use
tracingfor debug logging with predefined categories - Categories are defined in
trace_categories.rsmodules (e.g.,COMMANDS,COMPLETION,EXPANSION,FUNCTIONS,INPUT,JOBS,PARSE,PATTERN,UNIMPLEMENTED) - Usage pattern:
tracing::debug!(target: trace_categories::CATEGORY_NAME, "message") - Example:
tracing::debug!(target: trace_categories::JOBS, "Polling job {} for completion...", job_id)
Clone vs references:
- Avoid cloning by default, no reason to make extra copies
- Only use cloning when you really must capture a separate copy for async safety or similarly important reasons
Following the Linux kernel convention, when AI assistants or advanced coding tools have been used in the development of a change, include an Assisted-by: tag in the commit message. This provides transparency about the use of such tools in the development process.
The format for the Assisted-by tag is:
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
Example:
Assisted-by: Mistral Vibe:mistral-medium-3.5
When making changes to brush:
- Understand which crate(s) are affected
- Check if changes might break dependent crates
- Identify relevant test files and examples
- Run
cargo checkfrequently during development - Test changes with package-specific tests first (see section 2 for testing workflow)
- Update dependent crate usage if needed (see section 3 for compatibility considerations)
- Add/update examples for major feature additions only (see section 4)
- Run full test suite:
cargo test(see section 2 for complete testing workflow) - Format code:
cargo fmt(see section 5 for tool details) - Check linting:
cargo clippy - Use conventional commit format
- If using AI assistants or advanced coding tools, include an
Assisted-by:tag in the formatAGENT_NAME:MODEL_VERSION(following Linux kernel convention)
- Add rustdoc to exported APIs (see section 4 for documentation standards)
- Include working examples for major features only
- Update this guide if new patterns emerge