This file provides guidance to AI coding agents when working with code in this repository. It is tool-neutral and intended to be shared across agent runtimes.
- Use
ai-memory/README.mdfor durable project context and architecture notes. - If present, use
ai-memory/PROMPT.mdandai-memory/TASKS.mdfor active feature/task context. - Keep memory-bank updates concise and aligned with implemented behavior.
ElasticGraph is a schema-driven, scalable, cloud-native, batteries-included GraphQL platform backed by Elasticsearch/OpenSearch. It's designed as a modular system with a small core and numerous built-in extensions, organized as a Ruby monorepo containing 20+ gems.
script/run_specs- Run entire test suite (uses flatware for parallelization)script/run_gem_specs [gem_name]- Run tests for a specific gem (e.g.,elasticgraph-support)bundle exec rspec [path]- Run specific test file or directorybundle exec rspec --only-failures- Run only previously failed testsbundle exec rspec --next-failure- Run failures one at a time (for iterative debugging)script/flatware_rspec [path]- Run tests in parallel (faster for large test runs, slower for small subsets)
Important: Integration/acceptance tests require a running datastore:
bundle exec rake elasticsearch:test:boot
# or
bundle exec rake opensearch:test:bootscript/quick_build- Run abridged CI build (recommended before opening PRs)script/lint- Run linter (Standard Ruby)script/lint --fix- Auto-fix linting issuesscript/type_check- Run Steep type checkerscript/spellcheck- Check spelling (uses codespell)script/spellcheck -w- Auto-fix spelling issues
bundle exec rake schema_artifacts:dump- Regenerate schema artifacts after schema definition changes- Schema definition files:
config/schema.rbandconfig/schema/*.rb
bundle exec rake boot_locally- Boot ElasticGraph locally (from a new project)bundle exec rake site:serve- Serve project website locally at http://localhost:4000/elasticgraph/bundle exec rake site:preview_docs:[gem_name]- Preview API docs for a specific gem (faster feedback loop)
- API documentation uses YARD
- 100% documentation coverage is required for all public methods and classes.
- Website source:
config/site/ - Example queries:
config/site/examples/*/queries/ - When writing links in documentation, use permalinks (links to a specific commit/version)
- Prefer relative links to ElasticGraph documentation over external links to ruby-doc.org
All gems follow the pattern: elasticgraph-[name]/ containing:
lib/elastic_graph/[name]/- Source codespec/- RSpec test suiteGemfile- Symlinked from rootGemfile[name].gemspec- Gem specification
Core Libraries (8 gems): Always included in production deployments
elasticgraph-admin: Datastore administrationelasticgraph-datastore_core: Core datastore logicelasticgraph-graphql: GraphQL query engineelasticgraph-indexer: Data indexingelasticgraph-schema_artifacts: Schema artifact accesselasticgraph-support: Shared utilitieselasticgraph-rack: Rack serverelasticgraph-graphiql: GraphiQL IDE
Local Development Libraries (3 gems):
elasticgraph: Project bootstrappingelasticgraph-local: Local development supportelasticgraph-schema_definition: Schema definition DSL
Datastore Adapters (2 gems):
elasticgraph-elasticsearch: Elasticsearch client wrapperelasticgraph-opensearch: OpenSearch client wrapper
Extensions (5 gems): Optional functionality
elasticgraph-apollo: Apollo Federation supportelasticgraph-health_check: Health checkselasticgraph-query_interceptor: Query interceptionelasticgraph-query_registry: Source-controlled query registryelasticgraph-warehouse: Data warehouse ingestion
AWS Lambda Integration (6 gems):
elasticgraph-admin_lambda,elasticgraph-graphql_lambda,elasticgraph-indexer_lambda,elasticgraph-indexer_autoscaler_lambda,elasticgraph-warehouse_lambda,elasticgraph-lambda_support
Query Engine (elasticgraph-graphql):
ElasticGraph::GraphQL::DatastoreQuery: Intermediate query representationElasticGraph::GraphQL::Aggregation: Aggregation query handlingfilter_node_interpreter.rb: Filter operator mapping
Schema Definition (elasticgraph-schema_definition):
SchemaElementNames: Customizable GraphQL schema element namesconfig/schema.rb: Main schema entry pointconfig/schema/*.rb: Schema definition files (e.g.,teams.rb,widgets.rb)
Test Infrastructure:
spec_support/: Shared test utilities- Test coverage maintained at 100%
- Uses FactoryBot for test data
When adding filtering predicates or aggregation functions:
- Design Phase: Create GitHub Discussion, research datastore capabilities, design GraphQL API following ElasticGraph's guiding principles
- Schema Definition: Update
SchemaElementNames, built-in types, and test coverage - Query Translation: Implement GraphQL → datastore query translation with unit, integration, and acceptance tests
- Documentation: Add user-facing docs with working examples to
config/site/
Three layers of testing:
- Unit tests: Build and inspect
DatastoreQuerywithout execution - Integration tests: Build and execute
DatastoreQuerydirectly (skips GraphQL layer) - Acceptance tests: End-to-end GraphQL queries with real datastore
The repo uses a symlinked Gemfile approach:
- Root
Gemfiledefines development, site, and test dependencies - Each gem has a symlinked
Gemfilethat includes its.gemspecand recursively resolves ElasticGraph gem dependencies from the repo
Custom gems can be added via Gemfile-custom (see Gemfile-custom.example), then run source script/enable_custom_gemfile.
- Linter: Standard Ruby (see
.standard.yml) - Type Checker: Steep (
Steepfile) - Test Framework: RSpec
- Coverage: 100% required (enforced by SimpleCov)
- Ruby Version: 3.4.x or 4.0.x
- Standard Comment Header: Required on most Ruby files (copyright notice)
- Prefer
filter_mapover.select { ... }.map { ... }chains. For example, instead of:Use:items.select { |item| item.value }.map { |item| item.value }
items.filter_map { |item| item.value }
- Prefer
::Data.defineover::Struct.newfor immutable data classes. UseStructonly when mutability is required. - Don't rely on exceptions for control flow (exceptions are slow). Handle edge cases explicitly instead (e.g., check for
nilbefore calling a method that would raiseArgumentError). - For constants accessed from multiple EG gems, define them in
elasticgraph-support/lib/elastic_graph/constants.rb. - Always put a blank space after
#in comments. This applies to all comments, including RBS type annotation comments (e.g.,# : Stringnot#: String). - Avoid defensive code for impossible cases. Don't add checks, tests, or handling for scenarios that should never occur due to the design of the system. If something can only happen due to a bug in the implementation, it's better to fail fast than to silently handle it.
- Drop unnecessary namespace prefixes. When code is already inside
module ElasticGraph, useIndexerinstead of::ElasticGraph::Indexer, andErrors::ConfigErrorinstead of::ElasticGraph::Errors::ConfigError. Use fully qualified names only when necessary to avoid ambiguity. - Prefer using
prepend+superrather thanalias_methodwhen needing to hook in and override a method.
- When defining RBS signatures for extension modules, prefer declaring the concrete type a module extends rather than defining custom interfaces. For example, use
module IndexExtension : ::ElasticGraph::SchemaDefinition::Indexing::Indexinstead of creating a custom_IndexExtensionInterface.
- Avoid duplicate tests. If two tests will always pass/fail together, keep only one.
- Use
expect_to_return_non_nil_values_from_all_attributesto test wrapper classes (likeWarehouseLambda,GraphQL,Indexer, etc.). This automatically exercises every zero-argument method and verifies all dependencies are built successfully. - Use the
:capture_logsRSpec tag instead of logger test doubles for verifying log output. Access logs withlogged_jsons_of_type(message_type). - Use
build_*helper methods fromspec/support/builds_*.rbto construct test objects. These helpers provide sensible defaults while allowing selective overrides for testing specific scenarios.
After schema definition changes, always run:
bundle exec rake schema_artifacts:dumpThis updates:
- Generated GraphQL schema
- Datastore mappings
- Runtime metadata
- Datastore scripts (including auto-updating
INDEX_DATA_UPDATE_SCRIPT_IDconstant)
Test datastore ports configured in config/settings/test.yaml.template. The Rakefile automatically clears ClusterConfigurationManager state files when booting test datastores.
Tests run in parallel via flatware when beneficial. The build scripts automatically determine when to use it based on test suite size.
- Datastore in bad state: Kill and restart
rake [elasticsearch|opensearch]:test:boot - Schema artifact issues: Run
rake schema_artifacts:dumptwice if updatingupdate_index_data.painlessscript - Memory resets between datastore boots: The
boot_prep_for_teststask clearsClusterConfigurationManagerstate files
Rakefile: Main task definitions, schema artifact automation, test prep hooksscript/: Build and development scriptsconfig/schema.rb: Schema entry pointconfig/settings/: Environment configurationsspec_support/: Shared test infrastructureCODEBASE_OVERVIEW.md: Detailed architecture and dependency diagramsCONTRIBUTING.md: Contribution guidelines and detailed feature development walkthroughMAINTAINERS_RUNBOOK.md: Maintenance tasks (releases, etc.)ai-memory/: AI agent memory bank (if using AI assistants)