Files
scylladb/.github/instructions/cpp.instructions.md
Piotr Szymaniak 378bcd69e3 tree: add AGENTS.md router and improve AI instruction files
Add AGENTS.md as a minimal router that directs AI agents to the
relevant instruction files based on what they are editing.

Improve the instruction files:

- cpp.instructions.md: clarify seastarx.hh scope (headers, not
  "many files"), explain std::atomic restriction (single-shard
  model, not "blocking"), scope macros prohibition to new ad-hoc
  only, add coroutine exception propagation pattern, add invariant
  checking section preferring throwing_assert() over SCYLLA_ASSERT
  (issue #7871)
- python.instructions.md: demote PEP 8 to fallback after local
  style, clarify that only wildcard imports are prohibited
- copilot-instructions.md: show configure.py defaults to dev mode,
  add frozen toolchain section, clarify --no-gather-metrics applies
  to test.py, fix Python test paths to use .py extension, add
  license header guidance for new files

Closes scylladb/scylladb#29023
2026-04-19 21:59:52 +03:00

5.6 KiB

applyTo
applyTo
**/*.{cc,hh}

C++ Guidelines

Important: Always match the style and conventions of existing code in the file and directory.

Memory Management

  • Prefer stack allocation whenever possible
  • Use std::unique_ptr by default for dynamic allocations
  • new/delete are forbidden (use RAII)
  • Use seastar::lw_shared_ptr or seastar::shared_ptr for shared ownership within same shard
  • Use seastar::foreign_ptr for cross-shard sharing
  • Avoid std::shared_ptr except when interfacing with external C++ APIs
  • Avoid raw pointers except for non-owning references or C API interop

Seastar Asynchronous Programming

  • Use seastar::future<T> for all async operations
  • Prefer coroutines (co_await, co_return) over .then() chains for readability
  • Coroutines are preferred over seastar::do_with() for managing temporary state
  • In hot paths where futures are ready, continuations may be more efficient than coroutines
  • Chain futures with .then(), don't block with .get() (unless in seastar::thread context)
  • All I/O must be asynchronous (no blocking calls)
  • Use seastar::gate for shutdown coordination
  • Use seastar::semaphore for resource limiting (not std::mutex)
  • Break long loops with maybe_yield() to avoid reactor stalls
  • Most Scylla code runs on a single shard where atomics are unnecessary
  • Use Seastar message passing for cross-shard communication

Coroutines

seastar::future<T> func() {
    auto result = co_await async_operation();
    co_return result;
}

Error Handling

  • Throw exceptions for errors (futures propagate them automatically)
  • In coroutines, use co_await coroutine::return_exception_ptr() or co_return coroutine::exception() to avoid the overhead of throwing
  • In data path: avoid exceptions, use std::expected (or boost::outcome) instead
  • Use standard exceptions (std::runtime_error, std::invalid_argument)
  • Database-specific: throw appropriate schema/query exceptions

Invariant Checking

  • Prefer throwing_assert() (utils/assert.hh), it logs and throws instead of aborting
  • Use SCYLLA_ASSERT where critical to system stability where no clean shutdown is possible, it aborts
  • Use on_internal_error() for should-never-happen conditions that should be logged with backtrace

Performance

  • Pass large objects by const& or && (move semantics)
  • Use std::string_view for non-owning string references
  • Avoid copies: prefer move semantics
  • Use utils::chunked_vector instead of std::vector for large allocations (>128KB)
  • Minimize dynamic allocations in hot paths

Database-Specific Types

  • Use schema_ptr for schema references
  • Use mutation and mutation_partition for data modifications
  • Use partition_key and clustering_key for keys
  • Use api::timestamp_type for database timestamps
  • Use gc_clock for garbage collection timing

Style

  • C++23 standard (prefer modern features, especially coroutines)
  • Use auto when type is obvious from RHS
  • Avoid auto when it obscures the type
  • Use range-based for loops: for (const auto& item : container)
  • Use standard algorithms when they clearly simplify code (e.g., replacing 10-line loops)
  • Avoid chaining multiple algorithms if a straightforward loop is clearer
  • Mark functions and variables const whenever possible
  • Use scoped enums: enum class (not unscoped enum)

Headers

  • Use #pragma once
  • Include order: own header, C++ std, Seastar, Boost, project headers
  • Forward declare when possible
  • Never using namespace in headers. Exception: most headers include seastarx.hh, which provides using namespace seastar project-wide.

Documentation

  • Public APIs require clear documentation
  • Implementation details should be self-evident from code
  • Use /// or Doxygen /** */ for public documentation, // for implementation notes - follow the existing style

Naming

  • snake_case for most identifiers (classes, functions, variables, namespaces)
  • Template parameters: CamelCase (e.g., template<typename ValueType>)
  • Member variables: prefix with _ (e.g., int _count;)
  • Structs (value-only): no _ prefix on members
  • Constants and constexpr: snake_case (e.g., static constexpr int max_size = 100;)
  • Files: .hh for headers, .cc for source

Formatting

  • 4 spaces indentation, never tabs
  • Opening braces on same line as control structure (except namespaces)
  • Space after keywords: if (, while (, return
  • Whitespace around operators matches precedence: *a + *b not * a+* b
  • Line length: keep reasonable (<160 chars), use continuation lines with double indent if needed
  • Brace all nested scopes, even single statements
  • Minimal patches: only format code you modify, never reformat entire files

Logging

  • Use structured logging with appropriate levels: DEBUG, INFO, WARN, ERROR
  • Include context in log messages (e.g., request IDs)
  • Never log sensitive data (credentials, PII)

Forbidden

  • malloc/free
  • printf family (use logging or fmt)
  • Raw pointers for ownership
  • Blocking operations: std::sleep, std::read, std::mutex (use Seastar equivalents)
  • New ad-hoc macros (prefer inline, constexpr, or templates; established project macros like SCYLLA_ASSERT are fine)

Testing

When modifying existing code, follow TDD: create/update test first, then implement.

  • Examine existing tests for style and structure
  • Use Boost.Test framework
  • Use SEASTAR_THREAD_TEST_CASE for Seastar asynchronous tests
  • Aim for high code coverage, especially for new features and bug fixes
  • Maintain bisectability: all tests must pass in every commit. Mark failing tests with BOOST_FAIL() or similar, then fix in subsequent commit