python · finom — скилл для Claude Code: типизированный Python-клиент из Vovk API
Скилл генерирует типизированный Python-пакет из схем Vovk.ts: RPC-функции, TypedDict, стриминг через JSON Lines. Нужен, когда API уже есть, а Python-клиент писать руками не хочется.
npx skills add finom/vovk --skill python -a claude-codeЧто делает python
Скилл опирается на vovk-python и те же артефакты .vovk-schema/, что и TypeScript-клиент. Один источник правды, два языка. Шаблон py собирает готовый пакет под PyPI: __init__.py с RPC-функциями и TypedDict, api_client.py, py.typed, schema.json, pyproject.toml на hatchling. Шаблон pySrc выдаёт только .py-файлы — их кладут в существующий проект.
Методы статические, имена в snake_case, типы в PascalCase. Порядок позиционных аргументов задаёт генератор: body, files для multipart, query, params, затем всегда headers, api_root и disable_client_validation. Процедуры с iteration дают на клиенте синхронный генератор: next(), list(), выход из цикла через break.
Перед генерацией задайте clientTemplateDefs.py.outputConfig.origin — клиент шлёт запросы на абсолютный URL, и без origin каждый вызов потребует api_root, а vovk generate предупредит. Генератор синхронный, на requests; для asyncio стрим придётся запускать в отдельном потоке. Разовые HTTP-запросы к /api/... этот скилл не покрывает — там хватит curl или httpx.
Какие задачи решает
- сгенерировать Python-пакет из схем Vovk API
- получить автодополнение полей в редакторе через
TypedDict - разложить стриминг JSON Lines на синхронный генератор
- запечь продовый URL в клиент при генерации
- собрать пакет под публикацию на PyPI
Примеры запросов агенту
- Сгенерируй Python-клиент из схемы через
vovk-pythonв./dist_python - Подключи шаблон
pyвvovk.config.mjsи пропишиoriginпродового API - Сделай стриминг токенов из процедуры
completeи собери ответ в список
Как установить python
1Через Skills CLI (Vercel)
npx skills add finom/vovk --skill python -a claude-code2Вручную: положить файлы
~/.claude/skills/python/SKILL.mdПапка скилла целиком; для одного проекта — .claude/skills/python/
1Через Skills CLI (Vercel)
npx skills add finom/vovk --skill python -a codex2Вручную: положить файлы
.agents/skills/python/SKILL.mdДля всех проектов — ~/.agents/skills/
1Через Skills CLI (Vercel)
npx skills add finom/vovk --skill python -a cursor2Вручную: положить файлы
.cursor/skills/python/SKILL.mdCursor читает и .agents/skills/, и .claude/skills/
1GitHub CLI
gh skill install finom/vovk python2Вручную: положить файлы
.github/skills/python/SKILL.md1Через Skills CLI (Vercel)
npx skills add finom/vovk --skill python -a gemini-cli2Командой платформы
gemini skills install https://github.com/finom/vovk --path skills/pythonВручную: положить файлы
.devin/skills/python/SKILL.mdСтарый путь .windsurf/skills/ тоже читается
Через Skills CLI (Vercel)
npx skills add finom/vovk --skill python -a opencodeClaude.ai
Упакуйте папку в zip и загрузите в Settings → Capabilities → Skills
По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов
Вопросы о python
Как установить скилл python в Claude Code?
Выполните npx skills add finom/vovk --skill python -a claude-code. Файл скилла окажется в ~/.claude/skills/python/SKILL.md.
Что делает скилл python?
Генерирует типизированный Python-пакет из артефактов .vovk-schema/: RPC-функции, TypedDict-типы, HTTP-клиент и файлы сборки. Шаблон pySrc выдаёт только исходники для вставки в существующий проект.
Чем это отличается от обычного вызова API через requests?
Разовые запросы к /api/... проще сделать через curl или httpx — эндпоинты Vovk обычный REST. Скилл нужен, когда требуется сгенерированный типизированный клиент.
Исходный текст
SKILL.md · MIT
---
name: python
description: The Vovk.ts Python client — generating a typed Python package from a Vovk API with `vovk-python`, the `py` / `pySrc` templates, `TypedDict` shapes, JSON + JSON Lines consumption, client-side validation, and PyPI publishing. Use whenever the user wants a typed Python SDK, ongoing Python integration, or PyPI publishing — phrasings like "generate a Python client / SDK", "ship a Python package for my API", "use vovk-python", "pySrc template", "python client streaming", "publish to PyPI". Does NOT cover controller / procedure authoring → hand off to `procedure` skill. Does NOT cover `vovk bundle` in general → hand off to `bundle` skill. Does NOT cover JSON Lines server-side → hand off to `jsonlines` skill. **Does NOT cover one-off HTTP calls** — Vovk endpoints are plain REST, so a `curl`, `httpx`, or `requests` call against `/api/...` is the simpler answer for "I just want to hit my API from a Python script / CLI / shell" use cases. Reach for this skill only when the user actually wants generated typed client code.
---
# Vovk.ts Python client
`vovk-python` generates typed Python package from same `.vovk-schema/` artifacts driving TS client. One source of truth, multi-language.
## Install + generate
```bash
npm i -D vovk-python
```
### Standalone package
Emits complete Python package (PyPI-ready). Canonical output dir `./dist_python` (hello-world convention):
```bash
npx vovk generate --from py --out ./dist_python
```
Output:
```
dist_python/
src/<package_name>/__init__.py # RPC functions + TypedDict definitions
src/<package_name>/api_client.py # HTTP client
src/<package_name>/py.typed # Type-hint marker
src/<package_name>/schema.json # Generated schema
pyproject.toml # hatchling build backend
setup.cfg
README.md
```
### Embedded source
Emits `.py` files only — drop into existing Python project:
```bash
npx vovk generate --from pySrc --out ./python_src
```
## Auto-generate with composed client
Wire Python into `vovk generate` → runs alongside TS:
```ts
// vovk.config.mjs
const config = {
composedClient: {
fromTemplates: ['ts', 'py'],
},
};
export default config;
```
**Bake prod API URL** via `clientTemplateDefs.py.outputConfig.origin` — generated client uses this by default. Required: client sends calls to an absolute URL, so without an origin every call needs `api_root`, and `vovk generate` warns. Pattern from hello-world:
```ts
// vovk.config.js
const PROD_ORIGIN = 'https://hello-world.vovk.dev';
const config = {
composedClient: { fromTemplates: ['ts', 'py'] },
clientTemplateDefs: {
py: {
extends: 'py',
outputConfig: { origin: PROD_ORIGIN },
// composedClient: { outDir: './dist_python' }, // override output dir if needed
},
},
};
```
After this, every `npx vovk generate` (+ every `vovk dev` regen) refreshes Python client — `PROD_ORIGIN` baked in for consumers, overridable per-call via `api_root`.
## Generated call shape
Types follow `[PascalCaseMethodName][Body|Query|Params|Output]` as `TypedDict`. Methods static, snake_case. Positional arg order: the generator only emits slots where validation declared, in this order: `body`, `files` (multipart only, sits between `body` and `query`), `query`, `params`, then always-present trailing kwargs `headers`, `api_root`, `disable_client_validation`. After them, optional: `body` for a POST, PUT or PATCH without a body schema, `query` without a query schema, and `files` for a multipart record body.
```python
from my_api_client import UserRPC # whatever package the generator wrote
body: UserRPC.UpdateUserBody = {
"email": "[email protected]",
"profile": {"name": "John Doe", "age": 25},
}
query: UserRPC.UpdateUserQuery = {"notify": "email"}
params: UserRPC.UpdateUserParams = {
"id": "123e4567-e89b-12d3-a456-426614174000",
}
# Keyword args work for clarity at call sites:
response = UserRPC.update_user(body=body, query=query, params=params)
```
Method names snake_case. Type names PascalCase. Names alike in snake_case (`getUserByID`, `getUserById`) get the first free suffix, per RPC class in schema order: `get_user_by_id`, `get_user_by_id_2`.
### Multipart uploads via `files`
Procedures with `multipart/form-data` accept `files` kwarg — pass `Dict[str, Any]` matching `requests` upload format:
```python
with open("avatar.png", "rb") as f:
response = UserRPC.upload_avatar(
params={"id": user_id},
files={"avatar": ("avatar.png", f, "image/png")},
)
```
## JSON Lines streaming
Procedures with `iteration` schemas (server-side `async function*` handlers — see **`jsonlines`** skill) generate **sync Python generators** client-side. Return type `Generator[<MethodName>Iteration, None, None]`. Generator only emits slots for validation declared on procedure — for an iteration-only endpoint with no body / query / params, signature is just trailing kwargs:
```python
@staticmethod
def stream_tokens(
headers: Optional[Dict[str, str]] = None,
api_root: Optional[str] = None,
disable_client_validation: bool = False,
) -> Generator[StreamTokensIteration, None, None]:
...
```
Add `body: StreamTokensBody`, `query: StreamTokensQuery`, `params: StreamTokensParams` to the signature only when the procedure declares validation for them (same rule as JSON endpoints).
Yielded items typed against procedure's `iteration` schema — `StreamTokensIteration` is `TypedDict` → editors autocomplete fields.
### Basic consumption
```python
from my_api_client import StreamRPC
for item in StreamRPC.stream_tokens():
print(item["message"], end="", flush=True)
```
### Standard generator patterns
Sync generators support usual idioms:
```python
# Manual pull
stream = StreamRPC.stream_tokens()
first = next(stream)
second = next(stream)
# Collect into a list (drains the stream)
all_items = list(StreamRPC.stream_tokens())
# Comprehensions
messages = [item["message"] for item in StreamRPC.stream_tokens()]
# Early termination — break out of the for-loop
for item in StreamRPC.stream_tokens():
if item["message"] == "STOP":
break
handle(item)
# The underlying HTTP connection closes when the generator goes out of scope.
```
### With body / query / params
Streaming endpoints accept same input shape as JSON:
```python
from my_api_client import ChatRPC
for token in ChatRPC.complete(
body={"messages": [{"role": "user", "content": "hello"}]},
query={"model": "gpt-4"},
):
print(token["text"], end="", flush=True)
```
### Error handling
HTTP fail or iteration validation fail → generator raises on next `next()`. Wrap in `try/except` to recover:
```python
try:
for item in StreamRPC.stream_tokens():
handle(item)
except Exception as exc:
log.error("stream failed mid-iteration: %s", exc)
```
### Sync, not async
Generator **sync** — backed by `requests`, no async API. For asyncio, run iteration in thread pool (`asyncio.to_thread` or `loop.run_in_executor`) or wrap each `next()` call. Native async streaming not in current Python client.
See **`jsonlines`** skill for server-side handler.
## Client-side validation
Validation runs against `schema.json` by default — same Zod/Valibot shapes server enforces, cross-compiled to JSON Schema.
Skip for hot paths or server-only enforcement:
```python
response = UserRPC.update_user(
params=params, body=body, query=query,
disable_client_validation=True,
)
```
## Dependencies pulled in
Generated `pyproject.toml` declares (per hello-world):
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
requires-python = ">=3.9"
dependencies = ["requests", "jsonschema[format-nongpl]", "typing_extensions>=4.0.0; python_version < '3.12'"]
```
- `requests` — HTTP client; picks its own `urllib3`.
- `jsonschema[format-nongpl]` — client-side validation; the extra checks formats such as `uri` and `date-time` without GPL libraries. A `pattern` Python's `re` can't compile (`\p{L}`) is left to the server.
- `typing_extensions` — `NotRequired` and `TypeAlias` before Python 3.11.
Build backend **hatchling**, no runtime overhead past deps above.
## Auth + base URL
Generated client targets URL baked at generate time. Override per call via `api_root` kwarg — fully replaces baked-in value for that call. Auth: pass `headers` per call, or set them once on the module-level `client`, whose `session` every call shares:
```py
from my_api import client
client.session.headers["Authorization"] = "Bearer ..."
client.timeout = 30 # seconds, or a (connect, read) tuple; None waits forever
```
**Don't bake secrets into generated package.** Consumers supply API keys at runtime.
## PyPI publishing
Canonical script from hello-world (build wheel + sdist, upload via `twine`):
```bash
python3 -m build ./dist_python --wheel --sdist && python3 -m twine upload ./dist_python/dist/*
```
Both `python3 -m build` and `python3 -m twine` invoke modules directly — works with any Python env that has them installed (`pip install build twine`). Run `twine` with creds via `~/.pypirc` or `TWINE_USERNAME` / `TWINE_PASSWORD` env vars.
Wire into release flow alongside npm bundle + Rust crate (hello-world chains all three under `postversion`):
```json
"scripts": {
"publish:node": "npm publish ./dist",
"publish:rust": "cargo publish --manifest-path dist_rust/Cargo.toml --allow-dirty",
"publish:python": "python3 -m build ./dist_python --wheel --sdist && python3 -m twine upload ./dist_python/dist/*",
"postversion": "vovk generate && vovk bundle && npm run publish:node && npm run publish:rust && npm run publish:python"
}
```
Version / package name flow from root `package.json` (generator copies whitelisted fields — `name`, `version`, `description`, `license`, `author`, `contributors`, `repository`, `homepage`, `bugs`, `keywords` — into generated `pyproject.toml`). Set `version` in root `package.json`, `npm version patch` propagates to all three targets.
**Name transform — pin before publishing.** Python package name = root `name` with the scope's `@` dropped and every other character Python can't import → underscore (`my-api` → `my_api`, `@acme/web-app` → `acme_web_app`). Same name used for filesystem path (`src/<name>/`), `pyproject.toml` `name`, `pip install` command in README. Set a different distribution name than npm (e.g., npm `my-api`, PyPI `acme_client`) with `outputConfig.package.py_name`:
```js
// vovk.config.mjs
const config = {
composedClient: { fromTemplates: ['ts', 'py'] },
clientTemplateDefs: {
py: {
extends: 'py',
outputConfig: {
origin: 'https://api.example.com',
package: { py_name: 'acme_client' }, // PyPI name + filesystem path
},
},
},
};
```
## Flows
### "Call my Vovk API from a Python script"
1. `npm i -D vovk-python`.
2. Add `'py'` to `composedClient.fromTemplates` in `vovk.config.mjs`.
3. `npx vovk generate`.
4. `pip install -e ./dist_python` (or wherever generator wrote it).
5. `from vovk_hello_world import UserRPC` and call (editable install exposes the package directly — no `dist_python.src.` prefix).
### "Ship a Python SDK to PyPI"
1. `npx vovk generate --from py --out ./python_package`.
2. Set `version` (and `name`) in the root `package.json` before generating; to override them for this package only, use `clientTemplateDefs.py.outputConfig.package` (see above).
3. `python3 -m build && twine upload dist/*` from `python_package/`.
### "Consume a streaming endpoint from Python"
Server defines `procedure({ iteration })` with `async function*` handler (see `jsonlines`). Client iterates:
```python
for item in StreamRPC.stream_tokens():
handle(item)
```
### "Embed the client into an existing Python project"
Use `pySrc`:
```bash
npx vovk generate --from pySrc --out ./my_project/vovk_client
```
Then import from `my_project.vovk_client...`.
## Gotchas
- **`TypedDict`, not classes.** Generated shapes dict-based for JSON interop; treat as plain dicts with type hints, not Pydantic models.
- **Method names snake_case**, type names PascalCase. `updateUser` server → `update_user(...)` Python, `UpdateUserBody` etc.
- **Client-side validation uses `jsonschema`** — small import + runtime cost. Disable per-call for speed or server-only enforcement.
- **Base URL override is per-call.** `api_root` kwarg overrides the URL baked at generate time. Headers, timeout and cookies go on the module-level `client` (`client.session.headers`, `client.timeout`).
- **Regen on schema changes.** Any procedure / schema change server-side needs `vovk generate` before Python client reflects. CI should regen as part of build.
- **Don't hand-edit generated files.** Put shared Python utilities alongside, not inside, generated package.
- **Named schemas in `components/schemas` don't yet produce shared importable types.** Each call site gets own scoped `TypedDict` instead of single `UserSchema` reused across methods. Roadmap item — until fixed, expect duplicated type definitions.
© finom · MIT · finom/vovk
Похожие скиллы
Все скиллы по теме «Бэкенд и API» →Сначала — python от других авторов.