Agent skill

Keybase RPC Log Analysis

by keybase in keybase/client

Captures a clean Keybase service log and analyzes it for redundant, duplicated or looping RPCs, then checks whether a caching fix reduced the calls.

BSD-3-ClauseAuto-check passedDevelopment

Install Keybase RPC Log Analysis

skills CLI
$ npx skills add keybase/client --skill keybase-rpc-log-analysis -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install keybase/client keybase-rpc-log-analysis --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/keybase/client.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skill/keybase-rpc-log-analysis .claude/skills/keybase-rpc-log-analysis && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
keybase-rpc-log-analysis
GitHub stars
9.3k
Token cost
~3k tokens
SKILL.md length
1,724 words
Files
8 (incl. scripts)
Skills in repo
14
Repo updated
First seen
Licence
BSD-3-Clause

At a glance

Captures a clean Keybase service log and analyzes it for redundant, duplicated or looping RPCs, then checks whether a caching fix reduced the calls.

  • Hunting redundant or looping RPCs after a rate-limit error
  • SKILL.md covers Capture a clean run, Prove a fix, Read it and What a bug looks like, plus 2 more sections
  • Runs Python and Shell scripts from its folder; calls yarn, git and python3
  • Investigating a service log that rotates every few minutes

What it does

The Go service logs every RPC it serves and every call it makes, so its log is where the client's real network behavior shows. The skill captures a clean run with scripts that archive old logs and start a locally built service, writing to its own file under /tmp/kb-analysis so a flood of entries cannot rotate the evidence away. It then drives the desktop app with a focused end-to-end flow set instead of the full suite, which would double every count.

Log files still rotate at 128MB, so the report script is given all the sibling files together. Other bundled Python scripts report RPC cost, diff two runs and trace why a call was made. The skill warns that the service needs kbfs built beside it, or the Files tab stays empty and files and git tests fail for unrelated reasons, and it tells the agent to ask before stopping the service or launching the app.

When your agent uses it

  • Hunting redundant or looping RPCs after a rate-limit error
  • Investigating a service log that rotates every few minutes
  • Proving that a caching change cut the number of calls
  • Diagnosing a slow or hot desktop app

Example prompts

  • “Capture a clean service log and report which RPCs are called most.”
  • “Compare the RPC counts before and after my caching change.”
  • “Why does the service log rotate every few minutes? Find the flood.”

Requirements

  • A Keybase client checkout with a locally built service
  • yarn, to start the desktop app
  • Python 3

What it can do on your machine

Read from SKILL.md and the folder at commit 81e93d6. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships 7 files in scripts/ (Python and Shell), which the agent can run.

    Shell commands in SKILL.md call:

    • yarn
    • git
    • python3
    • go

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md. Its commands use yarn and git, which can reach the network depending on how they are called.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Keybase RPC Log Analysis loads about 3k tokens when it runs. Until then it costs about 82 tokens; SKILL.md has 1,724 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~82
When it runs · the whole SKILL.md, loaded when a task matches
~3k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.

SKILL.md

The full file from keybase/client at commit 81e93d6, republished under its BSD-3-Clause licence (© keybase). 1,724 words, ~3,025 tokens.

Download SKILL.mdSave it as .claude/skills/keybase-rpc-log-analysis/SKILL.md (or your agent's skills folder). This skill also uses 7 other files; get the full folder from GitHub.
name
keybase-rpc-log-analysis
description
Use when hunting redundant, duplicated or looping RPCs in the Keybase client — after a rate-limit error, a service log that rotates every few minutes, a slow or hot app, or to prove a caching fix actually reduced calls. Covers capturing a clean service log against a locally built service and reading it.

Keybase RPC log analysis

The Go service logs every RPC it serves and every call it makes. That log is the only place the client's real network behaviour is visible — the JS side shows intent, the log shows what actually went out. A quiet minute is ~45 lines; a minute with a flood is 120,000.

Capture a clean run

bash
skill/keybase-rpc-log-analysis/scripts/clean-logs.sh --archive   # dry run without a flag
skill/keybase-rpc-log-analysis/scripts/start-service.sh          # own terminal, foreground
cd shared && yarn desktop:start:hot:e2e                          # another terminal
cd shared && yarn test:e2e:desktop:rpc                           # or drive the app by hand

start-service.sh builds from this checkout, stops the running service, and logs with -d --log-file to /tmp/kb-analysis/service.log. Its own file matters: the default log is shared with everything else and a flood rotates the evidence away in under two minutes.

Use test:e2e:desktop:rpc, not test:e2e:desktop. The full suite is 6.6 minutes over two projects (light and dark), which doubles every count and makes the log rotate. test:e2e:desktop:rpc is the six flows that actually drive team and channel loading, on one project, in 39 seconds. test:e2e:desktop:flows takes file arguments if you need a different set — always pass a single --project (it does), or light and dark each contribute a copy of every call.

--log-file still rotates at 128MB — a full e2e run produces ~135MB and will cross it. Nothing is lost, but the analysis must then include the siblings, so pass them all:

bash
python3 skill/keybase-rpc-log-analysis/scripts/rpc-report.py \
  /tmp/kb-analysis/service.log-* /tmp/kb-analysis/service.log

Rotation is easy to miss: a script that reads only service.log after a long run silently analyses the tail. Check ls -la /tmp/kb-analysis/ before believing a count.

The service forks kbfs from its own bin directory, and a plain go install of the service does not build it. Without kbfs the Files tab is empty and git fails with KBFS client not found, which fails every files-* and git-* e2e test for reasons unrelated to the change under test. start-service.sh warns. Note the installed kbfs keeps the mount when the service is swapped for a local build, so those tests can fail even with a kbfs binary in place — they are not in the test:e2e:desktop:rpc set for that reason.

Ask before stopping the service or launching the app — both are the user's.

Prove a fix

A before/after is only worth reporting if both runs did the same thing. What works:

bash
# after: with the fix in the tree
<reload the renderer>; : > /tmp/kb-analysis/service.log
cd shared && yarn test:e2e:desktop:rpc
cp /tmp/kb-analysis/service.log /tmp/kb-analysis/after.log

# before: revert ONLY the source changes, keeping any new test scripts
git stash push -- <the source files you changed>
<reload the renderer>; : > /tmp/kb-analysis/service.log
cd shared && yarn test:e2e:desktop:rpc
cp /tmp/kb-analysis/service.log /tmp/kb-analysis/before.log
git stash pop
  • Stash by path, not wholesale. If the fix added the very npm script the capture runs, a bare git stash takes it with them.
  • Hard-reload the renderer between runs (CDP page.reload() on localhost:9222). Module-level caches — the usual subject of these fixes — survive HMR, so without a reload the second run starts warm and reads better than it is.
  • The service does not need rebuilding between runs for a JS-only fix. Leave it up; only truncate its log.
  • Counting straight out of the log beats rpc-diff.py when you already know which calls you are watching: parse + Server: <Name> / + RemoteClient: chat.1.remote.<name>, and count how many landed within the hook's own staleMs of the previous call for the same subject. That last number is the one that says "this was a cache miss" rather than "this was work".

Read it

QuestionCommand
What did this run do?rpc-report.py <log> [--start 2026-07-24T17:23] [--end ...]
What was actually slow?rpc-cost.py <log> [--min-mean-ms 50]
Why is X called so much?rpc-why.py <log> --match 'AttachmentHTTPSrv: GetURL'
Did my fix work?rpc-diff.py before.log after.log

Run rpc-cost.py early. Count and cost answer different questions, and the loudest line in the log is usually not the expensive one. In one capture the top line by count was an in-memory map lookup — 15,767 calls for 0.16s total, not worth touching — while the real cost was 469 team loads at 292ms each, 186 seconds, sitting 30th by count.

To prove a loud flood is free rather than just absent from the table, pass --min-mean-ms 0 --top 400: the default threshold hides cheap chatty ops, which is exactly the row you need. AttachmentHTTPSrv: GetURL at 4,848 calls does not appear at all by default, and shows as 0.04s total once it does.

Analysing an already-rotated log is the same — pass ~/Library/Logs/keybase.service.log-<start>-<end> directly. The filename carries its own window, so --start/--end are only for narrowing further.

Read rpc-report.py's sections in order:

  • REMOTE — service→server. Only these burn server rate limits. Start here.
  • APP — app→service. One of these usually explains a REMOTE row.
  • BURSTS — same call and subject, 3+ times in one second. Each row is a missing cache or a remounting component.
  • FLOODS — most repeated lines, ids and numbers collapsed.

A BURSTS row with a bare name and no (subject) means the subject could not be resolved: many RPCs log no arguments. Those rows are same-name only — treat them as a lead, not as proof the same conversation was hit twice.

rpc-why.py answers attribution. ROOT (the app RPC that opened the trace) is usually the answer; DRIVERS (nearest preceding call) points at the specific line. BATCHES needs the span that logs the item count, which is normally the local one, not the remote it wraps — match HybridConversationSource: GetMessages, not getMessagesRemote. The script says so when it finds no counts.

What a bug looks like

  • Same args, same second, N times → no dedupe, or a keyed component remounting as its props arrive in stages.
  • Fires again the instant the previous lands → a feedback loop, not user action. Look for a cache that never records success, or an effect whose deps change on every render.
  • Batch sizes almost all 1 → the caller loops where it could fetch once.
  • A per-item cost inside a loop → e.g. a gregor state read per emoji.
Show full SKILL.md (832 more words)Show less

Mistakes

  • Guessing the trigger from neighbouring lines. A burst surrounded by startup-looking work is not necessarily startup. Correlate against something independent: the mtimes of shared/tests/results/test-results/*/test-finished-1.png give you a timestamped list of which test ran when, and app.log records renderer reloads. One burst-per-profile-open and one burst-per-bootstrap look identical in the service log until you check.
  • Attributing to the child call. The line directly above a flood is often something the flood itself invoked. Trust ROOT over DRIVERS.
  • Reading a count that went to zero as a win. A call that disappears may have been dropped, not deduped. Before claiming it, check what the baseline calls actually did: pull their chat-trace out of the before-log and count the work hanging off it. Two getMutualTeamsLocal calls here went to 0 after a guard on "empty argument list" — and their traces showed 82 remote refreshes and 750ms each, so the service treats the empty case as a real query and the guard was removing a feature, not a redundancy. A real dedupe takes N to 1, not to 0.
  • Forgetting that one call's result is another call's input. Suppressing a call suppresses everything downstream of it, so an unrelated-looking count improves for the wrong reason. getAnnotatedTeam read 3 in the run where mutual teams was wrongly suppressed and 11 in both runs where it was not — because the shared teams it returns are what then get loaded. If a metric you did not touch moves, find out which call upstream stopped happening.
  • Reading a fix as failed because the totals did not move. If the app's request volume changed between runs, a working cache can show flat server counts. Count what the cache actually did — a hit rate, a log line — before concluding anything. One cache here looked useless in one capture and turned out to be a 79% reduction once the volume feeding it was fixed.
  • Fixing what you have not measured. Two of the loudest floods in this log — 15,767 username lookups and 7,284 chain-storage misses — were worth 0.16s and 0.24s. Both were correctly left alone. rpc-cost.py first.
  • Blaming the biggest number. Service-side background work — the search indexer especially — can dwarf the real bug. An empty ROOT means nothing asked for it. Check whether it recurs on a timer before spending time on it.
  • Reporting a burst as same-subject when it is not. See the BURSTS caveat above. If it matters, prove the subject repeats before claiming it.
  • Comparing unlike runs. rpc-diff.py is only meaningful if both runs did the same thing — same tests, same order, same project, renderer reloaded between them. See "Prove a fix".

Shapes seen before

Each of these was a real bug, and each is what its section looks like:

  • An app RPC in the thousands where the screen has tens of items — a per-item prime re-run on every list reload.
  • A local call in the low single digits dragging thousands of lines behind it — a per-item cost inside a server-side loop.
  • FLOODS dominated by one span whose BATCHES are almost all size 1.
  • An APP row whose count is a multiple of the number of times a screen was opened — a component keyed on data that arrives in stages, remounting.
  • A list row eagerly loading what only its hover popup needs. The single biggest win here was one loadOnDemand flag: a profile rendered a row per team and each row annotated its team up front, for a popup nobody opened.
  • A hook that subscribes to a broadcast per component instance. One notification then does N times the work, and if the work itself emits that notification it compounds. Subscribe once at module scope and fan out.
  • The same expensive load repeated because each surface holds its own copy. Two or three components asking for the same user or team at the same instant is the common case, not the rare one.
  • Two identical calls the same microsecond apart. Not a race — two caches. Either the hook falls back to a per-instance map (so every provider and every provider-less consumer holds its own), or two different hooks issue the same RPC with the same arguments from separate module caches and cannot see each other's in-flight request. Both were live in this client at once. Grep the codebase for the RPC name: more than one call site that is not a shared hook is the tell.
  • Calls landing inside their own stale window. If a hook declares staleMs: 5_000 and most of its calls arrive under 5s after the previous one for the same subject, the cache is not being shared — the window is doing nothing because each caller has a fresh copy of it. This ratio is the single most useful derived number here; 81% for getAnnotatedTeam is what found that bug.

Where the money actually is in this client: identify/proof checks and team loads. Both are hundreds of milliseconds each and both fan out to several HTTP calls. Chat localization is cheap per call but runs over every channel.

© keybase, BSD-3-Clause. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 7 other files (scripts) in skill/keybase-rpc-log-analysis of keybase/client.

  • SKILL.md
  • scripts/clean-logs.sh
  • scripts/kblog.py
  • scripts/rpc-cost.py
  • scripts/rpc-diff.py
  • scripts/rpc-report.py
  • scripts/rpc-why.py
  • scripts/start-service.sh

Open the folder on GitHubat commit 81e93d6

Compare with similar skills

Keybase RPC Log Analysis next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Keybase RPC Log Analysis compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Keybase RPC Log Analysis this skillkeybase/client9.3k—~3kAutomated safety check: PassBSD-3-Clause
Content-Hash File Cache Patternaffaan-m/ECC274k5 repos~1.4kAutomated safety check: PassMIT
Flowfile Debugging PlaybookEdwardvaneechoud/Flowfile370—~6.3kAutomated safety check: PassMIT
Writing Streamlit AppsPostHog/posthog-foss721—~1.5kAutomated safety check: PassMIT
Python Performance Optimizationwshobson/agents40k12 repos~814Automated safety check: PassMIT
The Art of Debuggingstas00/the-art-of-debugging1.7k—~6.1kAutomated safety check: NotesCC-BY-SA-4.0

Similar skills

  • Caches slow file processing results in Python keyed by a SHA-256 hash of the file content, so renames still hit the cache and edits invalidate it automatically.

    274k GitHub starsUsed in 5 repos~1.4k tokens
    DevelopmentAuto-check passed
  • Flowfile Debugging Playbook

    Edwardvaneechoud/Flowfile

    Symptom-to-cause triage playbook for Flowfile (core/worker/kernel/frontend/AI) — covers "no such table" DB cascades (two distinct causes), import-time Alembic migration corruption, silent…

    370 GitHub stars~6.3k tokensUpdated yesterday
    DevelopmentAuto-check passed
  • Writing Streamlit Apps

    PostHog/posthog-foss

    Official

    Write Streamlit app source code that runs well in a PostHog sandbox — the posthogapps.query() bridge for reading PostHog data, the packages baked into the sandbox image, caching and session state…

    721 GitHub stars~1.5k tokensUpdated today
    DevelopmentAuto-check passed
  • Profiles slow Python code with cProfile and memory profilers, then applies targeted fixes for CPU, memory, I/O and query bottlenecks.

    40k GitHub starsUsed in 12 repos~814 tokens
    DevelopmentAuto-check passed
  • The Art of Debugging

    stas00/the-art-of-debugging

    Condensed debugging method and tool recipes for Unix, Python and PyTorch programs: crashes, hangs, segfaults, wrong output, CUDA OOM, NaN values and slowness.

    1.7k GitHub stars~6.1k tokensUpdated yesterday
    DevelopmentAuto-check: notes
  • Climber Step Minimization

    ben-manes/caffeine

    Prices each step of the window climber algorithm by disabling it in turn, to find steps that no longer earn their keep and branches that no longer fire.

    18k GitHub stars~3k tokensUpdated yesterday
    DevelopmentAuto-check: notes

More from keybase/client

All 14 skills in this repo
  • Analyzes V8, Chrome and Electron .heapsnapshot files with Node scripts to find memory leaks, detached DOM nodes and the retainer paths that keep objects alive.

    9.3k GitHub stars~875 tokensUpdated today
    Auto-check passed
  • Analyzes Chrome or Electron DevTools Performance trace exports with Python scripts to find where render time actually goes, without opening DevTools.

    9.3k GitHub stars~809 tokensUpdated today
    Auto-check passed
  • Parses a React DevTools Profiler JSON export with Python scripts to find re-render storms, commit fan-out and why a component rendered, without opening the DevTools UI.

    9.3k GitHub stars~978 tokensUpdated today
    Auto-check passed
  • Address PR Feedback

    keybase/client

    Fetches GitHub Copilot review feedback from inline threads and review bodies, checks each finding against the code and fixes the valid ones.

    9.3k GitHub stars~657 tokensUpdated today
    Auto-check passed
  • Takes a screenshot of a running Electron desktop app through playwright-cli over remote debugging, shrinks it and shows it so you can check the UI visually.

    9.3k GitHub stars~476 tokensUpdated today
    Auto-check passed
  • Guides writing and fixing end-to-end flow tests for the Keybase app on desktop with Playwright and on iOS with Appium and WebdriverIO, sharing one testID registry.

    9.3k GitHub stars~1.2k tokensUpdated today
    Auto-check passed

Works with

Questions about Keybase RPC Log Analysis

What does Keybase RPC Log Analysis do?

Captures a clean Keybase service log and analyzes it for redundant, duplicated or looping RPCs, then checks whether a caching fix reduced the calls. The Go service logs every RPC it serves and every call it makes, so its log is where the client's real network behavior shows. The skill captures a clean run with scripts that archive old logs and start a locally built service, writing to its own file under /tmp/kb-analysis so a flood of entries cannot rotate the evidence away.

When should I use Keybase RPC Log Analysis?

Keybase RPC Log Analysis fits situations like: hunting redundant or looping RPCs after a rate-limit error; investigating a service log that rotates every few minutes; proving that a caching change cut the number of calls; diagnosing a slow or hot desktop app.

How do I install Keybase RPC Log Analysis in Claude Code?

Run `npx skills add keybase/client --skill keybase-rpc-log-analysis -a claude-code`. Or copy the skill folder (skill/keybase-rpc-log-analysis in keybase/client) into .claude/skills/keybase-rpc-log-analysis in your project. Claude Code loads it when a task matches its description.

How do I install Keybase RPC Log Analysis in Codex?

Run `npx skills add keybase/client --skill keybase-rpc-log-analysis -a codex`. Or copy the skill folder (skill/keybase-rpc-log-analysis in keybase/client) into .agents/skills/keybase-rpc-log-analysis in your project. Codex loads it when a task matches its description.

Can I use Keybase RPC Log Analysis in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add keybase/client --skill keybase-rpc-log-analysis -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/keybase-rpc-log-analysis, .gemini/skills/keybase-rpc-log-analysis, .github/skills/keybase-rpc-log-analysis and .opencode/skills/keybase-rpc-log-analysis in your project.

What does Keybase RPC Log Analysis need to run?

Going by SKILL.md and its folder, Keybase RPC Log Analysis needs Python and a shell for the scripts in its folder and the command-line tools its instructions call (yarn, git, python3 and go). Our summary lists: A Keybase client checkout with a locally built service; yarn, to start the desktop app; Python 3.

Does Keybase RPC Log Analysis access the network?

SKILL.md contains no URLs. Its commands use git, which can reach the network depending on how they are called. This is read from the text; nothing was executed.

Is Keybase RPC Log Analysis safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.

What licence does Keybase RPC Log Analysis use?

Keybase RPC Log Analysis is published under the BSD-3-Clause licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Keybase RPC Log Analysis use?

About 3k tokens (SKILL.md is roughly 12k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Keybase RPC Log Analysis?

Skills that share tags, products or a category with Keybase RPC Log Analysis: Content-Hash File Cache Pattern (affaan-m/ECC, 274k stars), Flowfile Debugging Playbook (Edwardvaneechoud/Flowfile, 370 stars), Writing Streamlit Apps (PostHog/posthog-foss, 721 stars) and Python Performance Optimization (wshobson/agents, 40k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Keybase RPC Log Analysis?

keybase (a GitHub organization) maintains it in keybase/client, which has 9,257 GitHub stars. The repository holds 14 skills in this directory. The repository was last updated on October 7, 2026.

Source: keybase/client on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.