pinecallDocs
Python / Production

Production

How a server runs a Python agent: pinecall start --prod, or pinecall.hold in your own process.

How a Python agent runs where its callers reach it. There are two ways, and neither is Pinecall's own servers yet.

The server's token#

A server runs on a server's token, minted for production in the console (Settings ▸ Keys) or with pinecall keys. It was made for one world and opens that one alone: put it in the server's secrets as PINECALL_KEY, never in the repository. A person's key works too while their production switch is on, but a server should not run on a person.

(a) Inside your own Python app#

When the app is already a Python process that stays up — a FastAPI service, a worker — the agent can live in it. pinecall.hold mounts the class on a client of its own, connects, and hands back what it holds; stop drains the calls to the next holder and closes:

Python
import os

import pinecall

from clinica.agent import ClinicaNorte  # a module of your app, like any other


async def lifespan(app):
    held = await pinecall.hold(
        ClinicaNorte, url="https://cloud.pinecall.io", api_key=os.environ["PINECALL_KEY"]
    )
    yield
    await held.stop()  # the live calls are handed over, not cut

pinecall.Client reads nothing from the environment: the app hands it the gateway and the key it keeps. A person's key would need env="production"; a server's token needs nothing. The class registers under its own slug, or its name in kebab-case, and its view is views/<slug>.jinja beside the module's file.

(b) pinecall start --prod, from the one CLI#

The pinecall command is the Node CLI (npm i -g pinecall), for every language. In the project's folder it finds agents/<name>/agent.py, and pinecall start --prod starts this package's serve entry with the project's own interpreter — .venv/bin/python -m pinecall.serve start … when the project has a .venv, else python3 — and watches it; beside it, it holds the socket that answers the console. Run that line under whatever keeps the app's processes up:

agent: pinecall start --prod

Node on the server is that verb's price; (a) is the way without it.

A deploy never cuts a call. On SIGTERM the serve entry drains: the gateway hands its live calls to another process holding the agent, or keeps them for the next one, and the tools running are let finish, up to 30 seconds; one line on stderr says where the calls went. Give the process 45 seconds between the signal and the kill — systemd's TimeoutStopSec=45, pm2's --kill-timeout 45000. A second signal leaves at once, and so does the end of its stdin: the CLI that started it is gone.

A refusal at start — the file cannot be served, the class is refused, the gateway will not take the slug or the key — is one sentence on stderr and exit status 2, so a supervisor that restarts on failure does not loop on it silently. PINECALL_LOG=debug writes the package's own log to stderr, each line timed: when a call opened, and every entry read with how late it arrived.

What the agent searches is pushed before the deploy, not with it: pinecall docs push --prod.

Not hosted by Pinecall yet#

pinecall deploy runs a project on Pinecall's own servers in a Node container, and a Python project is not one of those yet — pinecall deploy says so, and says to run (a) or (b) on your own server instead. Python in the runner's image and an install step are a plan of their own.