perplexity-local-dev-loop
Configures local mocking and testing for Perplexity APIs to save costs and speed up the development feedback loop.
Install
mkdir -p .claude/skills/perplexity-local-dev-loop && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/4798" && unzip -o skill.zip -d .claude/skills/perplexity-local-dev-loop && rm skill.zipInstalls to .claude/skills/perplexity-local-dev-loop
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Configure Perplexity local development with mocking, testing, and hotKey capabilities
- →Configure mock fixtures for offline development
- →Implement type-safe client wrappers
- →Enable live integration testing gated by API keys
- →Set up hot-reload development workflows
- →Capture API responses for test fixtures
How it works
The skill establishes a development loop using mock fixtures to simulate API responses. This allows developers to work offline and avoid costs during the iteration cycle.
Inputs & outputs
When to use perplexity-local-dev-loop
- →Configure local development with mock responses
- →Speed up test cycles for search features
- →Safely iterate on search result parsing
- →Enable offline development for API integrations
About this skill
Perplexity Local Dev Loop
Overview
Set up a fast, cost-effective local development workflow for Perplexity Sonar API. Key challenge: every real API call performs a web search and costs money, so mocking and caching are essential for development.
Prerequisites
- Completed
perplexity-install-authsetup - Node.js 18+ with npm/pnpm
vitestfor testing
Instructions
Step 1: Project Structure
my-perplexity-project/
├── src/
│ ├── perplexity/
│ │ ├── client.ts # OpenAI client wrapper for Perplexity
│ │ ├── search.ts # Search functions with citation handling
│ │ └── types.ts # Response type extensions
│ └── index.ts
├── tests/
│ ├── fixtures/ # Saved API responses for mocking
│ │ └── sonar-response.json
│ ├── perplexity.test.ts
│ └── setup.ts
├── .env.local # API key (git-ignored)
├── .env.example # Template
└── package.json
Step 2: Type-Safe Client Wrapper
// src/perplexity/client.ts
import OpenAI from "openai";
export interface PerplexityResponse extends OpenAI.ChatCompletion {
citations?: string[];
search_results?: Array<{
title: string;
url: string;
snippet: string;
}>;
related_questions?: string[];
}
export type PerplexityModel = "sonar" | "sonar-pro" | "sonar-reasoning-pro" | "sonar-deep-research";
export function createClient(apiKey?: string): OpenAI {
return new OpenAI({
apiKey: apiKey || process.env.PERPLEXITY_API_KEY,
baseURL: "https://api.perplexity.ai",
});
}
export async function search(
client: OpenAI,
query: string,
opts: {
model?: PerplexityModel;
systemPrompt?: string;
maxTokens?: number;
searchRecencyFilter?: "hour" | "day" | "week" | "month";
searchDomainFilter?: string[];
} = {}
): Promise<PerplexityResponse> {
const response = await client.chat.completions.create({
model: opts.model || "sonar",
messages: [
...(opts.systemPrompt
? [{ role: "system" as const, content: opts.systemPrompt }]
: []),
{ role: "user" as const, content: query },
],
max_tokens: opts.maxTokens,
...(opts.searchRecencyFilter && { search_recency_filter: opts.searchRecencyFilter }),
...(opts.searchDomainFilter && { search_domain_filter: opts.searchDomainFilter }),
} as any);
return response as unknown as PerplexityResponse;
}
Step 3: Save Fixtures for Offline Development
// scripts/capture-fixture.ts
import { createClient, search } from "../src/perplexity/client";
import { writeFileSync } from "fs";
async function captureFixture() {
const client = createClient();
const response = await search(client, "What is TypeScript 5.5?");
writeFileSync(
"tests/fixtures/sonar-response.json",
JSON.stringify(response, null, 2)
);
console.log("Fixture saved with", (response.citations || []).length, "citations");
}
captureFixture();
Step 4: Mock Client for Tests
// tests/setup.ts
import { vi } from "vitest";
import fixture from "./fixtures/sonar-response.json";
export function mockPerplexityClient() {
return {
chat: {
completions: {
create: vi.fn().mockResolvedValue(fixture),
},
},
};
}
Step 5: Write Tests
// tests/perplexity.test.ts
import { describe, it, expect } from "vitest";
import { mockPerplexityClient } from "./setup";
import { search } from "../src/perplexity/client";
describe("Perplexity Search", () => {
it("returns answer with citations", async () => {
const client = mockPerplexityClient() as any;
const result = await search(client, "test query");
expect(result.choices[0].message.content).toBeDefined();
expect(result.citations).toBeDefined();
expect(result.citations!.length).toBeGreaterThan(0);
});
it.skipIf(!process.env.PERPLEXITY_API_KEY)(
"live API returns citations",
async () => {
const { createClient, search } = await import("../src/perplexity/client");
const client = createClient();
const result = await search(client, "What is Node.js?", {
model: "sonar",
maxTokens: 100,
});
expect(result.citations!.length).toBeGreaterThan(0);
}
);
});
Step 6: Dev Scripts
{
"scripts": {
"dev": "tsx watch src/index.ts",
"test": "vitest",
"test:watch": "vitest --watch",
"test:live": "PERPLEXITY_API_KEY=$PERPLEXITY_API_KEY vitest --run",
"capture-fixtures": "tsx scripts/capture-fixture.ts"
}
}
Error Handling
| Error | Cause | Solution |
|---|---|---|
| Fixture missing | Never captured | Run npm run capture-fixtures once |
| Tests hit real API | Missing mock | Ensure mock client is injected |
| Stale fixtures | API response format changed | Re-capture fixtures |
| High dev costs | Making live calls in loop | Use fixtures; reserve live calls for CI |
Output
- Type-safe Perplexity client wrapper
- Fixture-based test suite that runs offline
- Live integration test gated on API key presence
- Hot-reload dev server
Resources
Next Steps
See perplexity-sdk-patterns for production-ready code patterns.
Prerequisites
Limitations
- →Requires manual capture of fixtures
- →Stale fixtures if API response format changes
How it compares
It shifts the development workflow from live API calls to a fixture-based testing model, significantly reducing costs and latency during coding.
Compared to similar skills
perplexity-local-dev-loop side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| perplexity-local-dev-loop (this skill) | 1 | 27d | Review | Intermediate |
| zod-4 | 12 | 7mo | No flags | Intermediate |
| develop-ai-functions-example | 5 | 6mo | Review | Intermediate |
| indicator-buffer | 1 | 1mo | No flags | Advanced |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by jeremylongshore
View all by jeremylongshore →You might also like
zod-4
prowler-cloud
Zod 4 schema validation patterns. Trigger: When creating or updating Zod v4 schemas for validation/parsing (forms, request payloads, adapters), including v3 -> v4 migration patterns.
develop-ai-functions-example
vercel
Develop examples for AI SDK functions. Use when creating, running, or modifying examples under examples/ai-functions/src to validate provider support, demonstrate features, or create test fixtures.
indicator-buffer
DaveSkender
Implement BufferList incremental indicators with efficient state management. Use for IIncrementFromChain or IIncrementFromQuote implementations. Covers interface selection, constructor patterns, and BufferListTestBase testing requirements.
agent-implementer-sparc-coder
ruvnet
Agent skill for implementer-sparc-coder - invoke with $agent-implementer-sparc-coder
add-policy
microsoft
Use when adding, modifying, or reviewing VS Code configuration policies. Covers the full policy lifecycle from registration to export to platform-specific artifacts. Run on ANY change that adds a `policy:` field to a configuration property.
node
dannybrown37
Invoke when the user is writing or debugging TypeScript or JavaScript code, working with Node.js tooling, or asking about ESLint/Prettier configuration.