Add AGENTS.md and CLAUDE.md

patch by Ling Mao; reviewed by David Capwell, Stefan Miklosovic for CASSANDRA-21301

Co-authored-by: David Capwell <dcapwell@gmail.com>
This commit is contained in:
maoling 2026-04-12 23:20:00 +08:00 committed by Stefan Miklosovic
parent 890ba2a364
commit 41239b07b4
No known key found for this signature in database
GPG Key ID: 32F35CB2F546D93E
9 changed files with 583 additions and 0 deletions

View File

@ -88,6 +88,9 @@
<!-- legal files -->
<exclude NAME="NOTICE.txt"/>
<exclude NAME="LICENSE.txt"/>
<!-- AI agent instruction files -->
<exclude NAME="AGENTS.md"/>
<exclude NAME="CLAUDE.md"/>
<!-- misc -->
<exclude NAME="**/*.patch"/>
<exclude NAME="**/*.diff"/>

70
.build/sh/ai-build Executable file
View File

@ -0,0 +1,70 @@
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#set -o xtrace
set -o errexit
set -o pipefail
set -o nounset
bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
home="$(cd "$bin/../.." > /dev/null; pwd)" # this script lives in .build/sh
usage() {
if [[ $# -gt 0 ]]; then
echo "$*" 1>&2
fi
cat <<EOF
Usage: $(basename "$0") (options)*
Options:
--no-checkstyle - runs with all checkstyle disabled
-h|--help - this help page
EOF
exit 1
}
no_checkstyle=false
while [[ "$#" -gt 0 ]]; do
case "$1" in
--no-checkstyle)
no_checkstyle=true
shift
;;
-h|--help)
usage
shift
;;
*)
usage "Unknown argument $1"
;;
esac
done
# Switch to the project root so all commands work properly
cd "$home"
opts=(
-Dant.gen-doc.skip=true
-Drat.skip=true
)
if [ $no_checkstyle ]; then
ant -Dno-checkstyle=true "${opts[@]}" clean jar "$@" 2>&1 | "$bin"/ant-log-summary.py -
else
ant "${opts[@]}" clean jar checkstyle checkstyle-test "$@" 2>&1 | "$bin"/ant-log-summary.py -
fi

29
.build/sh/ai-ci-test Executable file
View File

@ -0,0 +1,29 @@
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#set -o xtrace
set -o errexit
set -o pipefail
set -o nounset
bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
home="$(cd "$bin/../.." > /dev/null; pwd)" # this script lives in .build/sh
# Switch to the project root so all commands work properly
cd "$home"
"$bin"/ci-test "$@" 2>&1 | "$bin"/ant-log-summary.py -

170
.build/sh/ant-log-summary.py Executable file
View File

@ -0,0 +1,170 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import argparse
import sys
def parse_args():
parser = argparse.ArgumentParser(
description="Parse Apache Cassandra ant build logs and summarize failures"
)
parser.add_argument(
"log_file",
help='Path to the ant build log file to analyze (use "-" to read from stdin)',
)
return parser.parse_args()
def find_build_failures(content):
"""
Parse the log content and extract failure information.
Returns a tuple: (is_failed, failed_target, failure_output)
"""
lines = content.split("\n")
# Check if build was successful first
if "BUILD FAILED" not in content:
return False, None, []
# Track what ant targets are running before the build failed
failed_target = None
failed_target_line = -1
for i, line in enumerate(lines):
if "BUILD FAILED" in line:
break
# Keep track of tasks so when we finally see the BUILD FAILED we know what the last task was
line_stripped = line.strip()
if line_stripped.endswith(":") and not line.startswith(" ") and "[" not in line:
failed_target = line_stripped[:-1]
failed_target_line = i
target_start_idx = 0
if failed_target and failed_target_line >= 0:
target_start_idx = failed_target_line
# Collect the output from the failed target up to BUILD FAILED
failure_output = []
for line in lines[target_start_idx:]:
stripped = line.strip()
if stripped:
failure_output.append(line.rstrip())
return True, failed_target, failure_output
def extract_compilation_errors(content):
"""Extract compilation error details specifically."""
lines = content.split("\n")
error_lines = []
for line in lines:
if "[javac]" in line and ("error:" in line or "errors" in line):
# Clean up the line to show just the error
clean_line = line.replace("[javac]", "").strip()
if clean_line:
error_lines.append(clean_line)
return error_lines
def extract_test_failures(content):
"""Extract test failure details specifically."""
lines = content.split("\n")
test_failures = []
for line in lines:
if "Test " in line and "FAILED" in line:
test_failures.append(line.strip())
return test_failures
def main():
args = parse_args()
try:
if args.log_file == "-":
content = sys.stdin.read()
else:
with open(args.log_file, "r") as f:
content = f.read()
except FileNotFoundError:
print(f"Error: Log file '{args.log_file}' not found")
sys.exit(1)
except Exception as e:
print(f"Error reading log file: {e}")
sys.exit(1)
is_failed, failed_target, failure_output = find_build_failures(content)
if not is_failed:
print("BUILD SUCCESSFUL")
sys.exit(0)
print("BUILD FAILED")
if failed_target:
print(f"Failed target: {failed_target}")
print("=" * 50)
# Special handling for compilation and test failures
if failed_target and (
"test" in failed_target.lower() or "compile" in failed_target.lower()
):
# Extract compilation errors if it's a compile-related target
compilation_errors = extract_compilation_errors("\n".join(failure_output))
if compilation_errors:
print("\nCompilation Errors:")
print("-" * 20)
for error in compilation_errors:
print(error)
# Also show the full output for context
print(f"\nFull output from failed target '{failed_target}':")
print("-" * 40)
for line in failure_output:
print(line)
sys.exit(1)
# Extract test failures if it's a test-related target
test_failures = extract_test_failures("\n".join(failure_output))
if test_failures:
print("\nTest Failures:")
print("-" * 15)
for failure in test_failures:
print(failure)
# Always show the full output for test failures - this is crucial for debugging
print(f"\nFull output from failed target '{failed_target}':")
print("-" * 40)
for line in failure_output:
print(line)
sys.exit(1)
# For all other targets or if no specific errors found, show the task output
if failure_output:
print(f"\nOutput from failed target '{failed_target}':")
print("-" * 40)
for line in failure_output:
print(line)
sys.exit(1)
if __name__ == "__main__":
main()

149
.build/sh/ci-test Executable file
View File

@ -0,0 +1,149 @@
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#set -o xtrace
set -o errexit
set -o pipefail
set -o nounset
bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
home="$(cd "$bin/../.." > /dev/null; pwd)" # this script lives in .build/sh
# Switch to the project root so all commands work properly
cd "$home"
error() {
echo "ERROR: $*" 1>&2
exit 1
}
usage() {
if [[ $# -gt 0 ]]; then
echo "$*" 1>&2
fi
cat <<EOF
Usage: $(basename "$0") [class name] (options)*
Options:
--cdc - runs with cdc enabled
--compression - run with compression enabled
--jvm-dtest-version|--dtest-version - which jvm-dtest version to use
--reuse - skip calling ant realclean
--tokens|--num-tokens - number of vnode tokens to use for jvm-dtest
-h|--help - this help page
EOF
exit 1
}
if [[ $# -eq 0 ]]; then
usage "Missing required arguments"
fi
class_name=""
task="testclasslist"
fresh_build=true
jvm_dtest_version=""
num_tokens=""
while [[ "$#" -gt 0 ]]; do
case "$1" in
--tokens|--num-tokens)
num_tokens="$2"
shift 2
;;
--cdc)
task="testclasslist-cdc"
shift
;;
--compression)
task="testclasslist-compression"
shift
;;
--reuse)
fresh_build=false
shift
;;
--jvm-dtest-version|--dtest-version)
jvm_dtest_version="$2"
shift 2
;;
-h|--help)
usage
shift
;;
*)
if [[ -z "${class_name:-}" ]]; then
class_name="$1"
shift
else
usage "Unknown argument $1"
fi
;;
esac
done
if [[ -z "${class_name:-}" ]]; then
usage "No class provided"
fi
# Is the class name valid?
if [[ "$class_name" =~ [:#$] ]]; then
error "Unexpected class name: $class_name. Illegal characters were detected: ':', '#', and '\$' are not allowed! ci-test only supports class names, and not references to methods."
fi
path="$(echo "$class_name" | tr '.' '/' ).java"
prefix="$( find test | grep "$path" | awk -F/ '{print $2}' )"
JAVA_VERSION=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}' | awk -F. '{print $1}')
if [ "$JAVA_VERSION" -ge 11 ]; then
export CASSANDRA_USE_JDK11=true
fi
if [ -n "${num_tokens:-}" ]; then
export CASSANDRA_DTEST_NUM_TOKENS="$num_tokens"
fi
opts=(
-Dant.gen-doc.skip=true
-Dno-checkstyle=true
-Dant.gen-doc.skip=true
-Drat.skip=true
)
if [[ -n "${jvm_dtest_version:-}" ]]; then
opts+=( "-Ddtest-api.version=$jvm_dtest_version" )
fi
if [[ "$fresh_build" == true ]]; then
if [[ ! "$path" =~ distributed/upgrade ]]; then
ant "${opts[@]}" realclean
ant "${opts[@]}"
ant "${opts[@]}" generate-idea-files
fi
fi
# cleanup logs so w/e is around are for this run
rm -rf build/test/logs || true
test_timeout=$(grep "name=\"test.$prefix.timeout\"" build.xml | awk -F'"' '{print $4}' || true)
if [ -z "$test_timeout" ]; then
test_timeout=$(grep 'name="test.timeout"' build.xml | awk -F'"' '{print $4}')
fi
if [[ "$fresh_build" == false ]]; then
opts+=(-Dno-build-test=true)
fi
if [[ "$prefix" == "simulator" ]]; then
ant "${opts[@]}" test-simulator-dtest -Dtest.name="$(echo "$path" | awk -F'.' '{print $1}' | awk -F'/' '{print $NF}')"
else
ant "${opts[@]}" "$task" -Dtest.timeout="$test_timeout" -Dtest.classlistfile=<(echo "$path") -Dtest.classlistprefix="$prefix"
fi

86
.build/sh/ci-test-loop Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/env bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#set -o xtrace
set -o errexit
set -o pipefail
set -o nounset
bin="$(cd "$(dirname "$0")" > /dev/null; pwd)"
home="$(cd "$bin/../.." > /dev/null; pwd)" # this script lives in .build/sh
# Switch to the project root so all commands work properly
cd "$home"
usage() {
if [[ $# -gt 0 ]]; then
echo "$*" 1>&2
fi
cat <<EOF
Usage: $(basename "$0") [class name] (option)*
Options:
EOF
exit 1
}
_main() {
local class_name=""
fresh_build=true
while [[ "$#" -gt 0 ]]; do
case "$1" in
--reuse)
fresh_build=false
shift
;;
-h|--help)
usage
shift
;;
*)
if [[ -z "${class_name:-}" ]]; then
class_name="$1"
shift
else
usage "Unknown argument $1"
fi
;;
esac
done
if [[ -z "${class_name:-}" ]]; then
usage "No class provided"
fi
path="$(echo "$class_name" | tr '.' '/' ).java"
if $fresh_build; then
if [[ ! "$path" =~ distributed/upgrade ]]; then
ant realclean && ant && ant generate-idea-files
fi
fi
counter=1
echo ">>> Running attempt $counter"
while "$bin"/ci-test "$class_name" --reuse; do
counter=$(( counter + 1 ))
echo ">>> Running attempt $counter"
done;
echo "Exited after $counter attempts"
}
_main "$@"

69
AGENTS.md Normal file
View File

@ -0,0 +1,69 @@
# Agent Instructions for Apache Cassandra
> These instructions apply to all AI-assisted contributions to `apache/cassandra`.
## Apache Cassandra
Apache Cassandra is a NoSQL distributed database. This is the official Git repository.
## Environment
- Java 11 (default), 17, 21.
- Python 3 for `cqlsh` and dtests.
- Apache Ant >= 1.10 for all builds. Do NOT attempt to use Maven, Gradle, or any other build tool. Cassandra uses Ant exclusively.
- Do NOT attempt to install dependencies, every dependency requires OSS community approval first.
## Build
```bash
.build/sh/ai-build # clean, build JAR, and run checkstyle (output is summarized)
```
Do NOT call `ant` directly — always use the `ai-*` wrapper scripts which handle log summarization and correct working directory.
## Testing
- Do NOT run the entire test suite. Run only the specific test(s) relevant to your change.
```bash
# Run a single unit test class
.build/sh/ai-ci-test org.apache.cassandra.service.StorageServiceServerTest
```
- `ai-ci-test` does NOT support method-level filtering — it runs the entire test class.
- When fixing a bug, first create a regression test that reproduces the failure, then implement the fix and verify.
- Provide test(s) coverage for all new or modified code.
## Linting and Code Checks
`.build/sh/ai-build` includes checkstyle validation. There is no need to run checkstyle separately.
## Code Style
Cassandra enforces style via Checkstyle (run via `.build/sh/ai-build`). The official style guide is at https://cassandra.apache.org/_/development/code_style.html. Always defer to it when in doubt.
General style conventions:
- 4-space indentation, no tabs.
- Match existing code style in the file you are editing.
- All new files must include the Apache License 2.0 header.
- Concise English documentation is required for complex classes and methods; trivial ones may not require them.
## Git Workflow
- Do NOT commit unless explicitly asked.
- Commit messages format. For example:
```
<One sentence description, usually Jira title or CHANGES.txt summary>
<Optional lengthier description>
Assisted-by: AGENT_NAME:MODEL_VERSION
```
## Boundaries
- 🚫 Never modify generated files in `src/gen-java/` — they are built from `src/antlr/` grammars.
- 🚫 Never modify files in `lib/` — these are managed dependencies.
- 🚫 Never commit secrets, credentials, or API keys.
- 🚫 Never run the full test suite — it takes hours. Run targeted tests only.
- 🚫 Never bypass Checkstyle violations without a suppression comment explaining why.
- ⚠️ Ask before modifying the CQL grammar (`src/antlr/Cql.g`) — changes cascade widely.

1
CLAUDE.md Normal file
View File

@ -0,0 +1 @@
AGENTS.md

View File

@ -1115,6 +1115,9 @@
<exclude name="${accord.dir}/*/build/**" />
<exclude name="${accord.dir}/**/.gradle/**" />
<exclude name=".git-blame-ignore-revs" />
<!-- AI stuff -->
<exclude name="AGENTS.md" />
<exclude name="CLAUDE.md" />
</tarfileset>
<!-- python driver -->
@ -1164,6 +1167,9 @@
<exclude name="bin/*" />
<exclude name="tools/bin/*"/>
<exclude name=".git-blame-ignore-revs" />
<!-- AI stuff -->
<exclude name="AGENTS.md" />
<exclude name="CLAUDE.md" />
</tarfileset>
<!-- Shell includes in bin/ (default mode) -->
<tarfileset dir="${dist.dir}" prefix="${final.name}">