Performance optimization
Skill jmxt3/gitscape.ai/.agents/skills/performance-optimization
Scan any agent skill — authored or compiled — for prompt injection, secrets, and malicious execution before it touches your agent. Or compile the long tail on the fly.
npx -y skills add jmxt3/gitscape.ai --skill performance-optimizationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its author says it does
Copied from the file, not written here
Optimizes application performance. Use when performance requirements exist, when you suspect performance regressions, or when Core Web Vitals or load times need improvement. Use when profiling reveals bottlenecks that need fixing.
SKILL.md
5.7 KB, ~1.3k tokens by cl100k_base, as published. Nobody here has run it
Performance Optimization
Overview
Measure first, then optimize. Never optimize without data. Performance problems have specific root causes — guessing wastes time and can introduce regressions. The goal is to identify the specific bottleneck, fix it, and measure the improvement.
When to Use
- A specific performance regression has been reported or measured
- A feature has a performance requirement (e.g., "< 200ms API response time")
- Core Web Vitals are in the "Needs Improvement" or "Poor" range
- Bundle size has grown significantly
When NOT to use: "Let's make it faster" without a measured baseline. Profile first.
The Measure-First Workflow
Step 1: Establish a Baseline
Before changing anything, capture the current state:
# API response time (via curl)
curl -w "@curl-format.txt" -s -o /dev/null https://api.gitscape.app/api/skills
# Frontend bundle size
npx vite build --mode production 2>&1 | grep "dist/"
# Lighthouse audit (frontend)
npx lighthouse https://gitscape.app --output json --output-path ./baseline.json
Record the specific numbers. You need them to prove the optimization worked.
Step 2: Profile to Find the Real Bottleneck
Don't guess. Use profiling tools:
Backend (Python FastAPI):
import cProfile
import pstats
with cProfile.Profile() as pr:
result = await generate_skill(repo)
stats = pstats.Stats(pr)
stats.sort_stats("cumulative")
stats.print_stats(20) # Top 20 hotspots
Frontend (React):
- Chrome DevTools → Performance tab → Record → Replay user action
- React DevTools Profiler → Identify components that re-render unnecessarily
Network:
- Chrome DevTools → Network tab → Filter by type, check response sizes and waterfall
Step 3: Fix Only the Measured Bottleneck
Fix the specific issue the profile reveals — not everything that could theoretically be faster.
Step 4: Measure After
Compare against the baseline. If the improvement isn't measurable, the optimization wasn't worth it.
Common Bottlenecks in GitScape
Large File Previews Freezing the Browser
// BAD: Rendering full file content for large files
function FilePreview({ content }: { content: string }) {
return <pre>{content}</pre>; // 10MB file = browser freeze
}
// GOOD: Truncate at a safe limit
const MAX_PREVIEW_CHARS = 10_000;
function FilePreview({ content }: { content: string }) {
const truncated = content.length > MAX_PREVIEW_CHARS;
return (
<div>
<pre>{truncated ? content.slice(0, MAX_PREVIEW_CHARS) : content}</pre>
{truncated && <p>Preview truncated — full content exported.</p>}
</div>
);
}
Slow GitHub API Calls (N+1 Pattern)
# BAD: Separate API call per file (N+1)
async def get_file_contents(repo: str, paths: list[str]) -> dict:
result = {}
for path in paths:
# One API call per file
result[path] = await github.get_file(repo, path)
return result
# GOOD: Batch or parallelize
async def get_file_contents(repo: str, paths: list[str]) -> dict:
tasks = [github.get_file(repo, path) for path in paths]
contents = await asyncio.gather(*tasks, return_exceptions=True)
return {path: content for path, content in zip(paths, contents)
if not isinstance(content, Exception)}
Unnecessary React Re-renders
// BAD: New object reference on every render
function SkillList({ skills }: Props) {
return <SkillFilters options={{ sortBy: 'name' }} />;
}
// GOOD: Stable reference
const DEFAULT_FILTER_OPTIONS = { sortBy: 'name' } as const;
function SkillList({ skills }: Props) {
return <SkillFilters options={DEFAULT_FILTER_OPTIONS} />;
}
Large Bundle Size
// GOOD: Dynamic import for heavy, rarely-used features
const MonacoEditor = lazy(() => import('./MonacoEditor'));
function App() {
return (
<Suspense fallback={<div>Loading editor...</div>}>
<MonacoEditor />
</Suspense>
);
}
Performance Budget
Track these targets and alert when exceeded:
API response time (p95): < 2000ms for skill generation
< 200ms for metadata endpoints
Frontend JS bundle: < 200KB gzipped (initial load)
File preview rendering: < 100ms for files < 10KB
Lighthouse Performance: ≥ 80 (acceptable), ≥ 90 (target)
Common Rationalizations
| Rationalization | Reality |
|---|---|
| "We'll optimize later" | Performance debt compounds. Address measured regressions now. |
| "It's fast on my machine" | Your machine isn't the user's. Profile on representative hardware. |
| "This optimization is obvious" | If you didn't measure, you don't know. Profile first. |
| "The framework handles performance" | Frameworks prevent some issues but can't fix N+1 queries or unbounded previews. |
Red Flags
- Optimization without profiling data
- N+1 API call patterns (loop of individual calls)
- Rendering full content of files without size limits
- Re-fetching data that hasn't changed
React.memoanduseMemoeverywhere (overusing is as bad as underusing)- Bundle size growing release-over-release without review
Verification
After any performance change:
- Before and after measurements exist (specific numbers, not "feels faster")
- The specific bottleneck is identified and addressed
- Full test suite passes (optimization didn't break behavior)
- Bundle size hasn't increased on changes unrelated to bundling
- The performance budget still passes