Python & JavaScript Development: The Plugins That Made Me Stop Fighting My Stack

Get the tools: python-development
Also check out: javascript-typescript
The ATM Software Incident
Last month I was building backend services for chainbytes.com - Bitcoin ATM software that needs to handle concurrent transactions, talk to payment processors, manage device state, and not lose anyone's money. No pressure.
I started with FastAPI because async seemed right for the job. Then I hit reality.
My first attempt at handling concurrent ATM sessions looked like this:
async def process_transaction(transaction_id: str):
# Get the transaction
transaction = await db.get(transaction_id)
# Do some processing
await asyncio.sleep(0.1) # Simulate work
# Update the transaction
transaction.status = "completed"
await db.save(transaction) # Race condition. Whoops.
See the bug? No? Neither did I. For three days.
Two ATMs submitted transactions simultaneously. Both read the same state. Both updated it. One update vanished. The logs showed everything working perfectly. The customer's Bitcoin did not.
This is when I realized I needed help. Not just "ask Claude" help - I needed expertise loaded and ready to go. Enter the python-development plugin.
What Python-Development Actually Is
It's a collection of specialized agents and skills for Python development. Not generic "write me some Python" help, but deep expertise in specific domains:
Three Agents:
django-pro- Django 5.x, DRF, Celery, Django Channelsfastapi-pro- Async APIs, SQLAlchemy 2.0, Pydantic V2python-pro- Modern Python 3.12+, the 2024/2025 ecosystem
Five Skills:
async-python-patterns- asyncio, concurrent programming, producer-consumeruv-package-manager- The blazing-fast package manager from Astralpython-testing-patterns- pytest, fixtures, mocking, TDDpython-packaging- pyproject.toml, PyPI publishing, wheelspython-performance-optimization- Profiling, bottleneck identification
The agents are heavy-weight - they load comprehensive domain knowledge. The skills are targeted references you invoke when you need specific guidance.
The Race Condition Fix
After installing the plugin, I invoked the async-python-patterns skill:
/async-python-patterns
Then I described my concurrent transaction problem. What came back wasn't just a fix - it was an explanation of why my code was broken and three different patterns for handling it:
import asyncio
from typing import Optional
class TransactionManager:
"""Manages concurrent transaction access with locks."""
def __init__(self):
self._locks: dict[str, asyncio.Lock] = {}
self._lock_lock = asyncio.Lock()
async def get_lock(self, transaction_id: str) -> asyncio.Lock:
"""Get or create a lock for a specific transaction."""
async with self._lock_lock:
if transaction_id not in self._locks:
self._locks[transaction_id] = asyncio.Lock()
return self._locks[transaction_id]
async def process_transaction(self, transaction_id: str):
"""Process transaction with proper locking."""
lock = await self.get_lock(transaction_id)
async with lock:
transaction = await db.get(transaction_id)
# Now we're safe - no other coroutine can modify
# this transaction while we hold the lock
await self._do_processing(transaction)
transaction.status = "completed"
await db.save(transaction)
The skill didn't just give me code. It explained the lock hierarchy problem (acquiring locks on locks), showed me the producer-consumer pattern for high-throughput scenarios, and pointed out that for really critical operations I should be using database-level locking anyway.
Django or FastAPI? Both.
Here's a confession: the chainbytes backend ended up being a hybrid. FastAPI for the async endpoints that talk to ATM hardware. Django for the admin interface and background job processing with Celery.
The django-pro and fastapi-pro agents handled the context switching. When I was working on the FastAPI side:
@fastapi-pro Design an endpoint that handles ATM status polling
from multiple machines simultaneously
What I got back used proper dependency injection, Pydantic models with validation, and showed me how to structure the response for efficient polling:
from fastapi import FastAPI, Depends, HTTPException
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
class ATMStatus(BaseModel):
machine_id: str
online: bool = True
last_heartbeat: datetime
current_transaction: Optional[str] = None
cash_level: int = Field(ge=0, le=100)
model_config = {"from_attributes": True}
class StatusUpdate(BaseModel):
machine_id: str
cash_level: int
error_code: Optional[int] = None
app = FastAPI()
@app.post("/atm/status", response_model=ATMStatus)
async def update_status(
update: StatusUpdate,
session: AsyncSession = Depends(get_session),
):
"""Update ATM status with proper async session handling."""
atm = await session.get(ATM, update.machine_id)
if not atm:
raise HTTPException(status_code=404, detail="ATM not found")
atm.cash_level = update.cash_level
atm.last_heartbeat = datetime.utcnow()
if update.error_code:
await handle_error(session, atm, update.error_code)
await session.commit()
await session.refresh(atm)
return ATMStatus.model_validate(atm)
Then when I switched to the Django admin and Celery tasks:
@django-pro Create a Celery task that reconciles transaction
records between the ATM logs and the payment processor
The django-pro agent understood the context switch. It showed me how to structure Celery tasks with proper retry logic, how to use Django's ORM efficiently in background jobs, and reminded me about database connection handling in long-running tasks.
The uv Revelation
I was still using pip. I know, I know.
The python-development plugin includes a skill for uv, the Rust-based package manager that's 10-100x faster than pip. After running /uv-package-manager, I migrated the project in about an hour:
# Old way (pip)
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
# ... wait ...
# ... still waiting ...
# 47 seconds later, environment ready
# New way (uv)
uv venv
uv add fastapi uvicorn sqlalchemy pydantic
# 2.3 seconds. Done.
But the speed isn't even the best part. The lockfile support means reproducible builds:
# Generate lockfile
uv lock
# Install exact versions everywhere
uv sync --frozen
# CI/CD is now deterministic
The skill also showed me how to structure pyproject.toml properly, separate dev dependencies, and set up uv in GitHub Actions. My CI went from 90 seconds to 15 seconds just from the dependency installation speedup.
Testing Async Code
This is where I really suffered before the plugin. Testing async Python is confusing. pytest-asyncio has its own decorators. Fixtures can be async. Mocking async functions requires different patterns.
The python-testing-patterns skill broke it all down:
import pytest
from unittest.mock import AsyncMock, patch
@pytest.fixture
async def mock_payment_processor():
"""Async fixture for payment processor."""
processor = AsyncMock()
processor.charge.return_value = {"status": "success", "tx_id": "abc123"}
return processor
@pytest.mark.asyncio
async def test_transaction_success(mock_payment_processor):
"""Test successful transaction flow."""
with patch("app.services.get_processor", return_value=mock_payment_processor):
result = await process_purchase(
amount=100,
customer_id="cust_123"
)
assert result.status == "completed"
mock_payment_processor.charge.assert_called_once_with(
amount=100,
customer="cust_123"
)
@pytest.mark.asyncio
async def test_transaction_retry_on_timeout():
"""Test that transactions retry on processor timeout."""
processor = AsyncMock()
processor.charge.side_effect = [
asyncio.TimeoutError(), # First call fails
{"status": "success"} # Second call succeeds
]
with patch("app.services.get_processor", return_value=processor):
result = await process_purchase(amount=50, customer_id="cust_456")
assert result.status == "completed"
assert processor.charge.call_count == 2
The pattern of AsyncMock with side_effect for simulating flaky services saved me. Payment processors time out. Networks fail. ATM hardware is weird. The tests now cover these cases.
The Compound Effect
What I didn't expect was how these tools would work together.
Start a FastAPI project with uv. Add Django for the admin. Use async patterns for concurrent operations. Test everything with pytest-asyncio. Package it all with pyproject.toml.
Each skill builds on the others. The python-pro agent understands the whole stack. When I ask it about something, it considers the tools I'm using, the patterns I've established, the structure of my project.
I'm not constantly context-switching between "how does asyncio work" and "what's the pytest syntax again" and "wait, how do I install this." The knowledge is loaded when I need it, specialized for my use case.
JavaScript and TypeScript: The Other Half of the Stack
Python handles the backend. But the chainbytes project also has a dashboard. A real-time monitoring interface. WebSocket connections. All the frontend stuff that Python developers pretend doesn't exist.
This is where the javascript-typescript plugin comes in.
The Agents:
nodejs-pro- Modern Node.js development, async patterns, npm ecosystemtypescript-pro- Type-safe JavaScript, advanced TypeScript patterns
The Skills:
- TypeScript configuration and strict mode setup
- Modern ES modules and build tooling
- Node.js performance patterns
- React and frontend framework integration
The nodejs-pro agent is like having a senior Node developer who actually reads the documentation. When I was setting up the WebSocket server for real-time ATM monitoring:
@nodejs-pro Set up a WebSocket server that broadcasts ATM status
updates to connected dashboard clients
What I got back wasn't just working code - it was production-ready patterns:
import { WebSocketServer, WebSocket } from 'ws';
import { createServer } from 'http';
interface ATMUpdate {
machineId: string;
status: 'online' | 'offline' | 'error';
lastTransaction?: string;
timestamp: number;
}
class ATMBroadcaster {
private wss: WebSocketServer;
private clients: Set<WebSocket> = new Set();
constructor(server: ReturnType<typeof createServer>) {
this.wss = new WebSocketServer({ server });
this.wss.on('connection', (ws) => {
this.clients.add(ws);
ws.on('close', () => {
this.clients.delete(ws);
});
ws.on('error', (err) => {
console.error('WebSocket error:', err);
this.clients.delete(ws);
});
});
}
broadcast(update: ATMUpdate): void {
const message = JSON.stringify(update);
for (const client of this.clients) {
if (client.readyState === WebSocket.OPEN) {
client.send(message);
}
}
}
}
The agent showed me proper connection cleanup, error handling, and the TypeScript interfaces that make the whole thing type-safe. No more any types leaking through the codebase.
TypeScript That Actually Works
Here's my confession about TypeScript: I used to treat it like JavaScript with extra syntax. Just add : string to things until the red squiggles go away.
The typescript-pro agent fixed that. When I asked about proper typing for the dashboard's state management:
@typescript-pro How do I type a reducer that handles multiple
ATM status updates with discriminated unions?
What came back was a proper TypeScript education:
// Discriminated union for ATM events
type ATMEvent =
| { type: 'STATUS_UPDATE'; machineId: string; status: ATMStatus }
| { type: 'TRANSACTION_START'; machineId: string; txId: string }
| { type: 'TRANSACTION_COMPLETE'; machineId: string; txId: string; amount: number }
| { type: 'ERROR'; machineId: string; code: number; message: string };
interface DashboardState {
machines: Map<string, ATMStatus>;
activeTransactions: Map<string, Transaction>;
errors: ATMError[];
}
function dashboardReducer(state: DashboardState, event: ATMEvent): DashboardState {
switch (event.type) {
case 'STATUS_UPDATE':
return {
...state,
machines: new Map(state.machines).set(event.machineId, event.status)
};
case 'TRANSACTION_START':
return {
...state,
activeTransactions: new Map(state.activeTransactions).set(
event.txId,
{ id: event.txId, machineId: event.machineId, startTime: Date.now() }
)
};
case 'TRANSACTION_COMPLETE': {
const updated = new Map(state.activeTransactions);
updated.delete(event.txId);
return { ...state, activeTransactions: updated };
}
case 'ERROR':
return {
...state,
errors: [...state.errors, {
machineId: event.machineId,
code: event.code,
message: event.message,
timestamp: Date.now()
}]
};
}
}
The discriminated union pattern means TypeScript knows exactly which properties exist in each case. No more runtime checks. No more event.amount when the event doesn't have an amount. The compiler catches it before the code runs.
The Full Stack Reality
The chainbytes project now has:
- FastAPI backend handling ATM transactions (python-development)
- Django admin for operations team (python-development)
- Node.js WebSocket server for real-time updates (javascript-typescript)
- TypeScript React dashboard (javascript-typescript)
- Proper types flowing through the entire stack
Both plugins talk to each other conceptually. The Python types and the TypeScript types mirror each other. The async patterns in Python match the async patterns in Node. The testing strategies are consistent.
# Python side
@fastapi-pro
/async-python-patterns
/python-testing-patterns
# JavaScript side
@nodejs-pro
@typescript-pro
When I'm working on the API endpoint and need to update the dashboard to consume it, I switch agents and the context follows. The nodejs-pro agent understands REST APIs. The typescript-pro agent knows how to type the response. It's the same mental model, different syntax.
Getting Started
Install the plugins from agents-skills-plugins.
For Python work:
# For a FastAPI project
@fastapi-pro
# For Django work
@django-pro
# For general Python excellence
@python-pro
Then dive into specific skills when you need them:
/async-python-patterns # Concurrent programming
/uv-package-manager # Modern dependency management
/python-testing-patterns # Pytest and TDD
/python-packaging # Publishing to PyPI
/python-performance # Profiling and optimization
For JavaScript and TypeScript work:
# For Node.js development
@nodejs-pro
# For TypeScript patterns
@typescript-pro
The agents are proactive - they'll catch issues and suggest improvements. The skills are reference material - invoke them when you need specific guidance.
The Honest Ending
Did the plugins make me a better developer? Probably not.
Did they make me a more productive developer? Absolutely.
The chainbytes ATM backend ships transactions without race conditions now. The dashboard updates in real-time. The TypeScript is actually typed. The test suite runs in CI. Dependencies install in seconds instead of minutes.
These plugins aren't magic. They're expertise, encoded and ready. The same knowledge you'd get from reading the docs, watching the tutorials, and making all the mistakes - but loaded into context when you need it, not sitting in browser tabs you'll definitely read later (you won't).
For more tools like this, check out the agents-skills-plugins repo.
"The best code is code that doesn't fight you. The second best is code that knows when it's fighting."
Ship Python. Ship TypeScript. Ship it fast. Don't lose anyone's Bitcoin.
One reaction per emoji per post.
// newsletter
Get dispatches from the edge
Field notes on AI systems, autonomous tooling, and what breaks when it all gets real.
You will be redirected to Substack to confirm your subscription.