This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Drasi-core is a Rust workspace library that implements continuous queries for graph data using Cypher Query Language. It provides the foundational components for the Drasi platform and can also be used standalone for embedded scenarios.
This is a Cargo workspace with the following key components:
- core - Main library with query evaluation engine, in-memory indexing, and continuous query processing
- query-ast - Abstract syntax tree for query parsing
- query-cypher - Cypher query language parser and compiler
- query-gql - GraphQL query support
- functions-cypher - Built-in Cypher functions
- functions-gql - Built-in GraphQL functions
- index-rocksdb - RocksDB persistent storage backend
- index-garnet - Garnet (Redis-compatible) storage backend
- middleware - Query middleware components
- examples - Usage examples and demonstrations
- query-perf - Performance testing utilities
- lib - Library that lets you run Drasi as a fully functional embedded library with sources, queries, reactions, and bootstrap providers
- shared-tests - Common test utilities
cargo build # Build all workspace members
cargo build --release # Release build with optimizations
cargo build -p drasi-core # Build specific packagecargo test # Run all tests
cargo test -p drasi-core # Run tests for specific packageFor performance tests:
cd query-perf
cargo run -- -s all -e memory -r memory -i 100000cargo clippy --all-targets --all-features # Run clippy lints
cargo fmt # Format code
cargo fmt -- --check # Check formattingThe project uses specific clippy configuration in clippy.toml that allows print/unwrap in tests.
- Uses Rust 1.83.0 for CI (see
.github/workflows/ci-lint.yml) - Formatting uses nightly toolchain
The main query evaluation logic is in core/src/evaluation/ which processes continuous queries against graph data. Key concepts:
- Continuous Queries: Unlike traditional queries, these run continuously and emit diffs when data changes
- Graph Model: Uses labeled property graphs with nodes and relationships
- Storage Backends: Supports in-memory, RocksDB, and Redis/Garnet for persistent indexing
- Cypher: Primary query language for graph traversal and pattern matching
- GraphQL: Alternative query interface with GraphQL-to-Cypher compilation
- Default: In-memory indexes for development and testing
- Production: Persistent storage via RocksDB or Redis/Garnet backends
- Index management in
core/src/in_memory_index/and separate storage crates
- The
publish-pluginsxtask command supports--signfor cosign keyless signing of published plugins - The CI workflow (
publish-plugins.yml) signs all published plugins using cosign keyless mode via GitHub Actions OIDC PluginMetadataincludesgit_commitandbuild_timestampfields populated at build time
- Redis service required for some tests (configured in CI)
- Performance benchmarks in
query-perf/crate - Shared test utilities in
shared-tests/for cross-crate testing
The lib/ crate (drasi-lib) uses a three-layer error handling pattern following idiomatic Rust conventions (matching sqlx, reqwest, tonic):
All methods on DrasiLib and the *_ops extension methods (source/query/reaction CRUD), InspectionAPI, and component_ops must return crate::error::Result<T> which uses DrasiError — a thiserror enum with variants like ComponentNotFound, InvalidState, OperationFailed, etc. This enables callers to pattern-match on error types.
Internal orchestration modules (lifecycle, component_graph, sources/manager, reactions/manager, queries/base) use anyhow::Result with .context() to build rich error chains. These modules are #[doc(hidden)] and not part of the external API.
Traits that plugin authors implement (Source, Reaction, BootstrapProvider) return anyhow::Result. Plugin authors use anyhow::context() for error chains, and the framework wraps these into DrasiError::OperationFailed or DrasiError::Internal at the public API boundary.
DrasiError::Internal(#[from] anyhow::Error) auto-converts internal anyhow errors to structured errors at the boundary via the ? operator. Use DrasiError::invalid_state(), DrasiError::operation_failed(), etc. for errors with known semantics.
- Never return
anyhow::Resultfrom a public API method onDrasiLibor the*_opsmodules - Never use
anyhow!()to construct errors in public API methods — useDrasiErrorvariants - Always use
anyhow::Resultwith.context("description")in internal modules - See
lib/src/error.rsfor the fullDrasiErrorenum and constructor helpers