smithery/dropseed

plain-optimize

Captures and analyzes performance traces to identify slow queries and N+1 problems. Use when a page is slow, there are too many queries, or the user asks about performance.

Installation

$ npx skills add smithery/dropseed --skill plain-optimize

Similar popular skills

Related neighbors and high-traction skills in the same topics — useful to compare before installing.

Also in this package

Other skills from smithery/dropseed.

npx skills add smithery/dropseed

Browse all from smithery/dropseed

More details

Agent compatibility

Declared targets from SKILL.md / docs. Unmarked agents are not listed — the skill may still install via the CLI.

Claude Code Not declared
Cursor Declared
Codex Not declared
GitHub Copilot Not declared
Windsurf Not declared
Gemini CLI Not declared
Cline Not declared
OpenCode Not declared

Skill metadata

Parsed from SKILL.md frontmatter.

Declared agents cursor

Package contents

Files included with this skill beyond the listing page.

  • skill md SKILL.md 4,169 B
  • docs SUMMARY.md 168 B

History

  1. First recorded snapshot · 0 installs

SKILL.md

Performance Optimization Workflow

1. Capture and Analyze

Make a request and get structured JSON — response metadata plus a full trace analysis:

uv run plain request /path --json
uv run plain request /path --json --user 1
uv run plain request /path --json --method POST --data '{"key": "value"}'

The --user flag accepts a user ID or email.

traces is normally a list — one entry per request, so a followed redirect chain returns one per hop in hop order. Analyze each on its own; the last entry is the page that actually rendered. Never sum counts across hops: a query the framework runs once per request would look like a repeat that no change can fix.

Check tracenote before indexing. traces is null when the OpenTelemetry SDK isn't installed and [] when nothing was captured; in both cases a tracenote sibling key says why. Report that instead of indexing into nothing.

A failed request returns a different shape. If the view raised, the command exits 1 and emits {"error": "...", "traces": [...]} — no response key. The trace is still there, and analysis.exceptions carries the stacktrace, so this is the payload to read when debugging a 500. Branch on "response" in payload before reaching for it.

Each entry has name (e.g. GET /admin/p/user, including any query string) and requestid — which matches response.requestid for the hop that rendered — plus analysis (derived) and spans (raw):

  • analysis.query_count — statements executed in this request
  • analysis.transaction_count — transaction-control statements, counted apart from queries. With plain.postgres this is savepoint bookkeeping; BEGIN/COMMIT are issued outside the instrumented cursor and never appear
  • analysis.duration_ms — that request's duration
  • analysis.exceptions — exceptions recorded on any span, with span, error_type, message, stacktrace
  • analysis.queries — each distinct statement with count, totaldurationms, and sources, slowest first
  • sources — the call sites that issued the statement, as path:line in function strings. The path says whose code it is: project paths vs installed-package (site-packages) paths
  • spans — raw OpenTelemetry spans, a flat list (parentspanid gives the structure)

count means one thing: how many times that statement ran in that request. Nothing is pre-diagnosed.

2. Identify Bottlenecks

You do the diagnosing. The trace reports what ran; deciding what is wrong with it is the job. Read analysis.queries and look for:

  • Repeats — count > 1 is the N+1 shape. Go read the code at the recorded call sites before concluding: three executions from three branches is not the same as three from a loop, and only the source tells you which. A source is where the query executed, which for lazy querysets can be framework code (a paginator, a template render) even though project code built the queryset — a repeat with only site-packages sources still usually traces back to a queryset the project constructed.
  • Slow statements — high totaldurationms. A single slow query outranks a dozen fast repeats.
  • Cost the counts don't show — duration_ms far exceeding the sum of query time means the time went somewhere else; read spans for it.
  • Missing indexes, unnecessary work in hot paths.

Never sum counts across hops — a query the framework runs once per request would look like a repeat that no change can fix.

3. Apply Fixes

  • Add selectrelated() / prefetchrelated() for N+1
  • Add database indexes for slow queries
  • Cache expensive computations

4. Verify Improvement

Re-run uv run plain request /path --json and compare analysis.querycount, the count on the statement you changed, and analysis.durationms for the same trace — match traces by name, not position, since a fix can change the redirect chain.