pinecallDocs
Guides / Run it on your own server

Run it on your own server

The agent inside your Node app or as a process of its own, with a server token.

Production's agent is an ordinary process: the same pinecall start you run on a laptop, with --prod, on a server token of the org. Run it inside the Node app you already have, or as a process of its own beside it.

How it works#

Your process opens a socket to the gateway and holds the agent. Calls reach it over that socket, so it listens on no port and needs no public address.

If you would rather not run a server at all, Deploy to Pinecall runs the same process for you.

The server token#

Make it#

Open production's console, Settings ▸ Tokens, name the token after what runs it (clinica web) under New production server token, and press Create. Production's token is made by somebody with production access.

Copy it#

It is shown once, as the line to paste:

Terminal
PINECALL_KEY=pc_live_…

Keep it in the server's secrets#

Your platform's config vars, a systemd EnvironmentFile, the container's secret: wherever the app's database URL is kept. A lost token is revoked from its row and a new one made.

A token opens only the sandbox or only production, whichever it was made in, and its prefix says which: pc_live_ for production, pc_test_ for the sandbox (made on the sandbox's console, for CI). The verb must agree: the CLI refuses a pc_test_ token with --prod, and the gateway refuses a production token used without it:

this key is a production server's token, and this request is for sandbox: a server's token opens the world it was made in

PINECALL_URL goes beside the key only when your gateway is not https://cloud.pinecall.io. It is one address for the sandbox and production.

Inside your Node app#

server.ts
import { readFileSync } from "node:fs";
import { mount } from "@pinecall/agents";
import { Pinecall } from "@pinecall/agents/client";

import FrontDesk from "./agents/front-desk/agent.js";

const pc = new Pinecall({ url: "https://cloud.pinecall.io", apiKey: process.env.PINECALL_KEY });
mount(FrontDesk, { pc, source: readFileSync(new URL("./agents/front-desk/agent.tsx", import.meta.url), "utf8") });
await pc.connect();

process.on("SIGTERM", () => void pc.drain().finally(() => pc.close()));

new Pinecall reads nothing from the environment: you hand it the URL and the key. source is the agent file's own text. Compiling removes the class docstring and the tools' parameter types, and this is how they come back, so ship the .tsx beside your build. Call drain() before close().

A class mounted this way draws no side panel: the panel is answered by the process pinecall start runs.

A process of its own#

Run pinecall start --prod under whatever keeps your processes up. In a Procfile:

Procfile
web: node dist/server.js
agent: pinecall start --prod

With pm2 it is pm2 start "pinecall start --prod" --name agent; with systemd, the same line as ExecStart. It prints one line per log entry on stdout, or JSON lines with --events. A project of several agents runs them all in one process, or one per process with --agent <name>. pinecall start is a Node program whatever language the agent is written in, so the server needs Node.

If the gateway restarts, the process prints a line ending in reconnecting, dials again on its own, and prints gateway back. Calls in progress go on.

Deploys and restarts#

On SIGTERM the process drains: it tells the gateway it is leaving, the gateway hands its live calls to another process holding the agent, or keeps them for the next one, and running tools are allowed to finish. pinecall start gives the agent's process 40 seconds before it kills it, so give pinecall start 45:

manager setting
pm2 --kill-timeout 45000 (its default is 1.6 s, which cuts every tool in flight)
systemd TimeoutStopSec=45, KillSignal=SIGTERM
a platform with a fixed grace calls still move; a tool slower than the grace may be cut

Start the new process as soon as the old one has the signal: the calls it kept wait for the new one to register.

What is running#

pinecall agent list --prod prints every process holding the org's agents in production: the agents, the machine and address it connected from, the SDK, and since when. pinecall agent stop <app> closes one, and pinecall start exits instead of dialling back. A manager that restarts whatever exits starts it again, so stop it where it is managed.

Next steps#