Your first Python call¶
Verified this session
Every command and output below was run against main: the Windows
path was validated against the checked-in evidence in
examples/python-math/README.md; the Linux path (build, runtime,
provider, invocation, overflow rejection, no-provider handling, and
graceful shutdown) was independently re-run end to end in this session
inside WSL2 Ubuntu. add(2, 3) really does return 5, computed by the
Python process — there is no addition logic in the C runtime or the
CLI.
This walks through examples/python-math/: a real Python process
implementing math.add, registered against the shipped root
Polycallfile, invoked through the polycall CLI over the real wire
protocol (LPV1-06).
Prerequisites¶
- Built binaries: run
make all(Linux) or.\build-windows.ps1 -Target rebuild(Windows) first — see Getting started. - Python 3.8 or later, standard library only. No
pip installis needed;provider.pyuses onlysocket,struct,json,subprocess, and (on Windows)ctypes. - Run everything from the repository root — the shipped
Polycallfileandrequest.jsonlive there.
The three terminals¶
| Terminal | Runs | Role |
|---|---|---|
| 1 | polycall runtime start |
the runtime: binds runtime.listen, accepts connections, authenticates, dispatches calls |
| 2 | python examples/python-math/provider.py |
the provider: registers math.add, serves invocations |
| 3 | polycall call invoke |
the caller: sends one typed request, prints the typed result |
Windows PowerShell¶
Terminal 1
.\bin\polycall.exe runtime start .\Polycallfile
runtime ready, listening
press Ctrl+C to stop
Terminal 2
python .\examples\python-math\provider.py .\Polycallfile
provider: registered math.add (generation 1); serving (Ctrl+C to stop)
.\Polycallfile here is a real positional argument that provider.py
accepts and passes straight to polycall.exe config show --json as a
subprocess — the script never parses Polycallfile syntax itself (see
Core concepts).
[security] mode = "local-auto" in the shipped file means no manual token
setup: the runtime auto-generates a shared credential into Windows
Credential Manager on start, and the provider reads that same entry.
Terminal 3
.\bin\polycall.exe call invoke --service math --method add --input .\request.json --json .\Polycallfile
{"ok":true,"command":"call","subcommand":"invoke","status":"completed","data":{"result":{"type":"i64","value":"5"}},"error":null}
Terminal 2 prints provider: add(2, 3) = 5 at the same moment — that
value came from the Python process.
Linux¶
make all # once
./bin/polycall runtime start ./Polycallfile # terminal 1
python3 ./examples/python-math/provider.py ./Polycallfile # terminal 2
./bin/polycall call invoke --service math --method add --input ./request.json --json ./Polycallfile # terminal 3
local-auto on Linux stores the credential in
~/.polycall-credentials/<runtime name> (or $XDG_RUNTIME_DIR if set)
instead of an OS credential manager; both the runtime and the provider
resolve it the same way automatically.
request.json (already at the repository root):
{"args":[{"type":"i64","value":"2"},{"type":"i64","value":"3"}]}
What else was tested, and what actually happens¶
Overflow is rejected, not wrapped or truncated. Requesting
add(9223372036854775807, 1) returns a structured error instead of a
silently wrong number:
{"ok":false,"command":"call","subcommand":"invoke","status":"provider_error","data":null,"error":{"code":"provider_error","message":"result is out of the signed 64-bit range"}}
exit code 2. Python integers do not overflow the way C's do, so this is
a check against the wire's declared i64 range, performed before the
value is ever put on the wire — not an accident of Python's arbitrary
precision.
No provider connected is reported honestly, never faked. Before the Python process registers (or after it disconnects), the same invocation returns:
{"ok":false,"command":"call","subcommand":"invoke","status":"unavailable","data":null,"error":{"code":"unavailable","message":"no eligible provider"}}
exit code 7.
Clean shutdown, on both platforms. polycall runtime stop --json .\Polycallfile
(note: options must come before the Polycallfile path — see
CLI reference) or Ctrl+C in terminal 1
drains and exits the runtime, and the provider notices its connection
close and exits on its own with provider: stopped.
Bug found and fixed this session
Before this session, a clean runtime stop on Linux hung
indefinitely: the shutdown code closed the listening socket and each
connection's socket to unblock threads waiting in accept()/recv(),
which reliably wakes those calls on Windows but not on Linux. Verified
hung for 15+ seconds with strace-visible futex_do_wait, then fixed
in src/transport/polycall_server.c by calling shutdown() before
close() on every connection socket, and forcing the blocked accept
thread to return with a local loopback self-connect before closing the
listening socket. Re-verified: both platforms now exit within
~1 second of a stop request, with a provider connected.
Stopping cleanly¶
Press Ctrl+C in terminal 1 (or run polycall runtime stop --json ./Polycallfile
from a fourth terminal), then Ctrl+C in terminal 2 if the provider hasn't
already exited on its own.
Also available: the C provider¶
examples/quickstart-math/ is the same demonstration using the public
polycall_provider_* C API instead of a hand-written wire client — see
Language integration.