From 940de789a2ab473981ff6235800b2b21e9da02b8 Mon Sep 17 00:00:00 2001 From: Tristan Swadell Date: Mon, 3 Aug 2026 08:46:27 -0700 Subject: [PATCH 1/2] Update GEMINI.md and create CLAUDE.md PiperOrigin-RevId: 958396247 --- .bazelrc | 6 ++++ .github/workflows/go-update.yml | 56 +++++++++++++++++++++++++++++ .gitignore | 4 +++ CLAUDE.md | 60 ++++++++++++++++++++++++++++++++ GEMINI.md | 17 ++++++--- MODULE.bazel | 6 ++++ internal/proto/test_schema.proto | 2 +- 7 files changed, 145 insertions(+), 6 deletions(-) create mode 100644 .bazelrc create mode 100644 .github/workflows/go-update.yml create mode 100644 .gitignore create mode 100644 CLAUDE.md diff --git a/.bazelrc b/.bazelrc new file mode 100644 index 0000000..d845a15 --- /dev/null +++ b/.bazelrc @@ -0,0 +1,6 @@ +# Enable Bzlmod for every Bazel command +common --enable_bzlmod + +build --cxxopt=-std=c++17 --host_cxxopt=-std=c++17 + +test --test_output=errors \ No newline at end of file diff --git a/.github/workflows/go-update.yml b/.github/workflows/go-update.yml new file mode 100644 index 0000000..cdd24be --- /dev/null +++ b/.github/workflows/go-update.yml @@ -0,0 +1,56 @@ +name: CEL Skills Go Update & Test + +on: + pull_request: + types: [opened, synchronize, reopened] + branches: + - main + - copybara-sync + push: + branches: + - main + +jobs: + go-update-and-test: + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - name: Checkout PR Branch + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: ${{ github.event.pull_request.head.ref }} + repository: ${{ github.event.pull_request.head.repo.full_name }} + + - name: Set up Go + uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + with: + go-version: '1.25.0' + + - name: Install Protoc & protoc-gen-go + run: | + sudo apt-get update && sudo apt-get install -y protobuf-compiler + go install google.golang.org/protobuf/cmd/protoc-gen-go@latest + + - name: Regenerate Protobuf Go Code + run: | + protoc --go_out=. --go_opt=paths=source_relative internal/proto/test_schema.proto + + - name: Run go mod tidy + run: go mod tidy + + - name: Run go test + run: go test ./... + + - name: Commit updated files if changed + run: | + if ! git diff --quiet go.mod go.sum internal/proto/test_schema.pb.go; then + git config user.name "copybara-service[bot]" + git config user.email "copybara-service[bot]@users.noreply.github.com" + git add go.mod go.sum internal/proto/test_schema.pb.go + git commit -m "chore(go): regenerate test_schema.pb.go and tidy go.mod/go.sum" + git push + else + echo "All generated files are up to date." + fi diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ca4959b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +bazel-bin/ +bazel-out/ +bazel-skills/ +bazel-testlogs/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..29249df --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,60 @@ +# Common Expression Language (CEL) Skills + +This repository provides tools and skills to author, test, and debug Common +Expression Language (CEL) expressions. + +## Project Structure & Architecture + +- `cmd/mcp`: Entry point for the Model Context Protocol (MCP) server + (`cel-expr-mcp`). +- `internal/tools`: Internal implementation for environment loading, + compilation, evaluation, and prompt generation. +- `skills/`: Agent skills directory containing guidelines and workflows: + - `cel-authoring`: Authoring, configuring, and testing expressions and + JSON environment definitions. + - `cel-debugging`: Diagnosing and resolving compilation and evaluation + errors. + +## Build and Test Commands + +### Go CLI + +- **Build MCP server**: `go build ./cmd/mcp` +- **Run tests**: `go test ./...` +- **Run MCP server**: `go run ./cmd/mcp` + +### Bazel + +- **Build all targets**: `bazel build //...` +- **Run all tests**: `bazel test //...` + +## Provided Tools + +The `cel-expr-mcp` MCP server provides the following tools for AI agents: + +- `cel_create_environment`: Defines the variables, functions, and types for a + CEL expression environment. +- `cel_generate_prompt`: Generates an authoring prompt for a CEL expression + based on the configuration and requirement. +- `cel_compile`: Compiles a CEL expression to validate syntax, correctness, + and type checking against an environment definition. +- `cel_evaluate`: Evaluates a compiled expression against provided test cases. + +### Startup Flags + +The server accepts startup flags to tailor the tool experience: + +- `-environment` (alias `-env`): Path to a JSON file or JSON string containing + the CEL environment configuration. +- `-file_descriptor_set` (alias `-file_descriptors`): Path to a binary + `FileDescriptorSet` file containing protobuf definitions referenced as types + within an environment. + +## Available Skills + +To understand how to best use these tools, refer to the skills in `skills/`: + +- `cel-authoring`: Guidelines for creating CEL environment configurations, + generating expressions, and compiling. +- `cel-debugging`: Diagnostic steps for troubleshooting syntax, type, and + evaluation errors. diff --git a/GEMINI.md b/GEMINI.md index 8fa0329..c94de1a 100644 --- a/GEMINI.md +++ b/GEMINI.md @@ -1,13 +1,12 @@ -# Google Common Expression Language (CEL) Extension +# Common Expression Language (CEL) Skills -This extension provides the Gemini CLI with tools and skills to author, test, -and debug CEL expressions. +This repository provides tools and skills to author and debug CEL expressions. ## Provided Tools -The `cel` MCP server provides the following tools: +The `cel-expr-mcp` MCP server provides the following tools: -- `cel_create_environment`: Defines the the variables, functions, types for an +- `cel_create_environment`: Defines the variables, functions, types for an expression. - `cel_generate_prompt`: Generates an authoring prompt for an expression based on the configuration and requirement. @@ -15,6 +14,14 @@ The `cel` MCP server provides the following tools: type checking against an environment definition. - `cel_evaluate`: Evaluates a compiled expression against provided test cases. +The server accepts startup flags to tailor the tool experience: + +- `-environment` (alias `-env`): Path to a JSON file or JSON string containing + the CEL environment configuration. +- `-file_descriptor_set` (alias `-file_descriptors`): Path to a binary + `FileDescriptorSet` file containing protobuf definitions referenced as types + within an environment. + ## Available Skills To understand how to best use these tools, please refer to the `cel_authoring` diff --git a/MODULE.bazel b/MODULE.bazel index a45f9c4..69a7e5c 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -21,3 +21,9 @@ go_deps.gazelle_default_attributes( ], ) go_deps.from_file(go_mod = "//:go.mod") +use_repo( + go_deps, + "com_github_google_cel_go", + "com_github_modelcontextprotocol_go_sdk", + "org_golang_google_protobuf", +) diff --git a/internal/proto/test_schema.proto b/internal/proto/test_schema.proto index 57bcd6d..f911d81 100644 --- a/internal/proto/test_schema.proto +++ b/internal/proto/test_schema.proto @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -edition = "2024"; +syntax = "proto3"; package cel.skills.internal.proto; From a51b46e1f309ca42eb68c392e5c9c83525d6a7fc Mon Sep 17 00:00:00 2001 From: "copybara-service[bot]" Date: Tue, 4 Aug 2026 19:07:37 +0000 Subject: [PATCH 2/2] chore(go): regenerate test_schema.pb.go and tidy go.mod/go.sum --- internal/proto/test_schema.pb.go | 158 +++++++++++-------------------- 1 file changed, 53 insertions(+), 105 deletions(-) diff --git a/internal/proto/test_schema.pb.go b/internal/proto/test_schema.pb.go index 1e0d08c..b612d63 100755 --- a/internal/proto/test_schema.pb.go +++ b/internal/proto/test_schema.pb.go @@ -1,15 +1,30 @@ +// Copyright 2026 Google LLC +// +// Licensed 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. + // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.36.10 -// protoc v6.33.4 +// protoc-gen-go v1.36.11 +// protoc v3.21.12 // source: internal/proto/test_schema.proto -package proto +package testpb import ( protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" + sync "sync" unsafe "unsafe" ) @@ -21,13 +36,11 @@ const ( ) type TestMessage struct { - state protoimpl.MessageState `protogen:"opaque.v1"` - xxx_hidden_SingleNestedMessage *TestMessage_NestedMessage `protobuf:"bytes,1,opt,name=single_nested_message,json=singleNestedMessage"` - xxx_hidden_SingleInt32 int32 `protobuf:"varint,2,opt,name=single_int32,json=singleInt32"` - XXX_raceDetectHookData protoimpl.RaceDetectHookData - XXX_presence [1]uint32 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + SingleNestedMessage *TestMessage_NestedMessage `protobuf:"bytes,1,opt,name=single_nested_message,json=singleNestedMessage,proto3" json:"single_nested_message,omitempty"` + SingleInt32 int32 `protobuf:"varint,2,opt,name=single_int32,json=singleInt32,proto3" json:"single_int32,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TestMessage) Reset() { @@ -55,78 +68,30 @@ func (x *TestMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } +// Deprecated: Use TestMessage.ProtoReflect.Descriptor instead. +func (*TestMessage) Descriptor() ([]byte, []int) { + return file_internal_proto_test_schema_proto_rawDescGZIP(), []int{0} +} + func (x *TestMessage) GetSingleNestedMessage() *TestMessage_NestedMessage { if x != nil { - return x.xxx_hidden_SingleNestedMessage + return x.SingleNestedMessage } return nil } func (x *TestMessage) GetSingleInt32() int32 { if x != nil { - return x.xxx_hidden_SingleInt32 + return x.SingleInt32 } return 0 } -func (x *TestMessage) SetSingleNestedMessage(v *TestMessage_NestedMessage) { - x.xxx_hidden_SingleNestedMessage = v -} - -func (x *TestMessage) SetSingleInt32(v int32) { - x.xxx_hidden_SingleInt32 = v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 1, 2) -} - -func (x *TestMessage) HasSingleNestedMessage() bool { - if x == nil { - return false - } - return x.xxx_hidden_SingleNestedMessage != nil -} - -func (x *TestMessage) HasSingleInt32() bool { - if x == nil { - return false - } - return protoimpl.X.Present(&(x.XXX_presence[0]), 1) -} - -func (x *TestMessage) ClearSingleNestedMessage() { - x.xxx_hidden_SingleNestedMessage = nil -} - -func (x *TestMessage) ClearSingleInt32() { - protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 1) - x.xxx_hidden_SingleInt32 = 0 -} - -type TestMessage_builder struct { - _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. - - SingleNestedMessage *TestMessage_NestedMessage - SingleInt32 *int32 -} - -func (b0 TestMessage_builder) Build() *TestMessage { - m0 := &TestMessage{} - b, x := &b0, m0 - _, _ = b, x - x.xxx_hidden_SingleNestedMessage = b.SingleNestedMessage - if b.SingleInt32 != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 1, 2) - x.xxx_hidden_SingleInt32 = *b.SingleInt32 - } - return m0 -} - type TestMessage_NestedMessage struct { - state protoimpl.MessageState `protogen:"opaque.v1"` - xxx_hidden_Bb int64 `protobuf:"varint,1,opt,name=bb"` - XXX_raceDetectHookData protoimpl.RaceDetectHookData - XXX_presence [1]uint32 - unknownFields protoimpl.UnknownFields - sizeCache protoimpl.SizeCache + state protoimpl.MessageState `protogen:"open.v1"` + Bb int64 `protobuf:"varint,1,opt,name=bb,proto3" json:"bb,omitempty"` + unknownFields protoimpl.UnknownFields + sizeCache protoimpl.SizeCache } func (x *TestMessage_NestedMessage) Reset() { @@ -154,47 +119,18 @@ func (x *TestMessage_NestedMessage) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } +// Deprecated: Use TestMessage_NestedMessage.ProtoReflect.Descriptor instead. +func (*TestMessage_NestedMessage) Descriptor() ([]byte, []int) { + return file_internal_proto_test_schema_proto_rawDescGZIP(), []int{0, 0} +} + func (x *TestMessage_NestedMessage) GetBb() int64 { if x != nil { - return x.xxx_hidden_Bb + return x.Bb } return 0 } -func (x *TestMessage_NestedMessage) SetBb(v int64) { - x.xxx_hidden_Bb = v - protoimpl.X.SetPresent(&(x.XXX_presence[0]), 0, 1) -} - -func (x *TestMessage_NestedMessage) HasBb() bool { - if x == nil { - return false - } - return protoimpl.X.Present(&(x.XXX_presence[0]), 0) -} - -func (x *TestMessage_NestedMessage) ClearBb() { - protoimpl.X.ClearPresent(&(x.XXX_presence[0]), 0) - x.xxx_hidden_Bb = 0 -} - -type TestMessage_NestedMessage_builder struct { - _ [0]func() // Prevents comparability and use of unkeyed literals for the builder. - - Bb *int64 -} - -func (b0 TestMessage_NestedMessage_builder) Build() *TestMessage_NestedMessage { - m0 := &TestMessage_NestedMessage{} - b, x := &b0, m0 - _, _ = b, x - if b.Bb != nil { - protoimpl.X.SetPresentNonAtomic(&(x.XXX_presence[0]), 0, 1) - x.xxx_hidden_Bb = *b.Bb - } - return m0 -} - var File_internal_proto_test_schema_proto protoreflect.FileDescriptor const file_internal_proto_test_schema_proto_rawDesc = "" + @@ -204,7 +140,19 @@ const file_internal_proto_test_schema_proto_rawDesc = "" + "\x15single_nested_message\x18\x01 \x01(\v24.cel.skills.internal.proto.TestMessage.NestedMessageR\x13singleNestedMessage\x12!\n" + "\fsingle_int32\x18\x02 \x01(\x05R\vsingleInt32\x1a\x1f\n" + "\rNestedMessage\x12\x0e\n" + - "\x02bb\x18\x01 \x01(\x03R\x02bbB5Z3google3/third_party/cel/skills/internal/proto;protob\beditionsp\xe9\a" + "\x02bb\x18\x01 \x01(\x03R\x02bbB2Z0github.com/cel-expr/skills/internal/proto;testpbb\x06proto3" + +var ( + file_internal_proto_test_schema_proto_rawDescOnce sync.Once + file_internal_proto_test_schema_proto_rawDescData []byte +) + +func file_internal_proto_test_schema_proto_rawDescGZIP() []byte { + file_internal_proto_test_schema_proto_rawDescOnce.Do(func() { + file_internal_proto_test_schema_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_internal_proto_test_schema_proto_rawDesc), len(file_internal_proto_test_schema_proto_rawDesc))) + }) + return file_internal_proto_test_schema_proto_rawDescData +} var file_internal_proto_test_schema_proto_msgTypes = make([]protoimpl.MessageInfo, 2) var file_internal_proto_test_schema_proto_goTypes = []any{