Blog

Thoughts, tutorials, and deep dives from the pyRPC team.

169 posts
·10 minTutorial

Getting Started With MCP: A Practical Guide

Comprehensive walkthrough for both MCP surfaces. Remote documentation in 30 seconds, local project in 15 minutes, both together in production.

·9 minDeep Dive

The Future of AI Development Tools

Protocol convergence, registry servers, agent-first design, trust infrastructure. Where AI-native development is heading and what it means for Python frameworks.

·8 minDeep Dive

Building Trust With AI Agents: The pyRPC Approach

Never-execute guarantees, dry-run-first defaults, structured errors, transparent discovery. How pyRPC design builds trust between developers and agents.

·7 minDeep Dive

Why Local MCP Beats API Docs for AI Agents

Static documentation drifts. MCP imports your actual code. Ground truth vs interpretation, and why structured data beats text for agent performance.

·10 minDeep Dive

AI-Native Development: What We Learned Building pyRPC MCP

Trust boundaries, read-only-first design, thin servers, protocol convergence. Lessons from building an AI-native Python framework from scratch.

·5 minTutorial

How to Set Up MCP in Under 5 Minutes

Quickstart for both remote and local MCP. One command for documentation, five minutes for your project. The it-just-works principle.

·7 minDeep Dive

The Catch With Remote MCP Servers

Claude Desktop refuses them. The auth gap in MCP spec. Rate limits. An honest discussion of remote MCP tradeoffs and why the two-server pattern still works.

·9 minTutorial

How to Add MCP to Any Python Framework

Step-by-step guide to adding pyRPC local MCP to FastAPI, Django, Flask, or any ASGI/WSGI app. Framework-specific gotchas included.

·8 minDeep Dive

The Protocol Is the Interface

Why MCP is the right abstraction layer for AI-tool integration. JSON-RPC foundations, Streamable HTTP vs stdio, and the thin server principle.

·7 minDeep Dive

When an Agent Breaks Your Schema

AI agents generate plausible but type-incorrect payloads. How pyRPC check_call validates against real Python types and returns per-parameter errors the agent can fix.

·8 minDeep Dive

Testing the MCP Like Prisma Does

Official SDK in-memory clients, raw subprocess JSON-RPC, and the purity test. A 21-test strategy that catches protocol bugs, lifecycle issues, and config regressions.

·7 minTutorial

MCP Without a Launcher: The npx @pyrpc/mcp mcp Pattern

How a 50-line branded wrapper over add-mcp configures 19 AI coding agents without maintaining a single line of protocol or client-specific code.

·9 minDeep Dive

Local vs Remote: The Trust Boundary That Matters

Two MCP servers, two trust models. Why the distinction between a subprocess importing your code and a hosted documentation endpoint is the most important design decision.

·8 minDeep Dive

Three Tools, No More

introspect_project, check_call, run_codegen. How pyRPC chose exactly three tools and why the anti-pattern of too many tools kills agent performance.

·7 minDeep Dive

Why MCP Is an Extra, Not a Default

Eighteen transitive packages including compiled cryptography. The packaging math behind making pyrpc-core[mcp] optional, and why that boundary is permanent.

·4 minDeep Dive

stdout belongs to the protocol: stdio discipline in pyrpc mcp

One stray print corrupts an MCP session. How the SDK protects the wire, the two windows it cannot cover, and the tests that make purity mechanical.

·5 minDeep Dive

Errors an agent can fix: the ToolError discipline

Structured failures with remediation baked in: what failed, what state caused it, and the exact next move, for every failure mode the server can hit.

·4 minDeep Dive

Codegen through an MCP: dry run first, narrow writes, honest hints

The one mutating tool in pyrpc mcp gets a non-mutating default, generated-files-only scope, and annotations that match reality.

·4 minDeep Dive

check_call: validation with execution removed from the universe

Bind-and-validate extracted from Procedure.execute so agents can verify payloads against real types while remaining structurally unable to run your code.

·5 minDeep Dive

Introspection that imports your code, on purpose

Static parsers guess; the runtime knows. How the MCP reuses the registry chain from pyrpc.json to get_registry_schema for ground truth.

·6 minRelease

pyRPC v0.14.0: pyrpc mcp, your backend as an AI-native surface

Release tour: the local MCP server with three read-oriented tools, the no-execution security line, dry-run-first codegen, and lean optional packaging.

·3 minRelease

pyRPC v0.14.1: Batch requests now work in FastAPI

Patch release: the FastAPI adapter now accepts batch requests. What was broken, why other adapters were fine, and how to upgrade.

·5 minDeep Dive

When your framework validates before your library does

The FastAPI batch bug as a case study in double validation — why framework annotations can block library features, and how a one-line type fix resolves it.

·4 minTutorial

Batch requests in pyRPC: how they work and when to use them

A guide to batch RPC operations — what they look like on the wire, how the server processes them, and when httpBatchLink beats httpLink.

·5 minDeep Dive

Dependabot across two lockfile ecosystems

Four surfaces (uv.lock, npm workspaces, docs npm, GitHub Actions), one policy: grouped minor+patch to cut noise, majors kept individual because a major pydantic bump is an event.

·6 minDeep Dive

Docs and examples as executable truth

Twelve example apps and dozens of doc snippets were never executed by anything. Now every example imports cleanly in CI, every python fence parses, and fences tagged test run for real.

·6 minDeep Dive

Coverage floors without theater

Measure first, pick the number second: a hard 78 percent floor against a measured 80, two points of slack absorbing noise instead of inviting gamed tests, and honesty about what line coverage cannot say.

·7 minDeep Dive

The Windows CI leg found a real bug on day one

Expanding the matrix to Windows immediately surfaced a first-run crash: jsonc-edit bootstrapped npm via CreateProcess, which cannot execute npm.cmd. Fixed upstream in 0.2.1; floor raised so users get it.

·7 minDeep Dive

Type checking a library whose product is types

mypy over five Python packages found thirteen errors, including an ASGI transport whose annotation still claimed dict-only payloads after batching shipped. Plus typed lazy globals and a Popen subclass replacing proc._cwd.

·7 minDeep Dive

Adopting ruff into a codebase with 374 violations

The playbook: autofix the boring parts, hand-fix what teaches something (three missing raise-from chains, a closure bug), encode accepted style as documented config, then let CI hold the line.

·7 minDeep Dive

From paper standards to enforced gates

Every engineering standard pyRPC claimed already existed in the repo; none were enforced. The audit, the rule set for closing seven gaps honestly, and what enforcement caught in its first days.

·6 minRelease

pyRPC v0.13.0: explicit backends and native dev servers

Release tour: declared backend config, framework-native dev servers, terminating links with batching, jailed autocomplete, and the site redesign - plus the two-step upgrade path.

·6 minDeep Dive

Twelve examples, one conformance bar

Links-based clients everywhere, fixed provider scope in CRA, working Svelte inputs, Vue-idiomatic hooks, restored configs - what conformance means for an examples matrix that must stay green.

·5 minDeep Dive

Restructuring the docs for adapters, links, and AI

Why client adapters got their own section, links earned dedicated pages, llms.txt and MCP became first-class navigation, and small fixes like restored sidebar icons compound.

·6 minDeep Dive

Redesigning the site around the code

New brand assets, better-auth-style light/dark tokens, fumadocs 16.12 migration, and one shared Shiki palette so landing, docs, and playground render code identically.

·8 minTutorial

Django gets first-class treatment in v0.13.0

manage.py runserver launched for you, entrypoint as a manage.py path, a required types_module pointing at views.py - and why that contract also fixes stale-type regen.

·8 minTutorial

Flask + Next.js with flask run under the hood

Full walkthrough of examples/flask-nextjs on v0.13.0: one command launches Flask native and regenerates types, with directory autocomplete in the wizard and live config swaps to try.

·6 minTutorial

Migrating your client to the links API

The mechanical before/after for v0.13.0: constructor options become a one-element links array, adapters re-export the terminators, and URL normalization gets looser not stricter.

·8 minDeep Dive

Editing pyrpc.json while the server runs

The config watcher diffs parsed BackendSpec values, restarts only when the backend changes, and re-wires codegen for client edits - plus the three races its tests had to kill.

·7 minDeep Dive

A filesystem prompt that can’t escape its jail

Client-root autocomplete via questionary.path: realpath containment filters symlink escapes from suggestions, while typed input stays free and only existence-checked. Tested headlessly.

·8 minDeep Dive

The types_module contract

Registration is an import side effect. Why Django layouts regenerated stale types under the old model, and how naming the registration module fixes reload semantics honestly.

·7 minDeep Dive

Explicit beats magic: declaring your backend in pyrpc.json

The nested backend/clients schema, sniffing demoted from oracle to preselection, --yes that fails closed, and BackendSpec validation as a data model instead of scattered ifs.

·7 minDeep Dive

Your framework’s dev server, not ours

pyrpc dev now launches uvicorn, flask run, or manage.py runserver natively. Why hosting your stack beats substituting for it, and how LaunchPlan made the matrix testable.

·8 minDeep Dive

Batched RPC requests, end to end

httpBatchLink coalesces same-tick operations into one JSON-array POST; the interpreter dispatches them sequentially with per-operation errors. What batching is - and deliberately is not.

·7 minDeep Dive

Terminating links: giving @pyrpc/client a pipeline

The tRPC-style link architecture behind v0.13.0: exactly one terminating link owns transport, composable links handle auth/retry/logging, and URL normalization moved where it belongs.

·5 minDeep Dive

A crash hiding in plain sight: watch vs watchfiles

How a local function shadowing the watchfiles import broke pyrpc watch, why every test missed it, and the three habits that catch shadowing bugs early.

·9 minDeep Dive

What pyRPC owns, and what it doesn’t

The dependency contract: what ships in dependencies, what stays a peer, why TanStack Query is internal but not owned, and how the Python extras mirror it.

·7 minDeep Dive

baseUrl: compile-time and runtime

A string in an options type at compile time, a normalization pipeline at runtime, and why the browser fallback fails loudly on the server.

·8 minDeep Dive

How we checked every bundler: the verification matrix

The claim that tsconfig paths work for webpack but not Vite, SvelteKit, or Turbopack, proven by unit tests, example apps, and a matrix that shows why.

·7 minDeep Dive

The release PR: how a version bump goes to review

Why the release is a reviewed merge followed by a tag, and how decoupling the two makes an irreversible step reversible.

·8 minDeep Dive

Reconciling zero-config with a runtime module

A release that demands more configuration while moving toward less, and the safety mechanisms that make a tool-owned config trustworthy.

·6 minDeep Dive

The changelog as structured data

Why the changelog is a TypeScript module, not Markdown: typechecked, programmatic, and rendered consistently by the docs page.

·7 minDeep Dive

The version contract between npm workspaces and uv

An unenforced agreement that binds two package managers: how the shared version number is structured and where drift could creep in.

·5 minDeep Dive

Auto-generated release notes and the naming fix

The softprops action, conventional-commit release notes, and the one-line change that renamed releases to their bare tags.

·7 minDeep Dive

A tag is a release trigger

How a git tag matching v*.*.* fires PyPI, npm, and the GitHub Release, and how the prerelease signal flows through all three.

·6 minDeep Dive

skip-existing and the npm guard: idempotent publishing

Two registries, two idempotency strategies, and why a release pipeline that can be re-run must reconcile instead of demand.

·7 minDeep Dive

The publish chain: types to client to react to adapters

The needs: graph that serializes npm publishing, and why every job hermetically rebuilds its dependency chain from the tag.

·7 minDeep Dive

Eleven packages, two ecosystems

Six npm workspaces and five Python packages shipped in lockstep from one tag, the dependency DAGs and the version contract that binds them.

·6 minDeep Dive

The lockfile dance after a version bump

Why the bump script skips lockfiles, and how uv lock and npm install close the resolution gap before the release PR opens.

·6 minDeep Dive

A version in three places

pyproject.toml, __init__.py, and uv.lock each hold the version for a different consumer, and the release process keeps them agreeing.

·8 minDeep Dive

release.mjs: one command, eleven packages

How an 85-line script walks the packages directory and rewrites versions, internal ranges, and the root workspace in lockstep.

·6 minDeep Dive

@pyrpc/types: from type-only to runtime dependency

A one-line package.json move that announces the whole v0.12.0 thesis, the type boundary became a runtime contract.

·7 minDeep Dive

Why adapters keep @pyrpc/types external

The tsup externals that let the app bundle redirect the type package: how externalization makes runtime substitution possible.

·6 minDeep Dive

The kinds override seam and why tests use it

A documented @internal escape hatch that turns the adapter into a pure function of kind, making hook-selection behavior exhaustively testable.

·7 minDeep Dive

ProcedureHooksForKind: the type-level mirror

The conditional types that make TypeScript agree with the runtime Proxy, one decision, two languages, no drift.

·8 minDeep Dive

How adapters read procedureKinds at runtime

The value import, the kinds override seam, and the Proxy get trap that builds query or mutation hooks from a single runtime lookup.

·8 minDeep Dive

Idempotent re-wiring on every regen

Every codegen run reconfigures tsconfig and the bundler. How existing-value probes, alias guards, and write-on-change make that safe.

·5 minDeep Dive

Why the alias is relative

The leading dot in "./__pyrpc.ts" is not style, it is the difference between a sibling file and a package that was never published.

·7 minDeep Dive

When the config is too weird: failing loud

A two-state return value, a yellow warning, and the exact remediation hint, the calibrated failure ladder when a config cannot be safely edited.

·6 minDeep Dive

Two alias shapes: Vite resolve.alias vs Turbopack resolveAlias

The same aliasing idea expressed in two bundler dialects, and why a shared splice core plus a per-tool snippet table is the right structure.

·8 minDeep Dive

Inserting into a config object without parsing it

How a one-line splice at the closing brace, an idempotency guard, and write-on-change logic keep config edits safe across hundreds of regenerations.

·10 minDeep Dive

A mini JS tokenizer for safe config editing

The hand-rolled tokenizer behind bundler config edits: skipping strings, comments, and template-literal interpolations so brace matching never misfires.

·6 minDeep Dive

Detecting the bundler by config filename

Six filenames, two frameworks: how pyrpc decides which bundler you use by walking the client directory for vite.config and next.config signatures.

·9 minDeep Dive

The node_modules resolution gap

Why tsconfig paths work for TypeScript and webpack but not for imports originating inside node_modules, and the bundler alias that closes the gap.

·6 minDeep Dive

Two channels: compile-time types and runtime kinds

TypeScript erases types at runtime. procedureKinds is the runtime channel that mirrors the compile-time Types channel, and the generated module is where both meet.

·7 minDeep Dive

Fail closed: why the placeholder throws

v0.9.0's placeholder exposed both hooks on every procedure; v0.12.0's throws. A comparison of two failure modes and why the strict one is the safe default.

·8 minDeep Dive

The placeholder that throws

Before pyrpc dev runs, @pyrpc/types ships a Proxy placeholder whose procedureKinds throws on access, so a misconfigured resolution fails loud instead of silently showing every hook.

·7 minDeep Dive

The _pyrpcKind brand and type-level kind inference

Every generated procedure carries a readonly _pyrpcKind brand. InferProcedureKinds reads it in a mapped type so the compile-time type system knows whether .useQuery or .useMutation exists.

·10 minDeep Dive

Parsing Python type strings into TypeScript

The string-grammar parser behind _pytype_to_ts: how Optional, Union, List, Dict, Tuple, and Set annotations become nullable unions, arrays, and records, and where it falls back to any.

·9 minDeep Dive

Inside the codegen template

How client.ts.j2 renders Types, the _pyrpcKind brand, ProcedureKinds, and the procedureKinds const from a Python schema dict.

·5 minDeep Dive

The generated file's contract

The header of __pyrpc.ts is not decoration: it documents how the file is resolved, when it is regenerated, and what happens if you edit it by hand.

·8 minDeep Dive

From .d.ts to .ts: when types became a runtime module

Why v0.12.0 stops emitting a declaration-only __pyrpc.d.ts and generates a real __pyrpc.ts module that carries both compile-time types and the runtime procedureKinds map.

·9 minDeep Dive

The life of pyrpc.json: from wizard to watcher to CI

How a small JSON file is born in the wizard, found by walking up, read by every command, and hot-reloaded by a running dev session.

·7 minDeep Dive

The dev console: a control panel, not a shell

Six commands (procedures, inspect, generate, restart, exit) and why the console deliberately stops at the dev loop instead of becoming a REPL.

·7 minDeep Dive

Manual entry as a first-class wizard action

How v0.11.1 makes manual client entry a first-class wizard action, chosen before the checkbox list, so detected-project selections are never silently discarded.

·8 minDeep Dive

Threads, timers, and the missing import time: how regeneration stays safe

The debounce timer, the timer lock, the regen lock, and the one-line import bug that silently silenced the regen log.

·9 minDeep Dive

Reloading modules in the watcher: import vs reload

Why a fresh import is not enough, how importlib.reload refreshes procedures without restarting the server, and the tradeoffs of reloading modules.

·8 minDeep Dive

Surgical tsconfig edits: injecting @pyrpc/types with jsonc-edit

The tsconfig.json edit that lets generated types reference @pyrpc/types, when it happens, and the edge cases we handle.

·9 minDeep Dive

Multi-client support: one Python server, many frontends

The clients array in pyrpc.json, per-client __pyrpc.d.ts generation, and the live-watch reload when clients change.

·7 minDeep Dive

pyrpc dev --yes: non-interactive setup for CI and scripts

Fully explicit --yes --module --client, auto-detected clients and frameworks, and a hard error instead of a guess when multiple frontends exist.

·8 minDeep Dive

The zero-codegen workflow: save, wait 300ms, types are fresh

How the watch scope, .py filtering, and a 300ms debounce turn "edit Python, save" into regenerated TypeScript with no codegen command at all.

·11 minTutorial

Django + Next.js: RSC prefetch with a Django backend

The django-nextjs example: Django async views with pyRPC, createNextClient pointing at Django, server-side prefetch in RSC, and client-side useQuery/useMutation.

·7 minDeep Dive

pyrpc watch: type generation without the server

The type-watcher half of pyrpc dev with the server management removed: the same regeneration pipeline, minus uvicorn, port probing, and the interactive console.

·9 minTutorial

Django + Svelte: async Python backend, reactive Svelte stores

The django-svelte example: Django 4.2+ async views, createSvelteClient, and the $ store subscription pattern with TanStack Svelte Query.

·9 minTutorial

Django + Vue: async Django backend, Vue 3 composables

The django-vue example: Django async views with pyRPC, createPyrpcVue with app.use(pyrpc.plugin), and reactive createQuery composables.

·11 minTutorial

Django + React: native async views, typed React hooks

The django-react example: async @rpc.query/@rpc.mutation views, why you must import views in urls.py, django-cors-headers setup, and createReactClient.

·9 minTutorial

Flask + Next.js: App Router with a Flask backend

The flask-nextjs example: mount_flask on port 5000, createNextClient with the Flask baseUrl, server-side prefetch, and client-side hooks.

·6 minDeep Dive

Probing the server: how pyrpc dev knows uvicorn is already running

One HTTP probe, a one-second timeout, and a server_managed flag that decides whether pyRPC starts uvicorn or attaches in watcher-only mode.

·8 minTutorial

Flask + Svelte: minimal server, typed Svelte stores

The flask-svelte example: a two-file Flask server, createSvelteClient, and reactive stores, the smallest possible pyRPC stack.

·8 minTutorial

Flask + Vue: zero-ceremony Python backend, Vue 3 frontend

The flask-vue example: mount_flask with flask-cors, createPyrpcVue pointing at port 5000, and Vue Composition API composables.

·9 minTutorial

Flask + React: lightweight Python, full type safety

The flask-react example explained: mount_flask, flask-cors, createReactClient on port 5000, and the same useQuery/useMutation hooks as every other React adapter.

·9 minTutorial

FastAPI + Svelte: typed Python procedures as Svelte stores

createSvelteClient, QueryClientProvider in +layout.svelte, createQuery/createMutation stores, and the $ subscription pattern, the fastapi-svelte example explained.

·8 minDeep Dive

Types in your source tree: why generated types left node_modules

The design decision behind committing generated types to the client repo, and what it means for editors, CI, and deployment.

·9 minTutorial

FastAPI + Vue: TanStack Vue Query with a Python backend

createPyrpcVue, pyrpc.plugin, createQuery with reactive args, and createMutation, the complete fastapi-vue example explained.

·12 minTutorial

FastAPI + Next.js: RSC prefetch with a Python backend

How api.prefetch, api.dehydrate(), and api.HydrationBoundary work together to give you instant data in Server Components, with a FastAPI backend.

·7 minDeep Dive

Framework auto-detection: reading the room from config files

How pyrpc recognizes Vite, Next.js, React, Vue, Svelte, and other frontends from package.json before the wizard has to ask.

·10 minTutorial

FastAPI + React: full-stack type safety from zero

Step-by-step: FastAPI server with @rpc.query/@rpc.mutation, createReactClient, api.Provider, and useQuery/useMutation, the complete fastapi-react example explained.

·8 minDeep Dive

Designing the pyrpc dev setup wizard: two questions, zero friction

How the first-run wizard asks the module and client questions, why --reconfigure pre-fills, and where detection takes over from prompts.

·7 minDeep Dive

uvicorn --reload by default: how pyrpc dev manages the server

How pyrpc dev spawns uvicorn with --reload by default, the two independent reload paths, the restart command, and when to choose --no-reload.

·14 minTutorial

From tRPC to pyRPC: what stays, what goes, what gets easier

Side-by-side comparison for tRPC users: same hooks, Python server, no Zod, no links chain.

·12 minDeep Dive

Why we chose TanStack Query, and what it gives you for free

Caching, stale-while-revalidate, deduplication, and mutation invalidation without reinventing the wheel.

·8 minDeep Dive

Testing procedure kinds: what we covered

Tests across four layers: Python decorators, introspection schema, codegen output, and adapter proxy.

·8 minDeep Dive

Backward compatibility: how @rpc stayed working through v0.9.0

Why bare @rpc, no-kinds adapters, and existing installs all work without changes.

·12 minDeep Dive

The CI/CD publish pipeline: tag-triggered, chained, OIDC

How publish.yml chains 6 jobs: PyPI via OIDC, npm types/client/react/adapters, and GitHub Release.

·10 minDeep Dive

How we publish: from git tag to npm and PyPI

The full release flow: release.mjs, tag push, CI chain, OIDC for PyPI, and manual fallback.

·8 minTutorial

The Svelte adapter: framework-native, zero ceremony

How createSvelteClient integrates with TanStack Svelte Query stores and Svelte-native patterns.

·8 minTutorial

The Vue adapter: same contract, Vue-native patterns

How createPyrpcVue uses plugins instead of providers, composables instead of hooks.

·12 minTutorial

Building the Next.js example app: file by file

Walkthrough of examples/fastapi-nextjs: server.py, lib/pyrpc.ts, layout, RSC prefetch, and client hooks.

·6 minDeep Dive

The tiny change in @pyrpc/types that powers everything

Why ProcedureKinds and procedureKinds are in @pyrpc/types, and how the const satisfies pattern works.

·10 minDeep Dive

The npx daemon: 715x faster type generation

How a persistent Node.js process drops jsonschema-ts from 3.3s to 4.6ms.

·10 minDeep Dive

Inside the codegen template: what client.ts.j2 generates

What the Jinja2 template produces: Types interface, ProcedureKinds, procedureKinds, and model interfaces.

·8 minDeep Dive

Router.merge: how pyRPC handles namespaces

Split procedures into separate modules and combine them with Router.merge() for larger projects.

·12 minDeep Dive

How procedure kinds flow from Python to TypeScript

Trace @rpc.query/@rpc.mutation from Python decorator through introspection, codegen, and into typed hooks.

·10 minDeep Dive

Publishing guide: npm @pyrpc/* and PyPI

release.mjs, build order, GitHub Actions tag publish, and manual npm/twine steps for new adapter packages.

·8 minRelease

v0.9.0, Framework adapters, procedure kinds, one api object

Release notes for @pyrpc/react, next, vue, svelte, server kinds, and the unified api DX.

·7 minTutorial

Migrating from createClient to TanStack hooks

Keep Promise calls via api.client / createCaller while adopting useQuery, and annotate mutations on the server.

·9 minTutorial

Vue and Svelte adapters: same contract, stack-native setup

createPyrpcVue with api.plugin, createSvelteClient with createQuery/createMutation, and TanStack conventions per framework.

·8 minTutorial

Guide: @pyrpc/react from zero to useQuery

Minimal install, api.Provider, useQuery/useMutation, and useUtils for a Vite or CRA-style React app.

·11 minDeep Dive

Next.js RSC: prefetch, dehydrate, and HydrationBoundary

What each server helper does, when you can skip hydration, and why prefetch is for queries not mutations.

·10 minDeep Dive

@rpc.query and @rpc.mutation: why procedure kinds exist

How server-side query/mutation kinds flow through codegen into TanStack hooks without a second import in app code.

·9 minDeep Dive

One api object: Provider, prefetch, and hooks in the same place

Why createNextClient / createReactClient return a single value with procedures, Provider, and server helpers, and why the variable can be named api or client.

·12 minDeep Dive

How to version, edit, and ship pyRPC’s multi-package surface

Synchronized npm @pyrpc/* versions, PyPI independence, what to edit where, and PR/release standards for a multi-package monorepo.

·14 minTutorial

Tutorial: Next.js App Router + TanStack Query with pyRPC

Step-by-step: @rpc.query/@rpc.mutation, createNextClient, RSC prefetch, HydrateClient, and client hooks.

·18 minDeep Dive

Deep dive: framework adapters, TanStack Query, and procedure kinds

Architecture of @pyrpc/react, next, vue, and svelte, one transport, flat DX, query/mutation kinds, and Next.js hydration.

·8 minDeep Dive

Following an RPC Call: From TypeScript Client to Python Function and Back

A step-by-step trace through pyrpc's RPC Call Flow: Proxy interception, HTTP transport, envelope validation, Router lookup, Procedure execution with TypeAdapters, and the error path.

·10 minDeep Dive

A Visual Tour of pyrpc's Architecture

Eight diagrams, seven packages, one framework: a guided walkthrough of pyrpc's architecture from the system landscape down to individual components and dynamic flows.

·8 minDeep Dive

Architecture as Code: Mapping pyrpc with LikeC4

How we turned pyrpc's architecture into version-controlled, interactive diagrams using LikeC4, and why every framework should do the same.

·8 minDeep Dive

715x faster type generation with the npx daemon

A persistent Node.js daemon replaces per-call npx subprocesses, dropping type regeneration from 3.3s to 4.6ms. How it works, the benchmarks, and the edge cases we handled.

·4 minRelease

v0.7.3 - Django adapter, FastAPI/Flask fixes

A new Django adapter (pyrpc-django-adapter) with native async views, plus an introspection crash fix that affected all adapters when no explicit router was provided.

·10 minRelease

v0.6.0 - Client distribution and package standardization

npx pyrpc sync, postinstall prompt, framework extras (pyrpc-core[fastapi], pyrpc-core[flask]), adapter auto-install, pyrpc.json config, distribution modes, and package standardization.

·9 minDeep Dive

Server mode: type distribution across repositories

How server mode works: the schema endpoint stays in memory, pyrpc never writes to the client filesystem, and the client fetches types on demand via npx pyrpc sync.

·7 minDeep Dive

Workspace mode: what happens when you run pyrpc dev

A step-by-step walkthrough of workspace mode: config resolution, client root validation, migration checks, file watcher loop, dev server startup, and CI compatibility.

·8 minDeep Dive

Distribution modes: workspace and server

Two distribution modes for pyrpc: workspace (monorepo, types written directly to client) and server (separate repos, types fetched via HTTP). When to use each and how they work under the hood.

·7 minDeep Dive

Why save_typescript_client() refuses relative paths

The hidden bug in os.getcwd() fallback paths - why a silent default is worse than a hard error, how the CLI layer resolves paths before calling the API, and the "fail fast on global state" design principle.

·8 minDeep Dive

No pyrpc init needed: designing the integrated setup wizard

Why pyrpc embeds setup inside pyrpc dev instead of a separate init command: fewer context switches, --reconfigure pre-fills defaults, CLI flags skip the wizard entirely, and KeyboardInterrupt exits cleanly.

·9 minDeep Dive

Three deployment architectures for pyrpc

Monorepo, separate repos, and published npm package - how pyrpc's config system and type generation handle all three workflows, and why server-side codegen was built before the client-side npx CLI.

·10 minDeep Dive

Three cases, zero data loss: pyrpc's types migration strategy

What happens when you change client_root in pyrpc.json? Three cases with SHA256 comparison, interactive prompts only when needed, and a clean KeyboardInterrupt path that never leaves half-migrated state.

·8 minDeep Dive

Path resolution in pyrpc: config-relative, not CWD-relative

Why resolving paths against pyrpc.json's directory (not os.getcwd()) is the only correct approach, how the pipeline produces absolute paths everywhere, and why save_typescript_client() enforces the contract at the boundary.

·9 minDeep Dive

pyrpc.json: why we left pyproject.toml behind

Three problems with [tool.pyrpc] in pyproject.toml - fragile writing, ambiguous file ownership, and unclear path semantics - and why a dedicated pyrpc.json file with JSON, not TOML, was the right answer.

·8 minRelease

v0.3.3 - Cleaner types, no more /rpc/rpc, quieter watcher, CORS included

TypeScript autocomplete no longer suggests .rpc, URL normalization prevents double /rpc/rpc, file watcher debounced to 300ms, and the ASGI dev server now sends CORS headers - all following reference patterns from tRPC, Better Auth, FastAPI, webpack, and nodemon.

·6 minRelease

v0.3.2 - Cleaner terminal, smarter prompts, no more :app confusion

Interactive framework picker, simplified entry point, CWD import path fix, and a terminal that shows what matters - no Uvicorn spam, no raw [cyan] markup, no giant Panel boxes.

·4 minRelease

v0.3.1 - Lazy imports, pyrpc_codegen decoupled from CLI

pyrpc_codegen is no longer loaded for version, inspect, serve, pull, or help - only codegen and dev need it. A patch triggered by a stale shim bug.

·5 minRelease

v0.3.0 - pyrpc-cli merged into core, one-command install

pip install pyrpc-core now gives you the runtime, CLI, and codegen in a single command - no separate packages, no extra steps.

·7 minRelease

Why we merged pyrpc-cli back into pyrpc-core

How the circular dependency that motivated a three-package split disappeared - and why we simplified back to two packages for a single-install experience.

·11 minDeep Dive

How to break a circular dependency in Python packaging

Four strategies for breaking circular package dependencies in Python, evaluated through pyrpc’s real-world restructuring, with a step-by-step extraction guide.

·7 minDeep Dive

Windows compatibility in a Python OSS project: what we learned

Unicode crashes on cp1252, LF/CRLF git warnings, path separators, file watcher quirks, and a no-special-chars policy for cross-platform Python OSS.

·8 minDeep Dive

Lazy imports as API contract, not performance hack

Three tiers of CLI commands, the packaging-vs-code dependency distinction, and why lazy imports define capability boundaries, not just startup time.

·9 minDeep Dive

The Better Auth meta-package pattern, adapted for Python

How Better Auth’s npm meta-package inspired pyrpc’s package architecture, and how we adapted it for Python’s packaging constraints.

·7 minDeep Dive

Core → CLI → Codegen: why the dependency direction matters

Why pyrpc-core → pyrpc-cli → pyrpc-codegen is the right dependency direction - and three principles for designing package chains that never tangle.

·8 minDeep Dive

Dev console vs shell: two tools, one job, and the line between them

Why the dev console reads from the parent process (not HTTP), how the shell connects remotely, and the shared REPL UI that bridges them.

·10 minDeep Dive

The circular dependency problem and how pyrpc-cli solved it

How we discovered and solved the circular dependency between pyrpc-core and pyrpc-codegen by extracting pyrpc-cli - with three alternative strategies evaluated and a step-by-step extraction guide.

·12 minRelease

CLI overhaul, model interfaces, and the dev tools we built

Merging pull into codegen, fixing serve, adding the dev watcher and shell REPL, and integrating jsonschema-ts for Pydantic model interfaces.

·14 minDeep Dive

Designing the pyrpc developer console

Threads, subprocesses, and an embedded interactive console - how pyrpc dev combines a dev server, file watcher, type generator, and CLI into one terminal session.

·6 minRelease

v0.2.0 - Type safety, proper async, and @pyrpc/types

The three critical fixes that ship v0.2.0: real type generation, working async, and a postinstall-based @pyrpc/types setup.

·8 minRelease

Cleaner codegen, one CLI, and a sharper story

Pattern A CLI, lazy pyrpc-core imports, frontend DX simplified to npm install, cross-language positioning, SECURITY.md rewrite, and Windows cp1252 fixes.

·8 minDeep Dive

Inside the Interactive Demo Sandbox

A deep dive into how the pyrpc playground works - design decisions, architecture, and a comparison with the real pyrpc implementation.

·6 minTutorial

Why pyRPC?

The philosophy behind pyRPC, what tRPC-style typing means for Python backends, and why we built it.

·7 minTutorial

From raw FastAPI to pyRPC

A before-and-after migration guide showing how to convert a traditional FastAPI application to pyRPC - and why you might want to.

·10 minTutorial

Building a full-stack app with pyRPC

A step-by-step tutorial: FastAPI backend, TypeScript React frontend, end-to-end type safety with pyRPC.