ProtoMap makes Claude Code 6.4× faster and 5.3× cheaper across 9 gRPC repositories with 5 million lines of code
We asked Claude Code 20 questions engineers ask every day in gRPC and protobuf codebases, on nine repositories in seven languages with 2,380 gRPC services, with and without the ProtoMap MCP server, twice each, with Opus 5.5 at high effort and Sonnet 5.5 at extra-high effort. Answers were graded by code against an answer key that does not come from ProtoMap. October 28, 2026.
Opus 5.5 · high effort
Sonnet 5.5 · xhigh effort
Side by side
Two live Claude Code sessions (Opus 5.5, high effort) given Q09 at the same moment, recorded on one screen: ProtoMap's answers in 50 seconds for $0.40, the baseline's in 6 minutes for $14.44. Sped up where marked.
Open the video page → · Want the full story? Watch the live ProtoMap demo at MozFest →
Per prompt
Opus 5.5 · high effort: time to answer
Median wall-clock time of 2 runs per prompt (their mean), log scale. The figure at the right of each row is how many times faster the answer came with ProtoMap.
Opus 5.5 · high effort: cost per answer
Median cost of 2 runs per prompt (their mean) at API prices, as Claude Code reports it, log scale.
Opus 5.5 · high effort: table view
| Prompt | Baseline time | ProtoMap time | Faster | Baseline cost | ProtoMap cost | Cheaper | Baseline tokens | ProtoMap tokens | ProtoMap calls |
|---|---|---|---|---|---|---|---|---|---|
| Q01 · list services | 1m 12s | 39s | 1.8× | $0.58 | $0.31 | 1.9× | 411K | 109K | 3 |
| Q02 · most connected | 23m 56s | 12s | 121× | $9.86 | $0.15 | 64× | 15.8M | 71K | 2 |
| Q03 · service dependents | 6m 36s | 18s | 22× | $1.81 | $0.19 | 9.8× | 2.7M | 73K | 2 |
| Q04 · rpc callers | 3m 19s | 24s | 8.3× | $1.13 | $0.19 | 6.0× | 1.2M | 98K | 1 |
| Q05 · field blast radius | 6m 27s | 21s | 18× | $9.00 | $0.22 | 41× | 16.8M | 107K | 4 |
| Q06 · request field change | 3m 24s | 1m 09s | 3.0× | $1.69 | $0.65 | 2.6× | 1.9M | 693K | 4 |
| Q07 · response provenance | 25s | 18s | 1.4× | $0.24 | $0.21 | 1.2× | 172K | 161K | 1 |
| Q08 · two hop lineage | 49s | 24s | 2.0× | $0.47 | $0.20 | 2.4× | 378K | 121K | 5 |
| Q09 · remove rpc | 8m 13s | 27s | 18× | $4.46 | $0.20 | 23× | 7.0M | 130K | 2 |
| Q10 · outbound dependencies | 53s | 22s | 2.4× | $0.49 | $0.19 | 2.7× | 473K | 84K | 6 |
| Q11 · transitive impact | 7m 18s | 16s | 28× | $1.97 | $0.13 | 15× | 3.4M | 68K | 2 |
| Q12 · call chain | 5m 09s | 8s | 39× | $1.55 | $0.076 | 20× | 2.0M | 62K | 1 |
| Q13 · non handler callers | 4m 59s | 28s | 11× | $8.70 | $0.20 | 44× | 17.1M | 100K | 1 |
| Q14 · api docs | 1m 54s | 22s | 5.3× | $1.06 | $0.23 | 4.6× | 1.3M | 127K | 3 |
| Q15 · dead rpcs | 2m 49s | 2m 41s | 1.1× | $0.97 | $0.51 | 1.9× | 1.1M | 502K | 4 |
| Q16 · pii flow | 7m 12s | 29s | 15× | $1.45 | $0.30 | 4.8× | 2.4M | 178K | 9 |
| Q17 · response consumers | 4m 43s | 25s | 11× | $2.48 | $0.31 | 8.1× | 3.5M | 164K | 4 |
| Q18 · handler fanout | 2m 32s | 36s | 4.2× | $0.34 | $0.39 | 0.9× | 261K | 372K | 2 |
| Q19 · domain dependencies | 2m 54s | 20s | 8.7× | $0.92 | $0.19 | 4.8× | 1.0M | 86K | 2 |
| Q20 · proto change repos | 2m 11s | 24s | 5.4× | $1.51 | $0.31 | 4.9× | 1.6M | 139K | 8 |
| All 20 prompts | 96m 55s | 10m 42s | 9.1× | $50.69 | $5.13 | 9.9× | 80.5M | 3.4M |
Sonnet 5.5 · xhigh effort: time to answer
Median wall-clock time of 2 runs per prompt (their mean), log scale. The figure at the right of each row is how many times faster the answer came with ProtoMap.
Sonnet 5.5 · xhigh effort: cost per answer
Median cost of 2 runs per prompt (their mean) at API prices, as Claude Code reports it, log scale.
Sonnet 5.5 · xhigh effort: table view
| Prompt | Baseline time | ProtoMap time | Faster | Baseline cost | ProtoMap cost | Cheaper | Baseline tokens | ProtoMap tokens | ProtoMap calls |
|---|---|---|---|---|---|---|---|---|---|
| Q01 · list services | 1m 29s | 42s | 2.1× | $0.46 | $0.20 | 2.2× | 781K | 175K | 4 |
| Q02 · most connected | 21m 57s | 57s | 23× | $5.03 | $0.27 | 19× | 22.6M | 210K | 12 |
| Q03 · service dependents | 1m 39s | 30s | 3.3× | $0.44 | $0.12 | 3.7× | 686K | 123K | 2 |
| Q04 · rpc callers | 2m 11s | 18s | 7.2× | $0.40 | $0.077 | 5.2× | 663K | 67K | 1 |
| Q05 · field blast radius | 4m 26s | 40s | 6.7× | $1.41 | $0.17 | 8.5× | 4.5M | 208K | 4 |
| Q06 · request field change | 1m 46s | 57s | 1.9× | $0.57 | $0.30 | 1.9× | 908K | 399K | 4 |
| Q07 · response provenance | 28s | 19s | 1.5× | $0.16 | $0.15 | 1.1× | 190K | 146K | 5 |
| Q08 · two hop lineage | 2m 29s | 35s | 4.3× | $0.41 | $0.24 | 1.7× | 656K | 293K | 8 |
| Q09 · remove rpc | 6m 24s | 2m 04s | 3.1× | $1.98 | $0.31 | 6.3× | 7.2M | 397K | 2 |
| Q10 · outbound dependencies | 1m 05s | 34s | 1.9× | $0.34 | $0.17 | 2.0× | 543K | 175K | 16 |
| Q11 · transitive impact | 5m 34s | 14s | 23× | $1.01 | $0.064 | 16× | 1.9M | 67K | 1 |
| Q12 · call chain | 7m 04s | 16s | 27× | $1.22 | $0.068 | 18× | 2.8M | 133K | 1 |
| Q13 · non handler callers | 6m 50s | 23s | 18× | $3.84 | $0.12 | 32× | 11.3M | 107K | 2 |
| Q14 · api docs | 2m 38s | 22s | 7.1× | $0.70 | $0.15 | 4.6× | 1.0M | 135K | 4 |
| Q15 · dead rpcs | 2m 47s | 39s | 4.2× | $0.49 | $0.24 | 2.0× | 893K | 337K | 5 |
| Q16 · pii flow | 3m 29s | 41s | 5.1× | $0.79 | $0.21 | 3.8× | 1.8M | 296K | 7 |
| Q17 · response consumers | 4m 26s | 27s | 9.8× | $1.22 | $0.18 | 6.8× | 2.7M | 152K | 4 |
| Q18 · handler fanout | 46s | 40s | 1.2× | $0.20 | $0.29 | 0.7× | 272K | 479K | 4 |
| Q19 · domain dependencies | 3m 29s | 19s | 11× | $0.85 | $0.094 | 9.0× | 2.0M | 72K | 1 |
| Q20 · proto change repos | 1m 37s | 39s | 2.5× | $0.54 | $0.26 | 2.1× | 900K | 194K | 22 |
| All 20 prompts | 82m 34s | 12m 15s | 6.7× | $22.05 | $3.68 | 6.0× | 64.3M | 4.2M |
Accuracy
Each answer scores the share of the facts it must state, such as every calling service, that it names. The facts come from
the fixtures' oracles (expected.json, written by the generator of the code, not by ProtoMap) and were checked by
hand where ProtoMap and the oracle disagreed; the agents could not read the oracles, which were moved out of the workspace.
Mean of 2 runs.
| Prompt | Opus 5.5 | Sonnet 5.5 | Facts graded | ||
|---|---|---|---|---|---|
| Baseline | ProtoMap | Baseline | ProtoMap | ||
| Q01 · list services | 100% | 100% | 100% | 100% | 110 |
| Q02 · most connected | 80% | 100% | 80% | 100% | top 10 |
| Q03 · service dependents | 100% | 100% | 100% | 100% | 16 |
| Q04 · rpc callers | 96% | 100% | 93% | 100% | 14 |
| Q05 · field blast radius | 100% | 100% | 100% | 100% | 12 |
| Q06 · request field change | 100% | 100% | 100% | 100% | 17 |
| Q07 · response provenance | 100% | 100% | 100% | 100% | 4 |
| Q08 · two hop lineage | 100% | 100% | 100% | 100% | 5 |
| Q09 · remove rpc | 100% | 100% | 100% | 100% | 17 |
| Q10 · outbound dependencies | 96% | 100% | 92% | 100% | 12 |
| Q11 · transitive impact | 100% | 100% | 100% | 100% | 18 |
| Q12 · call chain | 100% | 100% | 100% | 100% | 4 |
| Q13 · non handler callers | 100% | 100% | 100% | 100% | 25 |
| Q14 · api docs | 100% | 100% | 100% | 100% | 21 |
| Q15 · dead rpcs | 100% | 100% | 100% | 100% | 4 dead of 9 |
| Q16 · pii flow | 96% | 100% | 100% | 100% | 12 |
| Q17 · response consumers | 100% | 100% | 100% | 100% | 8 |
| Q18 · handler fanout | 100% | 100% | 100% | 100% | 6 |
| Q19 · domain dependencies | 100% | 100% | 100% | 100% | 43 |
| Q20 · proto change repos | 100% | 100% | 100% | 100% | 6 |
The prompts
Five are the chat panel's quickstart prompts with real names filled in; the other fifteen need several services, several repositories, or several protobuf messages to answer. Every prompt was given as written, after the same one-line preamble: Answer this question about the code in the current directory, which holds Acme's service repositories. Work read-only: do not modify any files. Be concise and exact: give full names, and file:line where asked.
- Quickstart Q01 List all the gRPC services implemented in the Swift repo (protomap-test-swift). Give the fully qualified name of each and how many RPCs it has.
- Quickstart Q02 Show the 10 most connected gRPC services across all our repos: the ones with the most distinct other services calling them or being called by them. Give the inbound and outbound service counts for each.
- Quickstart Q03 Which services depend on acme.loyalty.v1.LoyaltyMemberQueryService? For each dependent service, tell me which repo it lives in and which RPCs it calls.
- Quickstart Q04 Which services call acme.customers.v1.CustomerService/ListCustomers? List every call site with file:line and the enclosing function, across all repos.
- Quickstart Q05 What is the blast radius of changing acme.ledger.v1.LedgerAccount.currency_code? Which services actually use this field's data (read it and pass it along to another RPC or into a response), and through which RPCs?
- Cross-service Q06 We're replacing the `customer` field of acme.customers.v1.UpdateCustomerRequest with a new message. Which code, in which repos, sets that field when calling acme.customers.v1.CustomerService/UpdateCustomer, and to which other RPCs does the UpdateCustomer handler pass the field on?
- Cross-service Q07 Where does the `cart` in the response of acme.cart.v1.CartCalculationService/SimulateCart come from? Trace it back to the upstream RPC responses or request fields it is built from.
- Cross-service Q08 Trace the `payout` field of acme.payments.v1.SchedulePayoutExpiryRequest two hops downstream: which RPCs does the SchedulePayoutExpiry handler send it to, and where do the handlers of those RPCs send it next? Name the services and repos at each hop.
- Cross-service Q09 We want to remove the RPC acme.documents.v1.DocumentQueryService/ResolveDocuments. Find every place in every repo that calls it, including indirect calls through helpers, method names built from strings, registries, or reflection, and give file:line and the calling service for each so we can migrate them.
- Cross-service Q10 What does acme.payments.v1.PaymentCalculationService depend on? List every downstream service it calls, which RPCs, and which repo owns each downstream service.
- Cross-service Q11 If acme.pricing.v1.PriceListQueryService goes down, which services are affected? Include direct callers and services that depend on it transitively through the RPCs that call it, up to 3 hops away, and say how many hops away each one is.
- Cross-service Q12 Can a request to acme.ticketing.v1.TicketTransferWorkflowService end up calling acme.ledger.v1.LedgerAccountValidationService? Show the shortest call chain hop by hop: the RPC called at each hop, and the repo and file:line where each call is made.
- Cross-service Q13 Which code outside of gRPC handlers (event workers, batch jobs, CLIs, server startup) calls the ledger services (acme.ledger.v1.*)? List each caller, its repo, and the ledger RPCs it calls.
- Cross-service Q14 Write API reference docs for acme.giftcards.v1.GiftCardService: for each RPC, its request and response messages, the file that implements it, and which services call it.
- Cross-service Q15 Which RPCs of acme.checkout.v1.CheckoutSessionService are never called by any code in any of our repos? We want to delete dead endpoints, so don't list an RPC that is actually called somewhere. End your answer with one line of the form `UNUSED: <comma-separated RPC names>`.
- Cross-service Q16 For a privacy review: which services' code actually reads a patient's national ID (acme.patients.v1.Patient.national_id) and passes it on, and through which RPCs does it travel?
- Cross-service Q17 If acme.customers.v1.CustomerCalculationService/ExplainCustomerCalculation stopped returning the `result` field of its response, which callers would be affected? For each caller, which RPC requests or responses does that data flow into?
- Cross-service Q18 What does the handler of acme.shipping.v1.ShipmentCalculationService/CalculateShipment call downstream, and which fields of its request end up in each downstream call?
- Cross-service Q19 Which other domains does the checkout domain (acme.checkout.v1) call into, and which domains call checkout? Summarize the dependencies in both directions.
- Cross-service Q20 We're making a breaking change to the acme.subscriptions.v1 protos. Which repos call or implement subscriptions services and would need to update and redeploy? For each repo, which subscriptions services does it use?
The codebase
Acme's nine repositories, generated from one catalog of APIs and each in a different language, call each other's services
and copy each other's protobuf files, as an enterprise's do. Their code moves data through patterns that are hard to follow
statically: method paths built from strings, registries, reflection, futures, callbacks, event buses, and framework dispatch.
The indexing time is a fresh protomap scan of each repository on one machine.
| Repository | Language | Lines (tracked) | Services | Calls | Field flows | Index time |
|---|---|---|---|---|---|---|
| protomap-test-csharp | C# | 400,958 | 340 | 7,653 | 27,397 | 5 s |
| protomap-test-golang | Go | 2,590,754 | 480 | 6,923 | 37,747 | 9 s |
| protomap-test-java | Java | 590,063 | 400 | 6,027 | 32,215 | 4 s |
| protomap-test-javascript | JavaScript | 166,210 | 180 | 2,567 | 13,730 | 3 s |
| protomap-test-kotlin | Kotlin | 235,041 | 190 | 4,420 | 15,542 | 2 s |
| protomap-test-python | Python | 298,060 | 240 | 3,726 | 19,177 | 5 s |
| protomap-test-rust | Rust | 242,115 | 150 | 1,996 | 10,883 | 2 s |
| protomap-test-swift | Swift | 152,493 | 110 | 1,974 | 9,690 | 2 s |
| protomap-test-typescript | TypeScript | 314,723 | 290 | 4,226 | 22,873 | 4 s |
| All nine | 7 languages + protobuf | 4,990,417 | 2,380 | 39,512 | 189,254 | 35 s |
4.99M tracked lines: 1.64M of service code, 1.23M of protobuf (each repository holds copies of the files of the services it calls), and 2.12M of generated Go bindings, which the Go repository checks in. Calls and flows are the oracles' counts of call sites and field-level dataflows the code makes.
How it was run
- Each run is a fresh
claude -psession (Claude Code 2.1.306) in~/protomap-test, which holds only the nine repositories, with nothing the agents could take answers from: the fixtures' answer keys, build outputs, and other projects were moved out for the runs. - Both arms have the same read-only tools: Read, Grep, Glob, subagents, and read-only shell commands (rg, grep, find, git grep, awk, jq, and the like); anything else is denied. The ProtoMap arm adds the ProtoMap MCP server (Streamable HTTP, the shared graph of the nine repositories); the baseline arm has no MCP servers.
- User settings, CLAUDE.md files, and hooks were left out (
--setting-sources project,local) so nothing but the prompt differs between runs. - Opus 5.5 ran at high effort and Sonnet 5.5 at extra-high effort. Every prompt ran twice per model and arm (160 runs; a third round was cut short by usage limits and discarded); the charts show the median, which for two runs is their mean, and accuracy is the mean.
- Time is wall-clock time of the whole session; cost and tokens are what Claude Code reports at API prices, subagents and cache reads included. A run is stopped after 45 minutes and counts its 45 minutes and the cost it had reached.
- Grading is by code, with no model as judge: each answer must name the services, methods, repositories, or fields of its prompt's answer key (by full or short name, or the file its implementation is in). The dead-RPC prompt scores the F1 of the list the answer ends with, so a wrong RPC costs as much as a missed one.
Total spend across all runs at API prices: $163.11.
Stop wasting tokens on discovery.
Install the self-hosted ProtoMap platform and CLI scanner for free, and give your engineers and agents org-wide context.