[navi] add discovery init mesh config v1 (#768)

diff --git a/go.mod b/go.mod
index 0778740..79b2cd0 100644
--- a/go.mod
+++ b/go.mod
@@ -30,6 +30,7 @@
 	github.com/docker/docker-credential-helpers v0.9.3
 	github.com/docker/go-connections v0.5.0
 	github.com/fatih/color v1.18.0
+	github.com/fsnotify/fsnotify v1.9.0
 	github.com/go-git/go-billy/v5 v5.6.2
 	github.com/go-git/go-git/v5 v5.13.1
 	github.com/golang/protobuf v1.5.4
@@ -43,6 +44,7 @@
 	github.com/spf13/cobra v1.9.1
 	github.com/spf13/pflag v1.0.6
 	github.com/tmc/langchaingo v0.1.13
+	go.uber.org/atomic v1.11.0
 	golang.org/x/crypto v0.40.0
 	golang.org/x/exp v0.0.0-20250506013437-ce4c2cf36ca6
 	golang.org/x/net v0.42.0
@@ -61,7 +63,6 @@
 )
 
 require (
-	cel.dev/expr v0.24.0 // indirect
 	dario.cat/mergo v1.0.2 // indirect
 	github.com/Azure/azure-sdk-for-go v68.0.0+incompatible // indirect
 	github.com/Azure/go-ansiterm v0.0.0-20250102033503-faa5f7b0171c // indirect
@@ -82,7 +83,6 @@
 	github.com/ProtonMail/go-crypto v1.1.3 // indirect
 	github.com/VividCortex/ewma v1.2.0 // indirect
 	github.com/agext/levenshtein v1.2.3 // indirect
-	github.com/antlr4-go/antlr/v4 v4.13.1 // indirect
 	github.com/apex/log v1.9.0 // indirect
 	github.com/aws/aws-sdk-go-v2 v1.30.3 // indirect
 	github.com/aws/aws-sdk-go-v2/config v1.27.27 // indirect
@@ -100,21 +100,17 @@
 	github.com/aws/aws-sdk-go-v2/service/sts v1.30.3 // indirect
 	github.com/aws/smithy-go v1.20.3 // indirect
 	github.com/awslabs/amazon-ecr-credential-helper/ecr-login v0.0.0-20230522190001-adf1bafd791a // indirect
-	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/blang/semver/v4 v4.0.0 // indirect
 	github.com/buildpacks/imgutil v0.0.0-20230626185301-726f02e4225c // indirect
 	github.com/buildpacks/lifecycle v0.17.0 // indirect
 	github.com/cespare/xxhash v1.1.0 // indirect
-	github.com/cespare/xxhash/v2 v2.3.0 // indirect
 	github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
 	github.com/cloudflare/circl v1.3.7 // indirect
-	github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 // indirect
 	github.com/containerd/containerd v1.7.27 // indirect
 	github.com/containerd/stargz-snapshotter/estargz v0.16.3 // indirect
 	github.com/containerd/typeurl/v2 v2.2.3 // indirect
 	github.com/cyphar/filepath-securejoin v0.4.1 // indirect
 	github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
-	github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 // indirect
 	github.com/dgraph-io/ristretto v0.0.1 // indirect
 	github.com/dimchansky/utfbom v1.1.1 // indirect
 	github.com/dlclark/regexp2 v1.10.0 // indirect
@@ -123,33 +119,25 @@
 	github.com/dustin/go-humanize v1.0.1 // indirect
 	github.com/emicklei/go-restful/v3 v3.12.2 // indirect
 	github.com/emirpasic/gods v1.18.1 // indirect
-	github.com/envoyproxy/go-control-plane/contrib v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
-	github.com/envoyproxy/go-control-plane/envoy v1.32.5-0.20250627145903-197b96a9c7f8 // indirect
-	github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect
-	github.com/fsnotify/fsnotify v1.9.0 // indirect
 	github.com/fxamacker/cbor/v2 v2.8.0 // indirect
 	github.com/gdamore/encoding v1.0.0 // indirect
 	github.com/gdamore/tcell/v2 v2.6.0 // indirect
 	github.com/go-errors/errors v1.5.1 // indirect
 	github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
 	github.com/go-logr/logr v1.4.3 // indirect
-	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-openapi/jsonpointer v0.21.1 // indirect
 	github.com/go-openapi/jsonreference v0.21.0 // indirect
 	github.com/go-openapi/swag v0.23.1 // indirect
 	github.com/gobwas/glob v0.2.3 // indirect
-	github.com/goccy/go-json v0.10.5 // indirect
 	github.com/gogo/protobuf v1.3.2 // indirect
 	github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
 	github.com/google/btree v1.1.3 // indirect
-	github.com/google/cel-go v0.25.0 // indirect
 	github.com/google/gnostic-models v0.6.9 // indirect
 	github.com/google/go-cmp v0.7.0 // indirect
 	github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
 	github.com/google/uuid v1.6.0 // indirect
 	github.com/goph/emperror v0.17.2 // indirect
-	github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 // indirect
 	github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
 	github.com/hashicorp/errwrap v1.1.0 // indirect
 	github.com/hashicorp/hcl v1.0.0 // indirect
@@ -163,12 +151,6 @@
 	github.com/kevinburke/ssh_config v1.2.0 // indirect
 	github.com/klauspost/compress v1.18.0 // indirect
 	github.com/klauspost/pgzip v1.2.6 // indirect
-	github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
-	github.com/lestrrat-go/blackmagic v1.0.3 // indirect
-	github.com/lestrrat-go/httpcc v1.0.1 // indirect
-	github.com/lestrrat-go/iter v1.0.2 // indirect
-	github.com/lestrrat-go/jwx v1.2.31 // indirect
-	github.com/lestrrat-go/option v1.0.1 // indirect
 	github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
 	github.com/magiconair/properties v1.8.7 // indirect
 	github.com/mailru/easyjson v0.9.0 // indirect
@@ -184,7 +166,6 @@
 	github.com/moby/buildkit v0.21.1 // indirect
 	github.com/moby/docker-image-spec v1.3.1 // indirect
 	github.com/moby/patternmatcher v0.6.0 // indirect
-	github.com/moby/spdystream v0.5.0 // indirect
 	github.com/moby/sys/capability v0.4.0 // indirect
 	github.com/moby/sys/mountinfo v0.7.2 // indirect
 	github.com/moby/sys/sequential v0.6.0 // indirect
@@ -195,8 +176,9 @@
 	github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
 	github.com/morikuni/aec v1.0.0 // indirect
 	github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
-	github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
 	github.com/nikolalohinski/gonja v1.5.3 // indirect
+	github.com/onsi/ginkgo/v2 v2.23.4 // indirect
+	github.com/onsi/gomega v1.37.0 // indirect
 	github.com/opencontainers/go-digest v1.0.0 // indirect
 	github.com/opencontainers/image-spec v1.1.1 // indirect
 	github.com/opencontainers/runc v1.1.7 // indirect
@@ -208,7 +190,6 @@
 	github.com/pjbgf/sha1cd v0.3.0 // indirect
 	github.com/pkoukk/tiktoken-go v0.1.6 // indirect
 	github.com/planetscale/vtprotobuf v0.6.1-0.20240409071808-615f978279ca // indirect
-	github.com/prometheus/client_golang v1.22.0 // indirect
 	github.com/prometheus/client_model v0.6.2 // indirect
 	github.com/prometheus/common v0.65.0 // indirect
 	github.com/prometheus/procfs v0.16.1 // indirect
@@ -223,7 +204,6 @@
 	github.com/spf13/afero v1.14.0 // indirect
 	github.com/spf13/cast v1.8.0 // indirect
 	github.com/spf13/jwalterweatherman v1.1.0 // indirect
-	github.com/stoewer/go-strcase v1.3.0 // indirect
 	github.com/subosito/gotenv v1.6.0 // indirect
 	github.com/tonistiigi/go-csvvalue v0.0.0-20240710180619-ddb21b71c0b4 // indirect
 	github.com/ulikunitz/xz v0.5.12 // indirect
@@ -235,18 +215,7 @@
 	github.com/xeipuuv/gojsonschema v1.2.0 // indirect
 	github.com/xlab/treeprint v1.2.0 // indirect
 	github.com/yargevad/filepathx v1.0.0 // indirect
-	go.opentelemetry.io/auto/sdk v1.1.0 // indirect
-	go.opentelemetry.io/otel v1.36.0 // indirect
-	go.opentelemetry.io/otel/exporters/prometheus v0.57.0 // indirect
-	go.opentelemetry.io/otel/metric v1.36.0 // indirect
-	go.opentelemetry.io/otel/sdk v1.36.0 // indirect
-	go.opentelemetry.io/otel/sdk/metric v1.36.0 // indirect
-	go.opentelemetry.io/otel/trace v1.36.0 // indirect
-	go.opentelemetry.io/proto/otlp v1.7.0 // indirect
 	go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 // indirect
-	go.uber.org/atomic v1.11.0 // indirect
-	go.uber.org/multierr v1.11.0 // indirect
-	go.uber.org/zap v1.27.0 // indirect
 	go.yaml.in/yaml/v2 v2.4.2 // indirect
 	go.yaml.in/yaml/v3 v3.0.3 // indirect
 	golang.org/x/mod v0.25.0 // indirect
@@ -261,21 +230,15 @@
 	gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
 	gopkg.in/inf.v0 v0.9.1 // indirect
 	gopkg.in/ini.v1 v1.67.0 // indirect
-	gopkg.in/natefinch/lumberjack.v2 v2.2.1 // indirect
 	gopkg.in/warnings.v0 v0.1.2 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
-	istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe // indirect
-	k8s.io/apiserver v0.33.2 // indirect
 	k8s.io/cli-runtime v0.33.2 // indirect
 	k8s.io/klog/v2 v2.130.1 // indirect
 	k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff // indirect
 	k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979 // indirect
-	sigs.k8s.io/gateway-api v1.3.0 // indirect
-	sigs.k8s.io/gateway-api-inference-extension v0.5.0 // indirect
 	sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
 	sigs.k8s.io/kustomize/api v0.19.0 // indirect
 	sigs.k8s.io/kustomize/kyaml v0.19.0 // indirect
-	sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c // indirect
 	sigs.k8s.io/randfill v1.0.0 // indirect
 	sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
 )
diff --git a/go.sum b/go.sum
index 82d0239..70985de 100644
--- a/go.sum
+++ b/go.sum
@@ -1,5 +1,3 @@
-cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
-cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
 cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
 cloud.google.com/go v0.114.0 h1:OIPFAdfrFDFO2ve2U7r/H5SwSbBzEdrBdE7xkgwc+kY=
 cloud.google.com/go v0.114.0/go.mod h1:ZV9La5YYxctro1HTPug5lXH/GefROyW8PPD4T8n9J8E=
@@ -89,8 +87,6 @@
 github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
-github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYWrPrQ=
-github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw=
 github.com/apex/log v1.9.0 h1:FHtw/xuaM8AgmvDDTI9fiwoAL25Sq2cxojnZICUU8l0=
 github.com/apex/log v1.9.0/go.mod h1:m82fZlWIuiWzWP04XCTXmnX0xRkYYbCdYn8jbJeLBEA=
 github.com/apex/logs v1.0.0/go.mod h1:XzxuLZ5myVHDy9SAmYpamKKRNApGj54PfYLcFrXqDwo=
@@ -164,8 +160,6 @@
 github.com/buildpacks/pack v0.30.0/go.mod h1:ZtkyUJKcTdWgEDFi0KOmtHQAOkeQeOeJ2wre1+0ipnA=
 github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
 github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
-github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
 github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
 github.com/certifi/gocertifi v0.0.0-20190105021004-abcd57078448/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4=
 github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
@@ -188,8 +182,6 @@
 github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
 github.com/cloudflare/circl v1.3.7 h1:qlCDlTPz2n9fu58M0Nh1J/JzcFpfgkFHHX3O35r5vcU=
 github.com/cloudflare/circl v1.3.7/go.mod h1:sRTcRWXGLrKw6yIGJ+l7amYJFfAXbZG0kBSc8r4zxgA=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443 h1:aQ3y1lwWyqYPiWZThqv1aFbZMiM9vblcSArJRf2Irls=
-github.com/cncf/xds/go v0.0.0-20250501225837-2ac532fd4443/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
 github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII=
 github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0=
 github.com/containerd/continuity v0.4.5 h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
@@ -213,8 +205,6 @@
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0 h1:NMZiJj8QnKe1LgsbDayM4UoHwbvwDRwnI3hwNaAHRnc=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.0/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
 github.com/dgraph-io/ristretto v0.0.1 h1:cJwdnj42uV8Jg4+KLrYovLiCgIfz9wtWm6E6KA+1tLs=
 github.com/dgraph-io/ristretto v0.0.1/go.mod h1:T40EBc7CJke8TkpiYfGGKAeFjSaxuFXhuXRyumBd6RE=
 github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
@@ -249,13 +239,7 @@
 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane/contrib v1.32.5-0.20250627145903-197b96a9c7f8 h1:KXgXPtBofHkRHr+8dO058dGZnLHapW7m0yJEgSYdAFA=
-github.com/envoyproxy/go-control-plane/contrib v1.32.5-0.20250627145903-197b96a9c7f8/go.mod h1:Nx/YcyEeIcgjT13QwKHdcPmS060urxZ835MeO8cLOrg=
-github.com/envoyproxy/go-control-plane/envoy v1.32.5-0.20250627145903-197b96a9c7f8 h1:/F9jLyfDeNr4iZxyibtKlZxCDqCFEhoYiLdc9VOZT2E=
-github.com/envoyproxy/go-control-plane/envoy v1.32.5-0.20250627145903-197b96a9c7f8/go.mod h1:09qwbGVuSWWAyN5t/b3iyVfz5+z8QWGrzkoqm/8SbEs=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.2.1 h1:DEo3O99U8j4hBFwbJfrz9VtgcDfUKS7KJ7spH3d86P8=
-github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
 github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
@@ -292,7 +276,6 @@
 github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M=
 github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
-github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
 github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
 github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
 github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
@@ -305,13 +288,10 @@
 github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0=
 github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI=
 github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
-github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
 github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
 github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
 github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
 github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
-github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
-github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
 github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
@@ -339,8 +319,6 @@
 github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
 github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
 github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
-github.com/google/cel-go v0.25.0 h1:jsFw9Fhn+3y2kBbltZR4VEz5xKkcIFRPDnuEzAGv5GY=
-github.com/google/cel-go v0.25.0/go.mod h1:hjEb6r5SuOSlhCHmFoLzu8HGCERvIsDAbxDAyNU/MmI=
 github.com/google/generative-ai-go v0.15.1 h1:n8aQUpvhPOlGVuM2DRkJ2jvx04zpp42B778AROJa+pQ=
 github.com/google/generative-ai-go v0.15.1/go.mod h1:AAucpWZjXsDKhQYWvCYuP6d0yB1kX998pJlOW1rAesw=
 github.com/google/gnostic-models v0.6.9 h1:MU/8wDLif2qCXZmzncUQ/BOfxWfthHi63KqpoNbWqVw=
@@ -360,8 +338,8 @@
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
 github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
 github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a h1:rDA3FfmxwXR+BVKKdz55WwMJ1pD2hJQNW31d+l3mPk4=
-github.com/google/pprof v0.0.0-20250501235452-c0086092b71a/go.mod h1:5hDyRhoBCxViHszMt12TnOpEI4VVi+U8Gm9iphldiMA=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
+github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
 github.com/google/s2a-go v0.1.9 h1:LGD7gtMgezd8a/Xak7mEWL0PjoTQFvpRudN895yqKW0=
 github.com/google/s2a-go v0.1.9/go.mod h1:YA0Ei2ZQL3acow2O62kdp9UlnvMmU7kA6Eutn0dXayM=
 github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
@@ -380,13 +358,8 @@
 github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
 github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
 github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674 h1:JeSE6pjso5THxAzdVpqr6/geYxZytqFMBCOtn/ujyeo=
-github.com/gorilla/websocket v1.5.4-0.20250319132907-e064f32e3674/go.mod h1:r4w70xmWCQKmi1ONH4KIaBptdivuRPyosB9RmPlGEwA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
 github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
-github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
 github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
 github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
 github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
@@ -437,23 +410,8 @@
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
-github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
 github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
-github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
-github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
-github.com/lestrrat-go/blackmagic v1.0.3 h1:94HXkVLxkZO9vJI/w2u1T0DAoprShFd13xtnSINtDWs=
-github.com/lestrrat-go/blackmagic v1.0.3/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
-github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
-github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
-github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
-github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx v1.2.31 h1:/OM9oNl/fzyldpv5HKZ9m7bTywa7COUfg8gujd9nJ54=
-github.com/lestrrat-go/jwx v1.2.31/go.mod h1:eQJKoRwWcLg4PfD5CFA5gIZGxhPgoPYq9pZISdxLf0c=
-github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
-github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
-github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
 github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
 github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
@@ -494,8 +452,6 @@
 github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo=
 github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
 github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
-github.com/moby/spdystream v0.5.0 h1:7r0J1Si3QO/kjRitvSLVVFUjxMEb/YLj6S9FF62JBCU=
-github.com/moby/spdystream v0.5.0/go.mod h1:xBAYlnt/ay+11ShkdFKNAG7LsyK/tmNBVvVOwrfMgdI=
 github.com/moby/sys/capability v0.4.0 h1:4D4mI6KlNtWMCM1Z/K0i7RV1FkX+DBDHKVJpCndZoHk=
 github.com/moby/sys/capability v0.4.0/go.mod h1:4g9IK291rVkms3LKCDOoYlnV8xKwoDTpIrNEE35Wq0I=
 github.com/moby/sys/mountinfo v0.7.2 h1:1shs6aH5s4o5H2zQLn796ADW1wMrIwHsyJ2v9KouLrg=
@@ -519,13 +475,10 @@
 github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
 github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
-github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
 github.com/nikolalohinski/gonja v1.5.3 h1:GsA+EEaZDZPGJ8JtpeGN78jidhOlxeJROpqMT9fTj9c=
 github.com/nikolalohinski/gonja v1.5.3/go.mod h1:RmjwxNiXAEqcq1HeK5SSMmqFJvKOfTfXhkJv6YBtPa4=
 github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
 github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
 github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
 github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
 github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -623,8 +576,6 @@
 github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
 github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
 github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
-github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
-github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -638,7 +589,6 @@
 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
 github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
 github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
 github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
@@ -694,16 +644,10 @@
 go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0 h1:rgMkmiGfix9vFJDcDi1PK8WEQP4FLQwLDfhp5ZLpFeE=
 go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.59.0/go.mod h1:ijPqXp5P6IRRByFVVg9DY8P5HkxkHE5ARIa+86aXPf4=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU=
-go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0 h1:CV7UdSGJt/Ao6Gp4CXckLxVRRsRgDHoI8XjbL3PDl8s=
+go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.59.0/go.mod h1:FRmFuRJfag1IZ2dPkHnEoSFVgTVPUd2qf5Vi69hLb8I=
 go.opentelemetry.io/otel v1.36.0 h1:UumtzIklRBY6cI/lllNZlALOF5nNIzJVb16APdvgTXg=
 go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
-go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
-go.opentelemetry.io/otel/exporters/prometheus v0.57.0 h1:AHh/lAP1BHrY5gBwk8ncc25FXWm/gmmY3BX258z5nuk=
-go.opentelemetry.io/otel/exporters/prometheus v0.57.0/go.mod h1:QpFWz1QxqevfjwzYdbMb4Y1NnlJvqSGwyuU0B4iuc9c=
 go.opentelemetry.io/otel/metric v1.36.0 h1:MoWPKVhQvJ+eeXWHFBOPoBOi20jh6Iq2CcCREuTYufE=
 go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
 go.opentelemetry.io/otel/sdk v1.36.0 h1:b6SYIuLRs88ztox4EyrvRti80uXIFy+Sqzoh9kFULbs=
@@ -712,8 +656,6 @@
 go.opentelemetry.io/otel/sdk/metric v1.36.0/go.mod h1:qTNOhFDfKRwX0yXOqJYegL5WRaW376QbB7P4Pb0qva4=
 go.opentelemetry.io/otel/trace v1.36.0 h1:ahxWNuqZjpdiFAyrIoQ4GIiAIhxAunQR6MUoKrsNd4w=
 go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
-go.opentelemetry.io/proto/otlp v1.7.0 h1:jX1VolD6nHuFzOYso2E73H85i92Mv8JQYk0K9vz09os=
-go.opentelemetry.io/proto/otlp v1.7.0/go.mod h1:fSKjH6YJ7HDlwzltzyMj036AJ3ejJLCgCSHGj4efDDo=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254 h1:Ss6D3hLXTM0KobyBYEAygXzFfGcjnmfEJOBgSbemCtg=
 go.starlark.net v0.0.0-20230302034142-4b1e35fe2254/go.mod h1:jxU+3+j+71eXOW14274+SmmuW82qJzl6iZSeqEtTGds=
 go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
@@ -722,10 +664,6 @@
 go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
 go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
 go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
-go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
-go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
-go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
-go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
 go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
 go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
 go.yaml.in/yaml/v3 v3.0.3 h1:bXOww4E/J3f66rav3pX3m8w6jDE4knZjGOw8b5Y6iNE=
@@ -881,8 +819,6 @@
 gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
 gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
 gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc=
-gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc=
 gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
 gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
 gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -904,24 +840,16 @@
 honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
 istio.io/api v1.26.3 h1:/TiA7bJi24yBQSgpLy5vHhFkobf4DWS1L+CuUxNk4os=
 istio.io/api v1.26.3/go.mod h1:DTVGH6CLXj5W8FF9JUD3Tis78iRgT1WeuAnxfTz21Wg=
-istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe h1:A3m5j1PRh1J/Y1YkDHP7wqaaIoxdK0NuFFNewwEqNHQ=
-istio.io/client-go v1.26.0-alpha.0.0.20250731213105-2f06e3d976fe/go.mod h1:QE8FEo9JtZNOrXjzYTsKq8kzb9f3xt/Mkp0XXUvg5Hc=
-istio.io/istio v0.0.0-20250801115405-9aa2567b5daf h1:nAxrB4KVuux87MkeVn2wYtXDdgTNQdmRsg7qlSk/lvE=
-istio.io/istio v0.0.0-20250801115405-9aa2567b5daf/go.mod h1:n2Rl5PCQ3uQOAFYZqeXTA4z/oVvc1Fj1VfkBs+qRS2Q=
 k8s.io/api v0.33.2 h1:YgwIS5jKfA+BZg//OQhkJNIfie/kmRsO0BmNaVSimvY=
 k8s.io/api v0.33.2/go.mod h1:fhrbphQJSM2cXzCWgqU29xLDuks4mu7ti9vveEnpSXs=
 k8s.io/apiextensions-apiserver v0.33.2 h1:6gnkIbngnaUflR3XwE1mCefN3YS8yTD631JXQhsU6M8=
 k8s.io/apiextensions-apiserver v0.33.2/go.mod h1:IvVanieYsEHJImTKXGP6XCOjTwv2LUMos0YWc9O+QP8=
 k8s.io/apimachinery v0.33.2 h1:IHFVhqg59mb8PJWTLi8m1mAoepkUNYmptHsV+Z1m5jY=
 k8s.io/apimachinery v0.33.2/go.mod h1:BHW0YOu7n22fFv/JkYOEfkUYNRN0fj0BlvMFWA7b+SM=
-k8s.io/apiserver v0.33.2 h1:KGTRbxn2wJagJowo29kKBp4TchpO1DRO3g+dB/KOJN4=
-k8s.io/apiserver v0.33.2/go.mod h1:9qday04wEAMLPWWo9AwqCZSiIn3OYSZacDyu/AcoM/M=
 k8s.io/cli-runtime v0.33.2 h1:koNYQKSDdq5AExa/RDudXMhhtFasEg48KLS2KSAU74Y=
 k8s.io/cli-runtime v0.33.2/go.mod h1:gnhsAWpovqf1Zj5YRRBBU7PFsRc6NkEkwYNQE+mXL88=
 k8s.io/client-go v0.33.2 h1:z8CIcc0P581x/J1ZYf4CNzRKxRvQAwoAolYPbtQes+E=
 k8s.io/client-go v0.33.2/go.mod h1:9mCgT4wROvL948w6f6ArJNb7yQd7QsvqavDeZHvNmHo=
-k8s.io/component-base v0.33.2 h1:sCCsn9s/dG3ZrQTX/Us0/Sx2R0G5kwa0wbZFYoVp/+0=
-k8s.io/component-base v0.33.2/go.mod h1:/41uw9wKzuelhN+u+/C59ixxf4tYQKW7p32ddkYNe2k=
 k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
 k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
 k8s.io/kube-openapi v0.0.0-20250318190949-c8a335a9a2ff h1:/usPimJzUKKu+m+TE36gUyGcf03XZEP0ZIKgKj35LS4=
@@ -932,20 +860,12 @@
 k8s.io/utils v0.0.0-20250502105355-0f33e8f1c979/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
 nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
 nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1 h1:Cf+ed5N8038zbsaXFO7mKQDi/+VcSRafb0jM84KX5so=
-sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.32.1/go.mod h1:Ve9uj1L+deCXFrPOk1LpFXqTg7LCFzFso6PA48q/XZw=
-sigs.k8s.io/gateway-api v1.3.0 h1:q6okN+/UKDATola4JY7zXzx40WO4VISk7i9DIfOvr9M=
-sigs.k8s.io/gateway-api v1.3.0/go.mod h1:d8NV8nJbaRbEKem+5IuxkL8gJGOZ+FJ+NvOIltV8gDk=
-sigs.k8s.io/gateway-api-inference-extension v0.5.0 h1:bYtXffUF1WUUFT2gYXaQBXIEXxXq/ZZLP9gqQweTrBI=
-sigs.k8s.io/gateway-api-inference-extension v0.5.0/go.mod h1:lki0jx1qysZSZT4Ai2BxuAcpx6G8g5oBgOGuuJzjy/k=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
 sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
 sigs.k8s.io/kustomize/api v0.19.0 h1:F+2HB2mU1MSiR9Hp1NEgoU2q9ItNOaBJl0I4Dlus5SQ=
 sigs.k8s.io/kustomize/api v0.19.0/go.mod h1:/BbwnivGVcBh1r+8m3tH1VNxJmHSk1PzP5fkP6lbL1o=
 sigs.k8s.io/kustomize/kyaml v0.19.0 h1:RFge5qsO1uHhwJsu3ipV7RNolC7Uozc0jUBC/61XSlA=
 sigs.k8s.io/kustomize/kyaml v0.19.0/go.mod h1:FeKD5jEOH+FbZPpqUghBP8mrLjJ3+zD3/rf9NNu1cwY=
-sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c h1:F7hIEutAxtXDOQX9NXFdvhWmWETu2zmUPHuPPcAez7g=
-sigs.k8s.io/mcs-api v0.1.1-0.20240624222831-d7001fe1d21c/go.mod h1:DPFniRsBzCeLB4ANjlPEvQQt9QGIX489d1faK+GPvI4=
 sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
 sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
 sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
diff --git a/navigator/pkg/bootstrap/mesh.go b/navigator/pkg/bootstrap/mesh.go
index 224f79e..ffe293c 100644
--- a/navigator/pkg/bootstrap/mesh.go
+++ b/navigator/pkg/bootstrap/mesh.go
@@ -61,9 +61,9 @@
 	if s.kubeClient == nil {
 		return nil
 	}
-	// configMapName := getMeshConfigMapName("")
-	// primary := kubemesh.NewConfigMapSource(s.kubeClient, args.Namespace, configMapName, cmKey, opts)
-	return nil
+	configMapName := getMeshConfigMapName("")
+	primary := kubemesh.NewConfigMapSource(s.kubeClient, args.Namespace, configMapName, cmKey, opts)
+	return toSources(primary, userMeshConfig)
 }
 
 func toSources(base meshwatcher.MeshConfigSource, user *meshwatcher.MeshConfigSource) []meshwatcher.MeshConfigSource {
diff --git a/navigator/pkg/features/navigator.go b/navigator/pkg/features/navigator.go
index 7b2d29a..6db8bf7 100644
--- a/navigator/pkg/features/navigator.go
+++ b/navigator/pkg/features/navigator.go
@@ -31,6 +31,9 @@
 		"If enabled, addition runtime asserts will be performed. "+
 			"These checks are both expensive and panic on failure. As a result, this should be used only for testing.",
 	).Get()
+	InformerWatchNamespace = env.Register("DUBBO_WATCH_NAMESPACE", "",
+		"If set, limit Kubernetes watches to a single namespace. "+
+			"Warning: only a single namespace can be set.").Get()
 	ClusterName = env.Register("CLUSTER_ID", constants.DefaultClusterName,
 		"Defines the cluster and service registry that this Dubbod instance belongs to").Get()
 )
diff --git a/pkg/config/mesh/kubemesh/watcher.go b/pkg/config/mesh/kubemesh/watcher.go
index f671366..18ef0db 100644
--- a/pkg/config/mesh/kubemesh/watcher.go
+++ b/pkg/config/mesh/kubemesh/watcher.go
@@ -18,10 +18,16 @@
 package kubemesh
 
 import (
+	"fmt"
 	"github.com/apache/dubbo-kubernetes/pkg/kube"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/kclient"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/krt"
 	"github.com/apache/dubbo-kubernetes/pkg/mesh/meshwatcher"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
 	v1 "k8s.io/api/core/v1"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/fields"
+	"k8s.io/apimachinery/pkg/types"
 )
 
 const (
@@ -29,8 +35,19 @@
 	MeshNetworksKey = "meshNetworks"
 )
 
-func NewConfigMapSource(client kube.Client, namespace, name, key string, opts krt.OptionsBuilder) meshwatcher.MeshConfigResource {
-	return meshwatcher.MeshConfigResource{}
+// NewConfigMapSource builds a MeshConfigSource reading from ConfigMap "name" with key "key".
+func NewConfigMapSource(client kube.Client, namespace, name, key string, opts krt.OptionsBuilder) meshwatcher.MeshConfigSource {
+	clt := kclient.NewFiltered[*v1.ConfigMap](client, kclient.Filter{
+		Namespace:     namespace,
+		FieldSelector: fields.OneTermEqualSelector(metav1.ObjectNameField, name).String(),
+	})
+	cms := krt.WrapClient(clt, opts.WithName("ConfigMap_"+name)...)
+	clt.Start(opts.Stop())
+	cmKey := types.NamespacedName{Namespace: namespace, Name: name}.String()
+	return krt.NewSingleton(func(ctx krt.HandlerContext) *string {
+		cm := ptr.Flatten(krt.FetchOne(ctx, cms, krt.FilterKey(cmKey)))
+		return meshConfigMapData(cm, key)
+	}, opts.WithName(fmt.Sprintf("ConfigMap_%s_%s", name, key))...)
 }
 
 func meshConfigMapData(cm *v1.ConfigMap, key string) *string {
diff --git a/pkg/config/schema/gvr/resource.gen.go b/pkg/config/schema/gvr/resource.gen.go
index f5f1bba..beb02e9 100644
--- a/pkg/config/schema/gvr/resource.gen.go
+++ b/pkg/config/schema/gvr/resource.gen.go
@@ -18,3 +18,9 @@
 	Service                        = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "services"}
 	ServiceAccount                 = schema.GroupVersionResource{Group: "", Version: "v1", Resource: "serviceaccounts"}
 )
+
+func IsClusterScoped(g schema.GroupVersionResource) bool {
+	switch g {
+	}
+	return false
+}
diff --git a/pkg/config/schema/kubeclient/common.go b/pkg/config/schema/kubeclient/common.go
new file mode 100644
index 0000000..5fbd1b4
--- /dev/null
+++ b/pkg/config/schema/kubeclient/common.go
@@ -0,0 +1,187 @@
+package kubeclient
+
+import (
+	"context"
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/pkg/config/schema/kubetypes"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
+	ktypes "github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+	"github.com/apache/dubbo-kubernetes/pkg/typemap"
+	kubeext "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	"k8s.io/apimachinery/pkg/watch"
+	"k8s.io/client-go/dynamic"
+	"k8s.io/client-go/kubernetes"
+	"k8s.io/client-go/metadata"
+	"k8s.io/client-go/tools/cache"
+)
+
+type ClientGetter interface {
+	// Ext returns the API extensions client.
+	Ext() kubeext.Interface
+
+	// Kube returns the core kube client
+	Kube() kubernetes.Interface
+
+	// Dynamic client.
+	Dynamic() dynamic.Interface
+
+	// Metadata returns the Metadata kube client.
+	Metadata() metadata.Interface
+
+	// Informers returns an informer factory.
+	Informers() informerfactory.InformerFactory
+}
+
+type TypeRegistration[T runtime.Object] interface {
+	kubetypes.RegisterType[T]
+
+	// ListWatchFunc provides the necessary methods for list and
+	// watch for the informer
+	ListWatch(c ClientGetter, opts ktypes.InformerOptions) cache.ListerWatcher
+}
+
+var registerTypes = typemap.NewTypeMap()
+
+func GetInformerFiltered[T runtime.Object](
+	c ClientGetter,
+	opts ktypes.InformerOptions,
+	gvr schema.GroupVersionResource,
+) informerfactory.StartableInformer {
+	reg := typemap.Get[TypeRegistration[T]](registerTypes)
+	if reg != nil {
+		// This is registered type
+		tr := *reg
+		return c.Informers().InformerFor(tr.GetGVR(), opts, func() cache.SharedIndexInformer {
+			inf := cache.NewSharedIndexInformer(
+				tr.ListWatch(c, opts),
+				tr.Object(),
+				0,
+				cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+			)
+			setupInformer(opts, inf)
+			return inf
+		})
+	}
+	return GetInformerFilteredFromGVR(c, opts, gvr)
+}
+
+func setupInformer(opts ktypes.InformerOptions, inf cache.SharedIndexInformer) {
+	if opts.ObjectTransform != nil {
+		_ = inf.SetTransform(opts.ObjectTransform)
+	} else {
+		_ = inf.SetTransform(stripUnusedFields)
+	}
+}
+
+func GetInformerFilteredFromGVR(c ClientGetter, opts ktypes.InformerOptions, g schema.GroupVersionResource) informerfactory.StartableInformer {
+	switch opts.InformerType {
+	case ktypes.DynamicInformer:
+		return getInformerFilteredDynamic(c, opts, g)
+	case ktypes.MetadataInformer:
+		return getInformerFilteredMetadata(c, opts, g)
+	default:
+		return getInformerFiltered(c, opts, g)
+	}
+}
+
+func getInformerFilteredDynamic(c ClientGetter, opts ktypes.InformerOptions, g schema.GroupVersionResource) informerfactory.StartableInformer {
+	return c.Informers().InformerFor(g, opts, func() cache.SharedIndexInformer {
+		inf := cache.NewSharedIndexInformerWithOptions(
+			&cache.ListWatch{
+				ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return c.Dynamic().Resource(g).Namespace(opts.Namespace).List(context.Background(), options)
+				},
+				WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return c.Dynamic().Resource(g).Namespace(opts.Namespace).Watch(context.Background(), options)
+				},
+			},
+			&unstructured.Unstructured{},
+			cache.SharedIndexInformerOptions{
+				ResyncPeriod:      0,
+				Indexers:          cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+				ObjectDescription: g.String(),
+			},
+		)
+		setupInformer(opts, inf)
+		return inf
+	})
+}
+
+func getInformerFilteredMetadata(c ClientGetter, opts ktypes.InformerOptions, g schema.GroupVersionResource) informerfactory.StartableInformer {
+	return c.Informers().InformerFor(g, opts, func() cache.SharedIndexInformer {
+		inf := cache.NewSharedIndexInformerWithOptions(
+			&cache.ListWatch{
+				ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return c.Metadata().Resource(g).Namespace(opts.Namespace).List(context.Background(), options)
+				},
+				WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return c.Metadata().Resource(g).Namespace(opts.Namespace).Watch(context.Background(), options)
+				},
+			},
+			&metav1.PartialObjectMetadata{},
+			cache.SharedIndexInformerOptions{
+				ResyncPeriod:      0,
+				Indexers:          cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+				ObjectDescription: g.String(),
+			},
+		)
+		setupInformer(opts, inf)
+		return inf
+	})
+}
+
+func stripUnusedFields(obj any) (any, error) {
+	t, ok := obj.(metav1.ObjectMetaAccessor)
+	if !ok {
+		// shouldn't happen
+		return obj, nil
+	}
+	// ManagedFields is large and we never use it
+	t.GetObjectMeta().SetManagedFields(nil)
+	return obj, nil
+}
+
+func getInformerFiltered(c ClientGetter, opts ktypes.InformerOptions, g schema.GroupVersionResource) informerfactory.StartableInformer {
+	var l func(options metav1.ListOptions) (runtime.Object, error)
+	var w func(options metav1.ListOptions) (watch.Interface, error)
+	return c.Informers().InformerFor(g, opts, func() cache.SharedIndexInformer {
+		inf := cache.NewSharedIndexInformer(
+			&cache.ListWatch{
+				ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return l(options)
+				},
+				WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
+					options.FieldSelector = opts.FieldSelector
+					options.LabelSelector = opts.LabelSelector
+					return w(options)
+				},
+			},
+			gvrToObject(g),
+			0,
+			cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
+		)
+		setupInformer(opts, inf)
+		return inf
+	})
+}
+
+func gvrToObject(g schema.GroupVersionResource) runtime.Object {
+	switch g {
+	default:
+		panic(fmt.Sprintf("Unknown type %v", g))
+	}
+}
diff --git a/pkg/config/schema/kubeclient/resource.gen.go b/pkg/config/schema/kubeclient/resource.gen.go
new file mode 100644
index 0000000..b44b608
--- /dev/null
+++ b/pkg/config/schema/kubeclient/resource.gen.go
@@ -0,0 +1,15 @@
+package kubeclient
+
+import (
+	"fmt"
+	ktypes "github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
+func GetWriteClient[T runtime.Object](c ClientGetter, namespace string) ktypes.WriteAPI[T] {
+	switch any(ptr.Empty[T]()).(type) {
+	default:
+		panic(fmt.Sprintf("Unknown type %T", ptr.Empty[T]()))
+	}
+}
diff --git a/pkg/config/schema/kubetypes/common.go b/pkg/config/schema/kubetypes/common.go
new file mode 100644
index 0000000..5864cc4
--- /dev/null
+++ b/pkg/config/schema/kubetypes/common.go
@@ -0,0 +1,38 @@
+package kubetypes
+
+import (
+	"github.com/apache/dubbo-kubernetes/operator/pkg/config"
+	"github.com/apache/dubbo-kubernetes/pkg/config/schema/gvk"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"github.com/apache/dubbo-kubernetes/pkg/typemap"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+)
+
+func MustGVKFromType[T runtime.Object]() (cfg config.GroupVersionKind) {
+	if gvk, ok := getGvk(ptr.Empty[T]()); ok {
+		return gvk
+	}
+	if rp := typemap.Get[RegisterType[T]](registeredTypes); rp != nil {
+		return (*rp).GetGVK()
+	}
+	panic("unknown kind: " + cfg.String())
+}
+
+func MustToGVR[T runtime.Object](cfg config.GroupVersionKind) schema.GroupVersionResource {
+	if r, ok := gvk.ToGVR(cfg); ok {
+		return r
+	}
+	if rp := typemap.Get[RegisterType[T]](registeredTypes); rp != nil {
+		return (*rp).GetGVR()
+	}
+	panic("unknown kind: " + cfg.String())
+}
+
+var registeredTypes = typemap.NewTypeMap()
+
+type RegisterType[T runtime.Object] interface {
+	GetGVK() config.GroupVersionKind
+	GetGVR() schema.GroupVersionResource
+	Object() T
+}
diff --git a/pkg/config/schema/kubetypes/resources.gen.go b/pkg/config/schema/kubetypes/resources.gen.go
new file mode 100644
index 0000000..7458225
--- /dev/null
+++ b/pkg/config/schema/kubetypes/resources.gen.go
@@ -0,0 +1,12 @@
+package kubetypes
+
+import (
+	"github.com/apache/dubbo-kubernetes/operator/pkg/config"
+)
+
+func getGvk(obj any) (config.GroupVersionKind, bool) {
+	switch obj.(type) {
+	default:
+		return config.GroupVersionKind{}, false
+	}
+}
diff --git a/pkg/kube/client.go b/pkg/kube/client.go
index b49a8c9..82babef 100644
--- a/pkg/kube/client.go
+++ b/pkg/kube/client.go
@@ -20,14 +20,19 @@
 import (
 	"fmt"
 	"github.com/apache/dubbo-kubernetes/operator/pkg/config"
+	"github.com/apache/dubbo-kubernetes/pkg/cluster"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/collections"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
 	"github.com/apache/dubbo-kubernetes/pkg/lazy"
+	"github.com/apache/dubbo-kubernetes/pkg/sleep"
 	kubeExtClient "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
 	"k8s.io/apimachinery/pkg/api/meta"
 	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
 	"k8s.io/apimachinery/pkg/runtime/schema"
 	kubeVersion "k8s.io/apimachinery/pkg/version"
+	"k8s.io/client-go/metadata"
+	"k8s.io/client-go/tools/cache"
+
 	// "k8s.io/client-go/discovery"
 	"k8s.io/client-go/dynamic"
 	"k8s.io/client-go/kubernetes"
@@ -47,15 +52,23 @@
 	dynamic         dynamic.Interface
 	kube            kubernetes.Interface
 	mapper          meta.ResettableRESTMapper
+	metadata        metadata.Interface
 	http            *http.Client
+	clusterID       cluster.ID
 }
 
 type Client interface {
-	// Ext returns the API extensions client.
 	Ext() kubeExtClient.Interface
 
-	// Kube returns the core kube client
 	Kube() kubernetes.Interface
+
+	ClusterID() cluster.ID
+
+	Dynamic() dynamic.Interface
+
+	Metadata() metadata.Interface
+
+	Informers() informerfactory.InformerFactory
 }
 
 type CLIClient interface {
@@ -135,6 +148,22 @@
 	return c.kube
 }
 
+func (c *client) ClusterID() cluster.ID {
+	return c.clusterID
+}
+
+func (c *client) Dynamic() dynamic.Interface {
+	return c.dynamic
+}
+
+func (c *client) Metadata() metadata.Interface {
+	return c.metadata
+}
+
+func (c *client) Informers() informerfactory.InformerFactory {
+	return c.informerFactory
+}
+
 func (c *client) DynamicClientFor(gvk schema.GroupVersionKind, obj *unstructured.Unstructured, namespace string) (dynamic.ResourceInterface, error) {
 	gvr, namespaced := c.bestEffortToGVR(gvk, obj, namespace)
 	var dr dynamic.ResourceInterface
@@ -179,3 +208,52 @@
 		return client
 	}
 }
+
+func WithCluster(id cluster.ID) ClientOption {
+	return func(c CLIClient) CLIClient {
+		client := c.(*client)
+		client.clusterID = id
+		return client
+	}
+}
+
+func WaitForCacheSync(name string, stop <-chan struct{}, cacheSyncs ...cache.InformerSynced) (r bool) {
+	_ = time.Now()
+	maximum := time.Millisecond * 100
+	delay := time.Millisecond
+	f := func() bool {
+		for _, syncFunc := range cacheSyncs {
+			if !syncFunc() {
+				return false
+			}
+		}
+		return true
+	}
+	attempt := 0
+	defer func() {
+		if r {
+		} else {
+		}
+	}()
+	for {
+		select {
+		case <-stop:
+			return false
+		default:
+		}
+		attempt++
+		res := f()
+		if res {
+			return true
+		}
+		delay *= 2
+		if delay > maximum {
+			delay = maximum
+		}
+		if attempt%50 == 0 {
+		}
+		if !sleep.Until(stop, delay) {
+			return false
+		}
+	}
+}
diff --git a/pkg/kube/controllers/common.go b/pkg/kube/controllers/common.go
index dc460a4..c9f2302 100644
--- a/pkg/kube/controllers/common.go
+++ b/pkg/kube/controllers/common.go
@@ -1,5 +1,10 @@
 package controllers
 
+import (
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+)
+
 type EventType int
 
 const (
@@ -27,3 +32,13 @@
 	}
 	return out
 }
+
+type ComparableObject interface {
+	comparable
+	Object
+}
+
+type Object interface {
+	metav1.Object
+	runtime.Object
+}
diff --git a/pkg/kube/kclient/client.go b/pkg/kube/kclient/client.go
new file mode 100644
index 0000000..6442920
--- /dev/null
+++ b/pkg/kube/kclient/client.go
@@ -0,0 +1,209 @@
+package kclient
+
+import (
+	"context"
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/navigator/pkg/features"
+	dubbogvr "github.com/apache/dubbo-kubernetes/pkg/config/schema/gvr"
+	"github.com/apache/dubbo-kubernetes/pkg/config/schema/kubeclient"
+	types "github.com/apache/dubbo-kubernetes/pkg/config/schema/kubetypes"
+	"github.com/apache/dubbo-kubernetes/pkg/kube"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/informerfactory"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/kubetypes"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"github.com/apache/dubbo-kubernetes/pkg/util/sets"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	klabels "k8s.io/apimachinery/pkg/labels"
+	"k8s.io/apimachinery/pkg/runtime/schema"
+	apitypes "k8s.io/apimachinery/pkg/types"
+	"k8s.io/client-go/tools/cache"
+	"sync"
+)
+
+type fullClient[T controllers.Object] struct {
+	writeClient[T]
+	Informer[T]
+}
+
+type writeClient[T controllers.Object] struct {
+	client kube.Client
+}
+
+func NewFiltered[T controllers.ComparableObject](c kube.Client, filter Filter) Client[T] {
+	gvr := types.MustToGVR[T](types.MustGVKFromType[T]())
+	inf := kubeclient.GetInformerFiltered[T](c, ToOpts(c, gvr, filter), gvr)
+	return &fullClient[T]{
+		writeClient: writeClient[T]{client: c},
+		Informer:    newInformerClient[T](gvr, inf, filter),
+	}
+}
+
+type Filter = kubetypes.Filter
+
+func ToOpts(c kube.Client, gvr schema.GroupVersionResource, filter Filter) kubetypes.InformerOptions {
+	ns := filter.Namespace
+	if !dubbogvr.IsClusterScoped(gvr) && ns == "" {
+		ns = features.InformerWatchNamespace
+	}
+	return kubetypes.InformerOptions{
+		LabelSelector:   filter.LabelSelector,
+		FieldSelector:   filter.FieldSelector,
+		Namespace:       ns,
+		ObjectTransform: filter.ObjectTransform,
+		Cluster:         c.ClusterID(),
+	}
+}
+
+type handlerRegistration struct {
+	registration cache.ResourceEventHandlerRegistration
+	// handler is the actual handler. Note this does NOT have the filtering applied.
+	handler cache.ResourceEventHandler
+}
+
+type informerClient[T controllers.Object] struct {
+	informer      cache.SharedIndexInformer
+	startInformer func(stopCh <-chan struct{})
+	filter        func(t any) bool
+
+	handlerMu          sync.RWMutex
+	registeredHandlers []handlerRegistration
+}
+
+func newInformerClient[T controllers.ComparableObject](
+	gvr schema.GroupVersionResource,
+	inf informerfactory.StartableInformer,
+	filter Filter,
+) Informer[T] {
+	ic := &informerClient[T]{
+		informer:      inf.Informer,
+		startInformer: inf.Start,
+	}
+	if filter.ObjectFilter != nil {
+		applyDynamicFilter(filter, gvr, ic)
+	}
+	return ic
+}
+
+func applyDynamicFilter[T controllers.ComparableObject](filter Filter, gvr schema.GroupVersionResource, ic *informerClient[T]) {
+	if filter.ObjectFilter != nil {
+		ic.filter = filter.ObjectFilter.Filter
+		filter.ObjectFilter.AddHandler(func(added, removed sets.String) {
+			ic.handlerMu.RLock()
+			defer ic.handlerMu.RUnlock()
+			if gvr == dubbogvr.Namespace {
+				for _, item := range ic.ListUnfiltered(metav1.NamespaceAll, klabels.Everything()) {
+					if !added.Contains(item.GetName()) {
+						continue
+					}
+					for _, c := range ic.registeredHandlers {
+						c.handler.OnAdd(item, false)
+					}
+				}
+			} else {
+				for ns := range added {
+					for _, item := range ic.ListUnfiltered(ns, klabels.Everything()) {
+						for _, c := range ic.registeredHandlers {
+							c.handler.OnAdd(item, false)
+						}
+					}
+				}
+				for ns := range removed {
+					for _, item := range ic.ListUnfiltered(ns, klabels.Everything()) {
+						for _, c := range ic.registeredHandlers {
+							c.handler.OnDelete(item)
+						}
+					}
+				}
+			}
+		})
+	}
+}
+
+func (n *informerClient[T]) ListUnfiltered(namespace string, selector klabels.Selector) []T {
+	var res []T
+	err := cache.ListAllByNamespace(n.informer.GetIndexer(), namespace, selector, func(i any) {
+		cast := i.(T)
+		res = append(res, cast)
+	})
+
+	// Should never happen
+	if err != nil && features.EnableUnsafeAssertions {
+		fmt.Printf("lister returned err for %v: %v", namespace, err)
+	}
+	return res
+}
+
+func (n *informerClient[T]) Start(stopCh <-chan struct{}) {
+	n.startInformer(stopCh)
+}
+
+func (n *informerClient[T]) Get(name, namespace string) T {
+	obj, exists, err := n.informer.GetIndexer().GetByKey(keyFunc(name, namespace))
+	if err != nil {
+		return ptr.Empty[T]()
+	}
+	if !exists {
+		return ptr.Empty[T]()
+	}
+	cast := obj.(T)
+	if !n.applyFilter(cast) {
+		return ptr.Empty[T]()
+	}
+	return cast
+}
+
+func keyFunc(name, namespace string) string {
+	if len(namespace) == 0 {
+		return name
+	}
+	return namespace + "/" + name
+}
+
+func (n *informerClient[T]) applyFilter(t T) bool {
+	if n.filter == nil {
+		return true
+	}
+	return n.filter(t)
+}
+
+func (n *writeClient[T]) Create(object T) (T, error) {
+	api := kubeclient.GetWriteClient[T](n.client, object.GetNamespace())
+	return api.Create(context.Background(), object, metav1.CreateOptions{})
+}
+
+func (n *writeClient[T]) Update(object T) (T, error) {
+	api := kubeclient.GetWriteClient[T](n.client, object.GetNamespace())
+	return api.Update(context.Background(), object, metav1.UpdateOptions{})
+}
+
+func (n *writeClient[T]) Patch(name, namespace string, pt apitypes.PatchType, data []byte) (T, error) {
+	api := kubeclient.GetWriteClient[T](n.client, namespace)
+	return api.Patch(context.Background(), name, pt, data, metav1.PatchOptions{})
+}
+
+func (n *writeClient[T]) PatchStatus(name, namespace string, pt apitypes.PatchType, data []byte) (T, error) {
+	api := kubeclient.GetWriteClient[T](n.client, namespace)
+	return api.Patch(context.Background(), name, pt, data, metav1.PatchOptions{}, "status")
+}
+
+func (n *writeClient[T]) ApplyStatus(name, namespace string, pt apitypes.PatchType, data []byte, fieldManager string) (T, error) {
+	api := kubeclient.GetWriteClient[T](n.client, namespace)
+	return api.Patch(context.Background(), name, pt, data, metav1.PatchOptions{
+		Force:        ptr.Of(true),
+		FieldManager: fieldManager,
+	}, "status")
+}
+
+func (n *writeClient[T]) UpdateStatus(object T) (T, error) {
+	api, ok := kubeclient.GetWriteClient[T](n.client, object.GetNamespace()).(kubetypes.WriteStatusAPI[T])
+	if !ok {
+		return ptr.Empty[T](), fmt.Errorf("%T does not support UpdateStatus", object)
+	}
+	return api.UpdateStatus(context.Background(), object, metav1.UpdateOptions{})
+}
+
+func (n *writeClient[T]) Delete(name, namespace string) error {
+	api := kubeclient.GetWriteClient[T](n.client, namespace)
+	return api.Delete(context.Background(), name, metav1.DeleteOptions{})
+}
diff --git a/pkg/kube/kclient/interfaces.go b/pkg/kube/kclient/interfaces.go
new file mode 100644
index 0000000..819f002
--- /dev/null
+++ b/pkg/kube/kclient/interfaces.go
@@ -0,0 +1,43 @@
+package kclient
+
+import (
+	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+	klabels "k8s.io/apimachinery/pkg/labels"
+	apitypes "k8s.io/apimachinery/pkg/types"
+)
+
+type Reader[T controllers.Object] interface {
+	// Get looks up an object by name and namespace. If it does not exist, nil is returned
+	Get(name, namespace string) T
+	// List looks up an object by namespace and labels.
+	// Use metav1.NamespaceAll and klabels.Everything() to select everything.
+	List(namespace string, selector klabels.Selector) []T
+}
+
+type Writer[T controllers.Object] interface {
+	// Create creates a resource, returning the newly applied resource.
+	Create(object T) (T, error)
+	// Update updates a resource, returning the newly applied resource.
+	Update(object T) (T, error)
+	// UpdateStatus updates a resource's status, returning the newly applied resource.
+	UpdateStatus(object T) (T, error)
+	// Patch patches the resource, returning the newly applied resource.
+	Patch(name, namespace string, pt apitypes.PatchType, data []byte) (T, error)
+	// PatchStatus patches the resource's status, returning the newly applied resource.
+	PatchStatus(name, namespace string, pt apitypes.PatchType, data []byte) (T, error)
+	// ApplyStatus does a server-side Apply of the the resource's status, returning the newly applied resource.
+	// fieldManager is a required field; see https://kubernetes.io/docs/reference/using-api/server-side-apply/#managers.
+	ApplyStatus(name, namespace string, pt apitypes.PatchType, data []byte, fieldManager string) (T, error)
+	// Delete removes a resource.
+	Delete(name, namespace string) error
+}
+
+type Informer[T controllers.Object] interface {
+	Start(stop <-chan struct{})
+}
+
+type Client[T controllers.Object] interface {
+	Reader[T]
+	Writer[T]
+	Informer[T]
+}
diff --git a/pkg/kube/krt/collection.go b/pkg/kube/krt/collection.go
new file mode 100644
index 0000000..0aaccc3
--- /dev/null
+++ b/pkg/kube/krt/collection.go
@@ -0,0 +1,178 @@
+package krt
+
+import (
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"github.com/apache/dubbo-kubernetes/pkg/util/sets"
+	"k8s.io/apimachinery/pkg/util/wait"
+	"sync"
+)
+
+type indexedDependencyType uint8
+
+type Key[O any] string
+
+const (
+	unknownIndexType indexedDependencyType = iota
+	indexType        indexedDependencyType = iota
+	getKeyType       indexedDependencyType = iota
+)
+
+type indexedDependency struct {
+	id  collectionUID
+	key string
+	typ indexedDependencyType
+}
+
+type extractorKey struct {
+	uid       collectionUID
+	filterUID collectionUID
+	typ       indexedDependencyType
+}
+
+type objectKeyExtractor = func(o any) []string
+
+type multiIndex[I, O any] struct {
+	outputs  map[Key[O]]O
+	inputs   map[Key[I]]I
+	mappings map[Key[I]]sets.Set[Key[O]]
+}
+
+type collectionIndex[I, O any] struct {
+	extract func(o O) []string
+	index   map[string]sets.Set[Key[O]]
+	parent  *manyCollection[I, O]
+}
+
+type dependencyState[I any] struct {
+	collectionDependencies       sets.Set[collectionUID]
+	objectDependencies           map[Key[I]][]*dependency
+	indexedDependencies          map[indexedDependency]sets.Set[Key[I]]
+	indexedDependenciesExtractor map[extractorKey]objectKeyExtractor
+}
+
+type handlerSet[O any] struct {
+	mu sync.RWMutex
+	wg wait.Group
+}
+
+func newHandlerSet[O any]() *handlerSet[O] {
+	return &handlerSet[O]{}
+}
+
+func NewCollection[I, O any](c Collection[I], hf TransformationSingle[I, O], opts ...CollectionOption) Collection[O] {
+	hm := func(ctx HandlerContext, i I) []O {
+		res := hf(ctx, i)
+		if res == nil {
+			return nil
+		}
+		return []O{*res}
+	}
+	o := buildCollectionOptions(opts...)
+	if o.name == "" {
+		o.name = fmt.Sprintf("Collection[%v,%v]", ptr.TypeName[I](), ptr.TypeName[O]())
+	}
+	return newManyCollection(c, hm, o, nil)
+}
+
+func newManyCollection[I, O any](
+	cc Collection[I],
+	hf TransformationMulti[I, O],
+	opts collectionOptions,
+	onPrimaryInputEventHandler func([]Event[I]),
+) Collection[O] {
+	c := cc.(internalCollection[I])
+
+	h := &manyCollection[I, O]{
+		transformation: hf,
+		collectionName: opts.name,
+		id:             nextUID(),
+		parent:         c,
+		dependencyState: dependencyState[I]{
+			collectionDependencies:       sets.New[collectionUID](),
+			objectDependencies:           map[Key[I]][]*dependency{},
+			indexedDependencies:          map[indexedDependency]sets.Set[Key[I]]{},
+			indexedDependenciesExtractor: map[extractorKey]func(o any) []string{},
+		},
+		collectionState: multiIndex[I, O]{
+			inputs:   map[Key[I]]I{},
+			outputs:  map[Key[O]]O{},
+			mappings: map[Key[I]]sets.Set[Key[O]]{},
+		},
+		indexes:                    make(map[string]collectionIndex[I, O]),
+		eventHandlers:              newHandlerSet[O](),
+		augmentation:               opts.augmentation,
+		synced:                     make(chan struct{}),
+		stop:                       opts.stop,
+		onPrimaryInputEventHandler: onPrimaryInputEventHandler,
+	}
+
+	if opts.metadata != nil {
+		h.metadata = opts.metadata
+	}
+
+	return nil
+}
+
+type internalCollection[T any] interface {
+	Collection[T]
+
+	// Name is a human facing name for this collection.
+	// Note this may not be universally unique
+	name() string
+	// Uid is an internal unique ID for this collection. MUST be globally unique
+	uid() collectionUID
+
+	dump() CollectionDump
+
+	// Augment mutates an object for use in various function calls. See WithObjectAugmentation
+	augment(any) any
+
+	// Create a new index into the collection
+	index(name string, extract func(o T) []string) indexer[T]
+}
+
+type CollectionDump struct {
+	// Map of output key -> output
+	Outputs map[string]any `json:"outputs,omitempty"`
+	// Name of the input collection
+	InputCollection string `json:"inputCollection,omitempty"`
+	// Map of input key -> info
+	Inputs map[string]InputDump `json:"inputs,omitempty"`
+	// Synced returns whether the collection is synced or not
+	Synced bool `json:"synced"`
+}
+
+type InputDump struct {
+	Outputs      []string `json:"outputs,omitempty"`
+	Dependencies []string `json:"dependencies,omitempty"`
+}
+
+type manyCollection[I, O any] struct {
+	// collectionName provides the collectionName for this collection.
+	collectionName string
+	id             collectionUID
+	// parent is the input collection we are building off of.
+	parent          Collection[I]
+	mu              sync.RWMutex
+	collectionState multiIndex[I, O]
+	dependencyState dependencyState[I]
+	// internal indexes
+	indexes map[string]collectionIndex[I, O]
+
+	// eventHandlers is a list of event handlers registered for the collection. On any changes, each will be notified.
+	eventHandlers *handlerSet[O]
+
+	transformation TransformationMulti[I, O]
+
+	// augmentation allows transforming an object into another for usage throughout the library. See WithObjectAugmentation.
+	augmentation func(a any) any
+	synced       chan struct{}
+	stop         <-chan struct{}
+	metadata     Metadata
+
+	// onPrimaryInputEventHandler is a specialized internal handler that runs synchronously when a primary input changes
+	onPrimaryInputEventHandler func(o []Event[I])
+
+	syncer Syncer
+}
diff --git a/pkg/kube/krt/core.go b/pkg/kube/krt/core.go
index fa267fc..49635f1 100644
--- a/pkg/kube/krt/core.go
+++ b/pkg/kube/krt/core.go
@@ -5,34 +5,28 @@
 type FetchOption func(*dependency)
 
 type HandlerContext interface {
-	// DiscardResult triggers the result of this invocation to be skipped
-	// This allows a collection to mark that the current state is *invalid* and should use the last-known state.
-	//
-	// Note: this differs from returning `nil`, which would otherwise wipe out the last known state.
-	//
-	// Note: if the current resource has never been computed, the result will not be discarded if it is non-nil. This allows
-	// setting a default. For example, you may always return a static default config if the initial results are invalid,
-	// but not revert to this config if later results are invalid. Results can unconditionally be discarded by returning nil.
 	DiscardResult()
-	// _internalHandler is an interface that can only be implemented by this package.
 	_internalHandler()
 }
 
 type (
-	TransformationEmpty[T any] func(ctx HandlerContext) *T
+	TransformationEmpty[T any]     func(ctx HandlerContext) *T
+	TransformationMulti[I, O any]  func(ctx HandlerContext, i I) []O
+	TransformationSingle[I, O any] func(ctx HandlerContext, i I) *O
 )
 
 type Metadata map[string]any
 
 type Event[T any] struct {
-	// Old object, set on Update or Delete.
-	Old *T
-	// New object, set on Add or Update
-	New *T
-	// Event is the change type
+	Old   *T
+	New   *T
 	Event controllers.EventType
 }
 
+type indexer[T any] interface {
+	Lookup(key string) []T
+}
+
 type EventStream[T any] interface {
 	Syncer
 	Register(f func(o Event[T])) HandlerRegistration
@@ -57,27 +51,14 @@
 }
 
 type Collection[T any] interface {
-	// GetKey returns an object by its key, if present. Otherwise, nil is returned.
 	GetKey(k string) *T
-
-	// List returns all objects in the collection.
-	// Order of the list is undefined.
 	List() []T
-
-	// EventStream provides event handling capabilities for the collection, allowing clients to subscribe to changes
-	// and receive notifications when objects are added, modified, or removed.
 	EventStream[T]
-
-	// Metadata returns the metadata associated with this collection.
-	// This can be used to store and retrieve arbitrary key-value pairs
-	// that provide additional context or configuration for the collection.
 	Metadata() Metadata
 }
 
 type Singleton[T any] interface {
-	// Get returns the object, or nil if there is none.
 	Get() *T
-	// Register adds an event watcher to the object. Any time it changes, the handler will be called
 	Register(f func(o Event[T])) HandlerRegistration
 	AsCollection() Collection[T]
 	Metadata() Metadata
diff --git a/pkg/kube/krt/files/files.go b/pkg/kube/krt/files/files.go
index d00aaf1..8ab08ce 100644
--- a/pkg/kube/krt/files/files.go
+++ b/pkg/kube/krt/files/files.go
@@ -3,6 +3,8 @@
 import (
 	"github.com/apache/dubbo-kubernetes/pkg/filewatcher"
 	"github.com/apache/dubbo-kubernetes/pkg/kube/krt"
+	"go.uber.org/atomic"
+	"time"
 )
 
 type FileSingleton[T any] struct {
@@ -14,6 +16,49 @@
 	filename string,
 	readFile func(filename string) (T, error),
 	opts ...krt.CollectionOption,
-) {
-	return
+) (FileSingleton[T], error) {
+	cfg, err := readFile(filename)
+	if err != nil {
+		return FileSingleton[T]{}, err
+	}
+
+	stop := krt.GetStop(opts...)
+
+	cur := atomic.NewPointer(&cfg)
+	trigger := krt.NewRecomputeTrigger(true, opts...)
+	sc := krt.NewSingleton[T](func(ctx krt.HandlerContext) *T {
+		trigger.MarkDependant(ctx)
+		return cur.Load()
+	}, opts...)
+	sc.AsCollection().WaitUntilSynced(stop)
+	watchFile(fileWatcher, filename, stop, func() {
+		cfg, err := readFile(filename)
+		if err != nil {
+			log.Warnf("failed to update: %v", err)
+			return
+		}
+		cur.Store(&cfg)
+		trigger.TriggerRecomputation()
+	})
+	return FileSingleton[T]{sc}, nil
+}
+
+func watchFile(fileWatcher filewatcher.FileWatcher, file string, stop <-chan struct{}, callback func()) {
+	_ = fileWatcher.Add(file)
+	go func() {
+		var timerC <-chan time.Time
+		for {
+			select {
+			case <-stop:
+				return
+			case <-timerC:
+				timerC = nil
+				callback()
+			case <-fileWatcher.Events(file):
+				if timerC == nil {
+					timerC = time.After(100 * time.Millisecond)
+				}
+			}
+		}
+	}()
 }
diff --git a/pkg/kube/krt/filter.go b/pkg/kube/krt/filter.go
index 4545782..2bb04cd 100644
--- a/pkg/kube/krt/filter.go
+++ b/pkg/kube/krt/filter.go
@@ -1,3 +1,13 @@
 package krt
 
-type filter struct{}
+import "github.com/apache/dubbo-kubernetes/pkg/util/smallset"
+
+type filter struct {
+	keys smallset.Set[string]
+}
+
+func FilterKey(k string) FetchOption {
+	return func(h *dependency) {
+		h.filter.keys = smallset.New(k)
+	}
+}
diff --git a/pkg/kube/krt/helpers.go b/pkg/kube/krt/helpers.go
new file mode 100644
index 0000000..9b3f14c
--- /dev/null
+++ b/pkg/kube/krt/helpers.go
@@ -0,0 +1,29 @@
+package krt
+
+import (
+	"time"
+)
+
+func waitForCacheSync(name string, stop <-chan struct{}, collections ...<-chan struct{}) (r bool) {
+	t := time.NewTicker(time.Second * 5)
+	defer t.Stop()
+	_ = time.Now()
+	defer func() {
+		if r {
+		} else {
+		}
+	}()
+	for _, col := range collections {
+		for {
+			select {
+			case <-t.C:
+				continue
+			case <-stop:
+				return false
+			case <-col:
+			}
+			break
+		}
+	}
+	return true
+}
diff --git a/pkg/kube/krt/informer.go b/pkg/kube/krt/informer.go
new file mode 100644
index 0000000..3a64e3b
--- /dev/null
+++ b/pkg/kube/krt/informer.go
@@ -0,0 +1,50 @@
+package krt
+
+import (
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/kclient"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+)
+
+type informer[I controllers.ComparableObject] struct {
+	inf            kclient.Informer[I]
+	collectionName string
+	id             collectionUID
+	augmentation   func(a any) any
+	synced         chan struct{}
+	baseSyncer     Syncer
+	metadata       Metadata
+}
+
+type channelSyncer struct {
+	name   string
+	synced <-chan struct{}
+}
+
+func WrapClient[I controllers.ComparableObject](c kclient.Informer[I], opts ...CollectionOption) Collection[I] {
+	o := buildCollectionOptions(opts...)
+	if o.name == "" {
+		o.name = fmt.Sprintf("Informer[%v]", ptr.TypeName[I]())
+	}
+	h := &informer[I]{
+		inf:            c,
+		collectionName: o.name,
+		id:             nextUID(),
+		augmentation:   o.augmentation,
+		synced:         make(chan struct{}),
+	}
+	h.baseSyncer = channelSyncer{
+		name:   h.collectionName,
+		synced: h.synced,
+	}
+
+	if o.metadata != nil {
+		h.metadata = o.metadata
+	}
+	return nil
+}
+
+func (c channelSyncer) WaitUntilSynced(stop <-chan struct{}) bool {
+	return waitForCacheSync(c.name, stop, c.synced)
+}
diff --git a/pkg/kube/krt/internal.go b/pkg/kube/krt/internal.go
index 58f83b1..291c4f3 100644
--- a/pkg/kube/krt/internal.go
+++ b/pkg/kube/krt/internal.go
@@ -1,10 +1,11 @@
 package krt
 
+import "go.uber.org/atomic"
+
 type dependency struct {
 	id             collectionUID
 	collectionName string
-	// Filter over the collection
-	filter *filter
+	filter         *filter
 }
 
 type collectionUID uint64
@@ -24,3 +25,9 @@
 	}
 	return *c
 }
+
+var globalUIDCounter = atomic.NewUint64(1)
+
+func nextUID() collectionUID {
+	return collectionUID(globalUIDCounter.Inc())
+}
diff --git a/pkg/kube/krt/options.go b/pkg/kube/krt/options.go
index c7446c8..6f076e6 100644
--- a/pkg/kube/krt/options.go
+++ b/pkg/kube/krt/options.go
@@ -14,6 +14,10 @@
 	}
 }
 
+func (k OptionsBuilder) Stop() <-chan struct{} {
+	return k.stop
+}
+
 func (k OptionsBuilder) WithName(n string) []CollectionOption {
 	name := n
 	if k.namePrefix != "" {
diff --git a/pkg/kube/krt/recomputetrigger.go b/pkg/kube/krt/recomputetrigger.go
new file mode 100644
index 0000000..9d41eed
--- /dev/null
+++ b/pkg/kube/krt/recomputetrigger.go
@@ -0,0 +1,86 @@
+package krt
+
+import (
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"go.uber.org/atomic"
+)
+
+type RecomputeProtected[T any] struct {
+	trigger *RecomputeTrigger
+	data    T
+}
+
+// Get marks us as dependent on the value and fetches it.
+func (c RecomputeProtected[T]) Get(ctx HandlerContext) T {
+	c.trigger.MarkDependant(ctx)
+	return c.data
+}
+
+// TriggerRecomputation tells all dependants to recompute
+func (c RecomputeProtected[T]) TriggerRecomputation() {
+	c.trigger.TriggerRecomputation()
+}
+
+// MarkSynced marks this trigger as ready. Before this is called, dependant collections will be blocked.
+// This ensures initial state is populated.
+func (c RecomputeProtected[T]) MarkSynced() {
+	c.trigger.MarkSynced()
+}
+
+// Modify modifies the object and triggers a recompution.
+func (c RecomputeProtected[T]) Modify(fn func(*T)) {
+	fn(&c.data)
+	c.TriggerRecomputation()
+}
+
+// AccessUnprotected returns the data without marking as dependant. This must be used with caution; any use within a collection
+// is likely broken
+func (c RecomputeProtected[T]) AccessUnprotected() T {
+	return c.data
+}
+
+// NewRecomputeProtected builds a RecomputeProtected which wraps some data, ensuring it is always MarkDependant when accessed
+func NewRecomputeProtected[T any](initialData T, startSynced bool, opts ...CollectionOption) RecomputeProtected[T] {
+	trigger := NewRecomputeTrigger(startSynced, opts...)
+	return RecomputeProtected[T]{
+		trigger: trigger,
+		data:    initialData,
+	}
+}
+
+// RecomputeTrigger trigger provides an escape hatch to allow krt transformations to depend on external state and recompute
+// correctly when those change.
+// Typically, all state is registered and fetched through krt.Fetch. Through this mechanism, any changes are automatically
+// propagated through the system to dependencies.
+// In some cases, it may not be feasible to get all state into krt; hopefully, this is a temporary state.
+// RecomputeTrigger works around this by allowing an explicit call to recompute a collection; the caller must be sure to call Trigger()
+// any time the state changes.
+type RecomputeTrigger struct {
+	inner StaticSingleton[int32]
+	// krt will suppress events for unchanged resources. To workaround this, we constantly change and int each time TriggerRecomputation
+	// is called to ensure our event is not suppressed.
+	i *atomic.Int32
+}
+
+func NewRecomputeTrigger(startSynced bool, opts ...CollectionOption) *RecomputeTrigger {
+	inner := NewStatic[int32](ptr.Of(int32(0)), startSynced, opts...)
+	return &RecomputeTrigger{inner: inner, i: atomic.NewInt32(0)}
+}
+
+// TriggerRecomputation tells all dependants to recompute
+func (r *RecomputeTrigger) TriggerRecomputation() {
+	v := r.i.Inc()
+	r.inner.Set(ptr.Of(v))
+}
+
+// MarkDependant marks the given context as depending on this trigger. This registers it to be recomputed when TriggerRecomputation
+// is called.
+func (r *RecomputeTrigger) MarkDependant(ctx HandlerContext) {
+	_ = Fetch(ctx, r.inner.AsCollection())
+}
+
+// MarkSynced marks this trigger as ready. Before this is called, dependant collections will be blocked.
+// This ensures initial state is populated.
+func (r *RecomputeTrigger) MarkSynced() {
+	r.inner.MarkSynced()
+}
diff --git a/pkg/kube/krt/singleton.go b/pkg/kube/krt/singleton.go
index 414641f..b9e56d6 100644
--- a/pkg/kube/krt/singleton.go
+++ b/pkg/kube/krt/singleton.go
@@ -1,17 +1,200 @@
 package krt
 
-func NewSingleton[O any](hf TransformationEmpty[O], opts ...CollectionOption) Singleton[O] {
-	return nil
+import (
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/pkg/kube/controllers"
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"github.com/apache/dubbo-kubernetes/pkg/util/slices"
+
+	"sync/atomic"
+)
+
+type dummyValue struct{}
+
+func (d dummyValue) ResourceName() string {
+	return ""
 }
 
-var (
-	_ Singleton[any] = &collectionAdapter[any]{}
-)
+type StaticSingleton[T any] interface {
+	Singleton[T]
+	Set(*T)
+	MarkSynced()
+}
+
+func NewStatic[T any](initial *T, startSynced bool, opts ...CollectionOption) StaticSingleton[T] {
+	val := new(atomic.Pointer[T])
+	val.Store(initial)
+	x := &static[T]{
+		val:           val,
+		synced:        &atomic.Bool{},
+		id:            nextUID(),
+		eventHandlers: &handlers[T]{},
+	}
+	x.synced.Store(startSynced)
+	o := buildCollectionOptions(opts...)
+	if o.name == "" {
+		o.name = fmt.Sprintf("Static[%v]", ptr.TypeName[T]())
+	}
+	x.collectionName = o.name
+	x.syncer = pollSyncer{
+		name: x.collectionName,
+		f: func() bool {
+			return x.synced.Load()
+		},
+	}
+	if o.metadata != nil {
+		x.metadata = o.metadata
+	}
+	maybeRegisterCollectionForDebugging(x, o.debugger)
+	return collectionAdapter[T]{x}
+}
+
+type static[T any] struct {
+	val            *atomic.Pointer[T]
+	synced         *atomic.Bool
+	id             collectionUID
+	eventHandlers  *handlers[T]
+	collectionName string
+	syncer         Syncer
+	metadata       Metadata
+}
+
+func (d *static[T]) GetKey(k string) *T {
+	return d.val.Load()
+}
+
+func (d *static[T]) List() []T {
+	v := d.val.Load()
+	if v == nil {
+		return nil
+	}
+	return []T{*v}
+}
+
+func (d *static[T]) Metadata() Metadata {
+	return d.metadata
+}
+
+func (d *static[T]) Register(f func(o Event[T])) HandlerRegistration {
+	return registerHandlerAsBatched[T](d, f)
+}
+
+func (d *static[T]) RegisterBatch(f func(o []Event[T]), runExistingState bool) HandlerRegistration {
+	reg := d.eventHandlers.Insert(f)
+	if runExistingState {
+		v := d.val.Load()
+		if v != nil {
+			f([]Event[T]{{
+				New:   v,
+				Event: controllers.EventAdd,
+			}})
+		}
+	}
+
+	return staticHandler{Syncer: d.syncer, remove: func() {
+		d.eventHandlers.Delete(reg)
+	}}
+}
+
+type staticHandler struct {
+	Syncer
+	remove func()
+}
+
+func (s staticHandler) UnregisterHandler() {
+	s.remove()
+}
+
+func (d *static[T]) Synced() Syncer {
+	return pollSyncer{
+		name: d.collectionName,
+		f: func() bool {
+			return d.synced.Load()
+		},
+	}
+}
+
+func (d *static[T]) HasSynced() bool {
+	return d.syncer.HasSynced()
+}
+
+func (d *static[T]) WaitUntilSynced(stop <-chan struct{}) bool {
+	return d.syncer.WaitUntilSynced(stop)
+}
+
+func (d *static[T]) Set(now *T) {
+	old := d.val.Swap(now)
+	if old == now {
+		return
+	}
+	for _, h := range d.eventHandlers.Get() {
+		h([]Event[T]{toEvent[T](old, now)})
+	}
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) dump() CollectionDump {
+	return CollectionDump{
+		Outputs: map[string]any{
+			"static": d.val.Load(),
+		},
+		Synced: d.HasSynced(),
+	}
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) augment(a any) any {
+	// not supported in this collection type
+	return a
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) name() string {
+	return d.collectionName
+}
+
+// nolint: unused // (not true, its to implement an interface)
+func (d *static[T]) uid() collectionUID {
+	return d.id
+}
+
+func (d *static[T]) index(name string, extract func(o T) []string) indexer[T] {
+	panic("TODO")
+}
+
+func toEvent[T any](old, now *T) Event[T] {
+	if old == nil {
+		return Event[T]{
+			New:   now,
+			Event: controllers.EventAdd,
+		}
+	} else if now == nil {
+		return Event[T]{
+			Old:   old,
+			Event: controllers.EventDelete,
+		}
+	}
+	return Event[T]{
+		New:   now,
+		Old:   old,
+		Event: controllers.EventUpdate,
+	}
+}
+
+var _ Collection[dummyValue] = &static[dummyValue]{}
 
 type collectionAdapter[T any] struct {
 	c Collection[T]
 }
 
+func (c collectionAdapter[T]) MarkSynced() {
+	c.c.(*static[T]).synced.Store(true)
+}
+
+func (c collectionAdapter[T]) Set(t *T) {
+	c.c.(*static[T]).Set(t)
+}
+
 func (c collectionAdapter[T]) Get() *T {
 	// Guaranteed to be 0 or 1 len
 	res := c.c.List()
@@ -33,3 +216,16 @@
 func (c collectionAdapter[T]) AsCollection() Collection[T] {
 	return c.c
 }
+
+var (
+	_ Singleton[any] = &collectionAdapter[any]{}
+)
+
+func NewSingleton[O any](hf TransformationEmpty[O], opts ...CollectionOption) Singleton[O] {
+	staticOpts := append(slices.Clone(opts), nil)
+	dummyCollection := NewStatic[dummyValue](&dummyValue{}, true, staticOpts...).AsCollection()
+	col := NewCollection[dummyValue, O](dummyCollection, func(ctx HandlerContext, _ dummyValue) *O {
+		return hf(ctx)
+	}, opts...)
+	return collectionAdapter[O]{col}
+}
diff --git a/pkg/kube/kubetypes/types.go b/pkg/kube/kubetypes/types.go
index eecccd3..989de8c 100644
--- a/pkg/kube/kubetypes/types.go
+++ b/pkg/kube/kubetypes/types.go
@@ -17,14 +17,54 @@
 
 package kubetypes
 
+import (
+	"context"
+	"github.com/apache/dubbo-kubernetes/pkg/cluster"
+	"github.com/apache/dubbo-kubernetes/pkg/util/sets"
+	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+	"k8s.io/apimachinery/pkg/runtime"
+	"k8s.io/apimachinery/pkg/types"
+)
+
+type InformerType int
+
+const (
+	StandardInformer InformerType = iota
+	DynamicInformer
+	MetadataInformer
+)
+
+type WriteAPI[T runtime.Object] interface {
+	Create(ctx context.Context, object T, opts metav1.CreateOptions) (T, error)
+	Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result T, err error)
+	Update(ctx context.Context, object T, opts metav1.UpdateOptions) (T, error)
+	Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
+}
+
+type WriteStatusAPI[T runtime.Object] interface {
+	UpdateStatus(ctx context.Context, object T, opts metav1.UpdateOptions) (T, error)
+}
+
 type InformerOptions struct {
-	// A selector to restrict the list of returned objects by their labels.
-	LabelSelector string
-	// A selector to restrict the list of returned objects by their fields.
-	FieldSelector string
-	// Namespace to watch.
-	Namespace string
-	// ObjectTransform allows arbitrarily modifying objects stored in the underlying cache.
-	// If unset, a default transform is provided to remove ManagedFields (high cost, low value)
+	LabelSelector   string
+	FieldSelector   string
+	Namespace       string
 	ObjectTransform func(obj any) (any, error)
+	Cluster         cluster.ID
+	InformerType    InformerType
+}
+
+type Filter struct {
+	LabelSelector   string
+	FieldSelector   string
+	Namespace       string
+	ObjectFilter    DynamicObjectFilter
+	ObjectTransform func(obj any) (any, error)
+}
+
+type DynamicObjectFilter interface {
+	// Filter returns true if the input object or namespace string resides in a namespace selected for discovery
+	Filter(obj any) bool
+	// AddHandler registers a handler on namespace, which will be triggered when namespace selected or deselected.
+	AddHandler(func(selected, deselected sets.String))
 }
diff --git a/pkg/mesh/meshwatcher/collection.go b/pkg/mesh/meshwatcher/collection.go
index 04090d4..d1e93be 100644
--- a/pkg/mesh/meshwatcher/collection.go
+++ b/pkg/mesh/meshwatcher/collection.go
@@ -6,7 +6,6 @@
 	"github.com/apache/dubbo-kubernetes/pkg/kube/krt"
 	krtfiles "github.com/apache/dubbo-kubernetes/pkg/kube/krt/files"
 	"github.com/apache/dubbo-kubernetes/pkg/mesh"
-
 	"os"
 	"path"
 )
diff --git a/pkg/ptr/pointer.go b/pkg/ptr/pointer.go
index 5388152..6f40c10 100644
--- a/pkg/ptr/pointer.go
+++ b/pkg/ptr/pointer.go
@@ -1,5 +1,24 @@
 package ptr
 
+import "fmt"
+
 func Of[T any](t T) *T {
 	return &t
 }
+
+func Empty[T any]() T {
+	var empty T
+	return empty
+}
+
+func Flatten[T any](t **T) *T {
+	if t == nil {
+		return nil
+	}
+	return *t
+}
+
+func TypeName[T any]() string {
+	var empty T
+	return fmt.Sprintf("%T", empty)
+}
diff --git a/pkg/sleep/sleep.go b/pkg/sleep/sleep.go
new file mode 100644
index 0000000..f959876
--- /dev/null
+++ b/pkg/sleep/sleep.go
@@ -0,0 +1,23 @@
+package sleep
+
+import (
+	"context"
+	"time"
+)
+
+func UntilContext(ctx context.Context, d time.Duration) bool {
+	return Until(ctx.Done(), d)
+}
+
+func Until(ch <-chan struct{}, d time.Duration) bool {
+	timer := time.NewTimer(d)
+	select {
+	case <-ch:
+		if !timer.Stop() {
+			<-timer.C
+		}
+		return false
+	case <-timer.C:
+		return true
+	}
+}
diff --git a/pkg/typemap/map.go b/pkg/typemap/map.go
new file mode 100644
index 0000000..037cd27
--- /dev/null
+++ b/pkg/typemap/map.go
@@ -0,0 +1,27 @@
+package typemap
+
+import (
+	"github.com/apache/dubbo-kubernetes/pkg/ptr"
+	"reflect"
+)
+
+type TypeMap struct {
+	inner map[reflect.Type]any
+}
+
+func NewTypeMap() TypeMap {
+	return TypeMap{make(map[reflect.Type]any)}
+}
+
+func Set[T any](t TypeMap, v T) {
+	interfaceType := reflect.TypeOf((*T)(nil)).Elem()
+	t.inner[interfaceType] = v
+}
+
+func Get[T any](t TypeMap) *T {
+	v, f := t.inner[reflect.TypeFor[T]()]
+	if f {
+		return ptr.Of(v.(T))
+	}
+	return nil
+}
diff --git a/pkg/util/smallset/smallset.go b/pkg/util/smallset/smallset.go
new file mode 100644
index 0000000..5adbfa7
--- /dev/null
+++ b/pkg/util/smallset/smallset.go
@@ -0,0 +1,108 @@
+package smallset
+
+import (
+	"cmp"
+	"fmt"
+	"github.com/apache/dubbo-kubernetes/pkg/util/slices"
+)
+
+// Set is an immutable set optimized for *small number of items*. For general purposes, Sets is likely better
+//
+// *Set construction*: sets is roughly 1kb allocations per 250 items. smallsets is 0.
+// *Contains* sets is O(1). smallsets is O(logn). smallsets is typically faster up to about 5 elements.
+//
+//	At 1000 items, it is roughly 5x slower (30ns vs 5ns).
+type Set[T cmp.Ordered] struct {
+	items []T
+}
+
+// NewPresorted creates a new Set with the given items.
+// If items is not sorted or contains duplicates, this gives undefined behavior; use New instead.
+func NewPresorted[T cmp.Ordered](items ...T) Set[T] {
+	return Set[T]{items: items}
+}
+
+// New creates a new Set with the given items.
+// Duplicates are removed
+func New[T cmp.Ordered](items ...T) Set[T] {
+	if len(items) == 1 {
+		return Set[T]{items: items}
+	}
+	slices.Sort(items)
+	items = slices.FilterDuplicatesPresorted(items)
+	return Set[T]{items: items}
+}
+
+// CopyAndInsert builds a *new* with all the current items plus new items
+func (s Set[T]) CopyAndInsert(items ...T) Set[T] {
+	slices.Sort(items)
+	// This is basically the 'merge' part of merge sort.
+	a := s.items
+	b := items
+	nl := make([]T, 0, len(a)+len(b))
+	i, j := 0, 0
+	appendIfUnique := func(t T) []T {
+		l := len(nl)
+		if l == 0 {
+			nl = append(nl, t)
+		} else {
+			last := nl[l-1]
+			if last != t {
+				nl = append(nl, t)
+			}
+		}
+		return nl
+	}
+	for i < len(a) && j < len(b) {
+		if a[i] < b[j] {
+			nl = appendIfUnique(a[i])
+			i++
+		} else {
+			nl = appendIfUnique(b[j])
+			j++
+		}
+	}
+	for ; i < len(a); i++ {
+		nl = appendIfUnique(a[i])
+	}
+	for ; j < len(b); j++ {
+		nl = appendIfUnique(b[j])
+	}
+	// we already know they are sorted+unique
+	return Set[T]{items: nl}
+}
+
+// List returns the underlying slice. Must not be modified
+func (s Set[T]) List() []T {
+	return s.items
+}
+
+// Contains returns whether the given item is in the set.
+func (s Set[T]) Contains(item T) bool {
+	_, f := slices.BinarySearch(s.items, item)
+	return f
+}
+
+// Len returns the number of elements in this Set.
+func (s Set[T]) Len() int {
+	return len(s.items)
+}
+
+// IsEmpty indicates whether the set is the empty set.
+func (s Set[T]) IsEmpty() bool {
+	return len(s.items) == 0
+}
+
+// IsNil indicates whether the set is nil. This is different from an empty set.
+// 'var smallset.Set': nil
+// smallset.New(): nil
+// smallset.New(emptyList...): not nil
+func (s Set[T]) IsNil() bool {
+	return s.items == nil
+}
+
+// String returns a string representation of the set.
+// Use it only for debugging and logging.
+func (s Set[T]) String() string {
+	return fmt.Sprintf("%v", s.items)
+}