Skip to main content
skill CX Codex

lsp-concurrency-audit — Claude Code skill: audit and install

This skill checks how a type’s or file’s fields are accessed across concurrent contexts and produces a safety report. Use it before refactoring or when investigating possible data races.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add blackwell-systems/agent-lsp --skill lsp-concurrency-audit -a claude-code
Open on GitHub

What lsp-concurrency-audit does

The skill uses LSP to collect types and fields, inspect calling methods, and trace calls across concurrency boundaries. For each field, it reports synchronization, concurrent readers and writers, then assigns a status and severity. Audit a whole file or narrow the check with --type <TypeName>.

The agent-lsp MCP server is required. Boundary detection is heuristic, so indirect calls through callbacks can be missed. A mutex on a type does not prove that every method acquires it; external locking may also be reported as unsafe. Check the report against the code before treating a field as protected.

What it helps with

  • find fields accessed from concurrent contexts
  • flag fields with concurrent writes as race candidates
  • trace methods called from goroutines or threads
  • review field synchronization before refactoring

Example prompts for the agent

  • Check concurrent access in internal/server.go with /lsp-concurrency-audit internal/server.go.
  • Audit only the Session type in server.go: /lsp-concurrency-audit server.go --type Session.
  • Inspect cache.go for possible races and report concurrent readers and writers: /lsp-concurrency-audit cache.go.

How to install lsp-concurrency-audit

1Skills CLI (Vercel)

npx skills add blackwell-systems/agent-lsp --skill lsp-concurrency-audit -a claude-code

2Manually: put the files in place

~/.claude/skills/lsp-concurrency-audit/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/lsp-concurrency-audit/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about lsp-concurrency-audit

How do I install lsp-concurrency-audit in Claude Code?

Run npx skills add blackwell-systems/agent-lsp --skill lsp-concurrency-audit -a claude-code. The skill file is located at ~/.claude/skills/lsp-concurrency-audit/SKILL.md.

What does lsp-concurrency-audit do?

It checks field access across concurrent contexts and reports readers, writers, and synchronization status for each field.

Does the audit verify that every method acquires a lock?

No. It checks whether the type has a synchronization primitive, but does not verify lock acquisition at every field access. Concurrent-boundary and read/write detection are heuristic.

Source text

SKILL.md · MIT
---
name: lsp-concurrency-audit
description: Concurrency safety audit for a type or file. Maps all fields, traces which are accessed from concurrent contexts (goroutines, threads, async tasks), and flags fields that lack synchronization. Produces a field-level safety report. Language-agnostic across 4 concurrency families.
argument-hint: "<file-path> [--type <TypeName>]"
user-invocable: true
allowed-tools: mcp__lsp__start_lsp mcp__lsp__open_document mcp__lsp__blast_radius mcp__lsp__find_callers mcp__lsp__list_symbols mcp__lsp__get_symbol_source mcp__lsp__find_references
license: MIT
compatibility: Requires the agent-lsp MCP server (github.com/blackwell-systems/agent-lsp)
metadata:
  required-capabilities: documentSymbolProvider referencesProvider
  optional-capabilities: callHierarchyProvider
---

> Requires the agent-lsp MCP server.

# lsp-concurrency-audit

Given a type or file, map all fields, identify which are accessed from multiple
concurrent contexts, and flag fields that lack synchronization. Produces a
field-level concurrency safety report.

## When to Use

- Before refactoring a type that is accessed from goroutines/threads
- Auditing a codebase for data race candidates
- Reviewing a PR that adds concurrent access to an existing type
- Understanding which fields in a type need mutex protection

## Input

```
/lsp-concurrency-audit <file-path> [--type <TypeName>]
```

If `--type` is provided, audit only that type. Otherwise, audit all types in
the file that have concurrent callers.

## Step 1: Discover types and fields

Call `list_symbols` on the target file to enumerate all types (structs, classes):

```
mcp__lsp__list_symbols({ "file_path": "<target>" })
```

For each type (kind=23 struct, kind=5 class), collect:
- Type name
- All fields (children with kind=8 field or kind=7 variable)
- Whether any field's name or detail contains sync primitives
  ("Mutex", "RWMutex", "Lock", "Semaphore", "atomic", "Atomic", "sync.",
  "pthread_mutex", "std::mutex")

If `--type` was specified, filter to that type only.

## Step 2: Blast radius and sync-guarded status

Call `blast_radius` on the file:

```
mcp__lsp__blast_radius({
  "changed_files": ["<target>"],
  "scope": "all"
})
```

From the result, for each method on each target type:
- Record `sync_guarded: true/false` from the response
- Record `non_test_callers` count (blast radius)
- Record `test_callers` count

## Step 3: Trace concurrent boundaries

For each method on each target type, call `find_callers` with
`cross_concurrent: true`:

```
mcp__lsp__find_callers({
  "file_path": "<target>",
  "line": <method_line>,
  "column": <method_column>,
  "direction": "incoming",
  "cross_concurrent": true
})
```

Record for each method:
- `concurrent_callers`: list of callers that cross concurrent boundaries
- `pattern`: the concurrent entry pattern detected (e.g., "go func(", "Thread.start(")

## Step 4: Classify fields

For each field in each type, determine its safety status:

**SAFE:** The type is sync-guarded (has a mutex/lock field) AND all methods
that access this field acquire the lock before access. Confidence: verified
if the type has a sync primitive; suspected if relying on external locking.

**UNSAFE (data race candidate):** The field is accessed by methods that have
`concurrent_callers` AND the type has no sync primitive. This is a potential
data race.

**WRITE-CONCURRENT:** The field is written by a method that has concurrent
callers. Higher severity than read-only concurrent access.

**READ-ONLY:** The field is only read (not written) from concurrent contexts.
Lower severity; often safe but worth flagging for review.

Severity assignment:
- `error`: UNSAFE + WRITE-CONCURRENT (probable data race)
- `warning`: UNSAFE + READ-ONLY (potential race under high concurrency)
- `info`: SAFE (sync-guarded, for documentation)

## Step 5: Output

```markdown
## Concurrency Audit: <TypeName>

**File:** <file_path>
**Fields:** N total, M sync-guarded
**Concurrent methods:** K (methods called from goroutines/threads/tasks)

### Field Safety Report

| Field | Type | Sync | Concurrent Writers | Concurrent Readers | Status |
|-------|------|------|-------------------|-------------------|--------|
| mu | sync.RWMutex | (is sync) | - | - | SYNC PRIMITIVE |
| sender | NotificationSender | guarded | 2 (SetSender, Send) | 3 | SAFE |
| subscribers | []Subscriber | none | 1 (Subscribe) | 2 | UNSAFE (write-concurrent) |

### Concurrent Call Sites

For each UNSAFE field, list the concurrent callers:

- `subscribers` written by `Subscribe` called from:
  - `setupNotificationHub` via `go func()` at notifications.go:45
  - `handleNewSession` via `go func()` at server.go:312

### Recommendations

- Add `sync.RWMutex` to protect `subscribers` field
- Or: use channel-based access pattern instead of direct field mutation
```

## Caveats

1. **Heuristic detection.** Concurrent boundary detection relies on source
   pattern matching, not runtime analysis. False negatives are possible when
   concurrent entry is indirect (e.g., passed as a callback to a framework).

2. **Lock discipline not verified.** The audit checks whether a sync primitive
   exists on the type, not whether every method actually acquires it before
   field access. A type with a mutex but inconsistent locking will show as
   SAFE when it may not be.

3. **External synchronization invisible.** If synchronization is provided by
   an external lock (e.g., the caller holds a lock before calling the method),
   the audit will flag the field as UNSAFE. Add a comment or annotation to
   suppress.

4. **Read vs write detection is heuristic.** Determining whether a method
   reads or writes a field requires source code analysis. The skill reads the
   method body and looks for assignment patterns (`field =`, `field.Store()`,
   `append(field,`). False positives are possible for complex access patterns.

© blackwell-systems · MIT · blackwell-systems/agent-lsp

Similar skills

All skills for Code review and refactoring →

From the same set25

lsp-explore Inspect a symbol’s definition, type details, implementations, callers, and references in one report. Useful when you’re finding your way around an unfamiliar codebase. CX Codex +1 ★ 165repo stars lsp-edit-symbol Changes a function, type or variable by name when you don't know the file or position. Runs on the agent-lsp MCP server. CX Codex +1 ★ 165repo stars lsp-edit-export A guided workflow for editing exported symbols and public APIs. It finds every caller via LSP, pauses for explicit confirmation, and verifies the build. CX Codex +1 ★ 165repo stars lsp-docs This skill looks up symbol details through LSP, local toolchain docs, then source code. Use it when hover has little to show or a dependency is not indexed. CX Codex +1 ★ 165repo stars lsp-dead-code The skill lists exported symbols in a file and checks each one for references across the workspace. Useful when you want to know which exports are safe to drop. CX Codex +1 ★ 165repo stars lsp-cross-repo Locates callers of a library symbol across consumer repositories via LSP. Useful when preparing to refactor or remove shared code without breaking dependents. CX Codex +1 ★ 165repo stars lsp-architecture Produces a structural overview of a repository: languages, packages, entry points, dependency flow and hotspot files. One call instead of a manual sweep. CX Codex +1 ★ 165repo stars agent-lsp Coordinates language servers into 65 agent tools across 32 languages, keeping project indexes warm and testing edits in memory. CX Codex +1 ★ 165repo stars

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor