Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Configure a local development workflow for Anthropic Claude API projects. Use when setting up dev environment, configuring hot reload, or establishing a fast iteration cycle with the Messages API. Trigger with phrases like "anthropic local dev", "claude dev setup", "anthropic development workflow", "test claude locally".
.claude/skills/jeremylongshore-anth-local-dev-loop/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-05 | ✗→✓ | ▲ Improved | 72% | 0% |
| case-08 | ✗→✓ | ▲ Improved | 17% | 0% |
| case-11 | ✗→✓ | ▲ Improved | 8% | 0% |
| case-14 | ✗→✓ | ▲ Improved | -29% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 81% | 0% |
Set up a fast local development cycle for Claude API projects with environment management, request logging, cost tracking, and hot-reload.
anth-install-auth setup.env file with ANTHROPIC_API_KEYmy-claude-app/
├── .env # ANTHROPIC_API_KEY=sk-ant-...
├── .env.example # ANTHROPIC_API_KEY=your-key-here
├── .gitignore # Include .env
├── src/
│ ├── client.ts # Singleton client
│ ├── prompts/ # System prompts as files
│ └── tools/ # Tool definitions
├── tests/
│ └── mock-responses/ # Saved API responses for testing
└── scripts/
└── dev.ts # Dev runner with loggingtypescript// src/client.ts import Anthropic from '@anthropic-ai/sdk'; let client: Anthropic | null = null; export function getClient(): Anthropic { if (!client) { client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY, maxRetries: 2, timeout: 30_000, }); } return client; } // Development logger — tracks cost per request export function logUsage(messageId: string, usage: { input_tokens: number; output_tokens: number }, model: string) { const pricing: Record<string, { input: number; output: number }> = { 'claude-sonnet-4-20250514': { input: 3.0, output: 15.0 }, 'claude-haiku-4-20250514': { input: 0.80, output: 4.0 }, 'claude-opus-4-20250514': { input: 15.0, output: 75.0 }, }; const rates = pricing[model] || pricing['claude-sonnet-4-20250514']; const cost = (usage.input_tokens * rates.input + usage.output_tokens * rates.output) / 1_000_000; console.log(`[${messageId}] ${model} | ${usage.input_tokens}+${usage.output_tokens} tokens | $${cost.toFixed(4)}`); }
typescript// tests/mock-client.ts import { type Message } from '@anthropic-ai/sdk/resources/messages'; export function mockMessage(text: string): Message { return { id: 'msg_test_123', type: 'message', role: 'assistant', model: 'claude-sonnet-4-20250514', content: [{ type: 'text', text }], stop_reason: 'end_turn', stop_sequence: null, usage: { input_tokens: 10, output_tokens: 20 }, }; }
text# package.json scripts "scripts": { "dev": "tsx watch src/index.ts", "dev:debug": "ANTHROPIC_LOG=debug tsx watch src/index.ts", "test": "vitest", "test:live": "LIVE_API=1 vitest --run" }
The development loop produces a repeatable local project layout, a single configured client, mock-backed tests, and a request log that records model and token usage. A change can then be exercised with no API spend in the normal test suite or with deliberately enabled live traffic when investigating a prompt or integration behavior.
While editing a prompt, run the default vitest command against a saved mock response and confirm the application handles the expected text and stop reason. When a real API check is needed, set LIVE_API=1 only for that invocation, choose the lower-cost development model, and inspect the logger for token use. If the live response changes the contract, first update the fixture and its assertions, then rerun the mock suite so later local iterations remain fast and deterministic.
bash# .env.example (commit this) ANTHROPIC_API_KEY=your-key-here ANTHROPIC_MODEL=claude-sonnet-4-20250514 ANTHROPIC_MAX_TOKENS=1024 ANTHROPIC_LOG=warn # debug | info | warn | error # Enable SDK debug logging export ANTHROPIC_LOG=debug # Logs all requests/responses
pythonimport os DEV_MODEL = "claude-haiku-4-20250514" # $0.80/$4.00 per MTok PROD_MODEL = "claude-sonnet-4-20250514" # $3.00/$15.00 per MTok model = DEV_MODEL if os.getenv("ENV") == "development" else PROD_MODEL
| Issue | Cause | Solution | |-------|-------|----------| | Hot reload triggers duplicate requests | File save causes restart | Add debounce or save-on-explicit-action | | .env not loading | Missing dotenv setup | Use dotenv package or tsx --env-file=.env | | Mock tests pass but live fails | Response shape changed | Update mocks from real API responses |
Apply patterns in anth-sdk-patterns for production-ready code.
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-02 | fail→fail | 11,360 | 11,214 | -1% | 1 | 1 | 0% | 2,571 | 3,714 | +44% | 0 | 0 | — |
case-01 | fail→fail | 15,380 | 12,198 | -21% | 1 | 1 | 0% | 3,421 | 4,336 | +27% | 0 | 0 | — |
case-03 | fail→fail | 15,116 | 11,018 | -27% | 1 | 1 | 0% | 3,723 | 3,821 | +3% | 0 | 0 | — |
case-04 | pass→pass | 10,567 | 8,477 | -20% | 1 | 1 | 0% | 1,994 | 2,902 | +46% | 0 | 0 | — |
case-05 | fail→pass | 12,584 | 13,427 | +7% | 1 | 1 | 0% | 2,322 | 4,005 | +72% | 0 | 0 | — |
case-06 | pass→pass | 16,333 | 11,989 | -27% | 1 | 1 | 0% | 3,454 | 3,771 | +9% | 0 | 0 | — |
case-07 | pass→pass | 2,795 | 2,014 | -28% | 1 | 1 | 0% | 514 | 1,613 | +214% | 0 | 0 | — |
case-08 | fail→pass | 7,999 | 2,279 | -72% | 1 | 1 | 0% | 1,458 | 1,707 | +17% | 0 | 0 | — |
case-09 | pass→pass | 9,552 | 1,918 | -80% | 1 | 1 | 0% | 1,631 | 1,646 | +1% | 0 | 0 | — |
case-10 | pass→pass | 5,604 | 2,637 | -53% | 1 | 1 | 0% | 1,055 | 1,751 | +66% | 0 | 0 | — |
case-11 | fail→pass | 7,450 | 2,399 | -68% | 1 | 1 | 0% | 1,648 | 1,786 | +8% | 0 | 0 | — |
case-12 | pass→pass | 8,476 | 2,763 | -67% | 1 | 1 | 0% | 1,974 | 1,867 | -5% | 0 | 0 | — |
case-13 | pass→pass | 5,306 | 2,285 | -57% | 1 | 1 | 0% | 1,008 | 1,731 | +72% | 0 | 0 | — |
case-14 | fail→pass | 13,549 | 3,067 | -77% | 1 | 1 | 0% | 2,544 | 1,806 | -29% | 0 | 0 | — |
case-15 | fail→pass | 4,998 | 2,597 | -48% | 1 | 1 | 0% | 986 | 1,788 | +81% | 0 | 0 | — |
case-16 | fail→pass | 7,444 | 2,063 | -72% | 1 | 1 | 0% | 1,343 | 1,657 | +23% | 0 | 0 | — |
case-17 | fail→pass | 14,361 | 10,307 | -28% | 1 | 1 | 0% | 2,921 | 3,616 | +24% | 0 | 0 | — |
case-18 | pass→pass | 12,455 | 10,122 | -19% | 1 | 1 | 0% | 2,174 | 3,223 | +48% | 0 | 0 | — |
case-19 | pass→pass | 8,601 | 6,746 | -22% | 1 | 1 | 0% | 1,602 | 2,574 | +61% | 0 | 0 | — |
case-20 | pass→pass | 9,510 | 5,871 | -38% | 1 | 1 | 0% | 1,625 | 2,408 | +48% | 0 | 0 | — |
case-21 | fail→fail | 9,150 | 5,661 | -38% | 1 | 1 | 0% | 1,948 | 2,426 | +25% | 0 | 0 | — |
case-22 | pass→pass | 5,573 | 2,834 | -49% | 1 | 1 | 0% | 1,174 | 1,775 | +51% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +32 percentage points is the difference between those two pass rates over the 22 comparable cases.
The publisher has shipped newer versions since this run, so these numbers describe v1, not the version currently listed.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.