Skip to content

Latest commit

 

History

History
276 lines (196 loc) · 6.71 KB

File metadata and controls

276 lines (196 loc) · 6.71 KB

Contributing to Arbor

First off, thanks for considering contributing to Arbor. It's people like you that make this project possible.

Table of Contents

Code of Conduct

This project adheres to a Code of Conduct. By participating, you're expected to uphold this standard. Report unacceptable behavior to the maintainers.

Getting Started

What We're Looking For

  • Bug fixes — something isn't working as expected
  • New language parsers — help us support more ecosystems
  • Performance improvements — make the indexer even faster
  • Documentation — clarify confusing sections, add examples
  • Visualizer enhancements — new shaders, interactions, layouts

What to Avoid

  • Large architectural changes without discussion first
  • Vendoring dependencies unnecessarily
  • Breaking changes to the protocol without a migration path

Development Setup

Prerequisites

You'll need these installed:

Clone and Build

# Clone the repo
git clone https://github.com/Anandb71/arbor.git
cd arbor

# Build the Rust crates
cd crates
cargo build

# Run tests to make sure everything works
cargo test --all

# Build the visualizer (optional)
cd ../visualizer
flutter pub get
flutter build windows  # or macos/linux

# Verify your environment
cd ../crates
cargo run -- check-health

Running Locally

# Start the CLI in development mode
cd crates
cargo run --bin arbor-cli -- serve

# In another terminal, run the visualizer
cd visualizer
flutter run -d windows

# Or start everything together (MCP + Visualizer)
cargo run --bin arbor-cli -- bridge --viz

Making Changes

Branch Naming

Use descriptive branch names:

  • feat/python-parser — new feature
  • fix/watcher-memory-leak — bug fix
  • docs/protocol-examples — documentation
  • refactor/graph-query — code cleanup

Commit Messages

We follow conventional commits. Keep them short but descriptive:

feat(core): add Python class inheritance tracking

fix(watcher): handle symlink loops gracefully

docs: clarify WebSocket connection params

Testing Your Changes

Always run the test suite before submitting:

cd crates
cargo test --all
cargo clippy --all -- -D warnings

cd ../visualizer
flutter test
flutter analyze

Pull Request Process

  1. Fork the repo and create your branch from main
  2. Make your changes with appropriate tests
  3. Update documentation if you're changing behavior
  4. Run the full test suite and ensure it passes
  5. Submit your PR with a clear description

PR Template

When you open a PR, you'll see a template. Fill it out completely — it helps us review faster.

Review Timeline

We try to review PRs within a few days. Complex changes might take longer. If you haven't heard anything in a week, feel free to ping us.

Adding Language Support

Want to add support for a new language? Here's the process:

1. Add the Tree-sitter Grammar

In crates/arbor-core/Cargo.toml:

[dependencies]
tree-sitter-your-language = "0.20"

2. Create the Language Module

Create crates/arbor-core/src/languages/your_language.rs:

//! Parser implementation for YourLanguage.
//! 
//! Handles extraction of functions, classes, and imports from 
//! YourLanguage source files.

use crate::node::{CodeNode, NodeKind};
use crate::parser::LanguageParser;
use tree_sitter::Language;

pub struct YourLanguageParser;

impl LanguageParser for YourLanguageParser {
    fn language(&self) -> Language {
        tree_sitter_your_language::language()
    }

    fn extensions(&self) -> &[&str] {
        &["ext1", "ext2"]
    }

    fn extract_nodes(&self, tree: &tree_sitter::Tree, source: &str) -> Vec<CodeNode> {
        // Your extraction logic here
        vec![]
    }
}

3. Register the Parser

In crates/arbor-core/src/languages/mod.rs, add your language to the registry.

4. Add Tests

Create crates/arbor-core/tests/your_language_test.rs with representative test cases.

5. Update Documentation

Add your language to the table in README.md and any relevant docs.

Style Guide

Rust

We follow standard Rust conventions with a few preferences:

  • Use rustfmt for formatting (run cargo fmt)
  • Use clippy for linting (run cargo clippy)
  • Prefer explicit error handling over .unwrap()
  • Write doc comments for public APIs
  • Keep functions focused and reasonably sized
// Good: clear, documented, handles errors
/// Parses a source file and extracts all code nodes.
/// 
/// Returns an empty vector if the file cannot be parsed.
pub fn parse_file(path: &Path) -> Result<Vec<CodeNode>, ParseError> {
    let source = fs::read_to_string(path)?;
    let parser = detect_language(path)?;
    Ok(parser.extract_nodes(&source))
}

// Avoid: cryptic, no docs, panics on error
pub fn parse(p: &Path) -> Vec<CodeNode> {
    let s = fs::read_to_string(p).unwrap();
    detect_language(p).unwrap().extract_nodes(&s)
}

Flutter/Dart

  • Use dart format for formatting
  • Use flutter analyze for linting
  • Follow the Effective Dart guide
  • Keep widgets small and composable
  • Use providers for state management (Riverpod preferred)
// Good: clear naming, single responsibility
class GraphNode extends StatelessWidget {
  final NodeData data;
  final VoidCallback onTap;

  const GraphNode({
    required this.data,
    required this.onTap,
    super.key,
  });

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: onTap,
      child: CustomPaint(
        painter: NodePainter(data),
      ),
    );
  }
}

Comments

Write comments that explain why, not what. The code shows what's happening — comments should provide context.

// Meh: obvious from the code
// Increment the counter by one
counter += 1;

// Better: explains the why
// Tree-sitter uses 0-based byte offsets, but editors expect 1-based lines
let line = byte_offset_to_line(offset) + 1;

Questions?

  • Open a GitHub Discussion for general questions
  • File an issue for bugs or feature requests
  • Tag maintainers in your PR if you need guidance

Thanks for contributing. Let's build something great together.