pinecallDocs
Guides / Deploy to Pinecall

Deploy to Pinecall

pinecall deploy: Pinecall installs and runs your project. Secrets, limits, logs, rollbacks.

pinecall deploy uploads your project, and Pinecall installs it and keeps pinecall start running for you in an isolated container. There is no server to rent, no process manager and no token to paste.

How it works#

Each upload is a release of an app: numbered from 1 and never edited. The release before keeps answering until the new one's agents have registered, so a deploy cuts no call.

Terminal
~/acme-support $ pinecall deploy --prod
acme-support: release 1 sent · 38 KB · 3b507661b052
acme-support: release 1 is live

Without --prod, everything on this page acts on the sandbox. The sandbox and production have separate apps, releases and secrets.

Before the first deploy#

  • A TypeScript project in the layout pinecall new writes: agents/<name>/ at the root, a package.json and a tsconfig.json. A Ruby or Python agent runs on your own server.
  • @pinecall/agents under dependencies. Pinecall installs production dependencies only, and starts the project with its own pinecall start: the CLI is never a dependency of the project. pinecall deploy refuses a project that does not list the framework there, before it sends anything.
  • A committed lockfile. pnpm-lock.yaml is installed with pnpm install --frozen-lockfile --prod, package-lock.json with npm ci --omit=dev. With neither, npm install --omit=dev resolves package.json again on every release.
  • No build step. pinecall start reads your .tsx files directly. Apps run on the official node:24-slim image, which has no compiler: use packages with prebuilt linux-x64 binaries.
  • A key that may deploy: one that opens app (the developer and admin roles), and for --prod, your production switch on.

The app's name is the folder's, or --name: lower-case words and dashes, 40 characters at most. The first upload makes the app, within the org's number of hosted apps there.

What happens when you deploy#

Packed#

The folder is packed as its .gitignore files leave it, each read where it sits; git is not asked, so a folder that is no checkout packs the same. node_modules/, .git/, dist/, .pinecall/, .DS_Store and every .env stay on your machine. A release is at most 10 MiB packed, 100 MiB unpacked and 5,000 files; a symbolic link or a path outside the folder is refused.

Kept#

The gateway keeps the release. The first one also mints a server token for the app, listed in the console's Tokens as hosted app <name>. Nobody ever sees its value.

Installed#

The dependencies are installed inside the same sandbox the app runs in, with 1 GiB of memory and 300 seconds at most.

Live#

pinecall start (--prod in production) starts with your secrets, the app's token and the gateway's address. Once its agents register, the release is live, and the one before drains: its calls move to the new process and its running tools finish, within 45 seconds.

The verb follows all of it for up to eight minutes and prints release N is live (exit 0) or why it failed (exit 1). --no-follow returns as soon as the release is kept.

A release fails when its install fails, when its process exits before its agents register, or when 120 seconds pass without a register. The release before keeps answering. A failed release is not tried again: fix it and deploy again.

Secrets#

.env never travels. Whatever your tools read from the environment is set as the org's secrets, the sandbox's and production's apart:

Terminal
$ printf %s "$CRM_TOKEN" | pinecall secrets set CRM_TOKEN --prod
CRM_TOKEN kept · the org's hosted apps here start again with it

Your code reads process.env.CRM_TOKEN as before. Every hosted app of the org there starts with every secret. A name is capitals, digits and underscores and never starts with PINECALL_; a value is 16 KB at most. Type the value or pipe it in, never on the command line. Nothing reads a value back: pinecall secrets lists names, who set each and when. Setting or removing one restarts every app of the org there, the old process answering until the new one registers.

variable set by
each of the org's secrets, the sandbox's or production's pinecall secrets set, or the console's Agents ▸ Secrets
PINECALL_KEY Pinecall: the app's own server token
PINECALL_URL Pinecall: the gateway's address, the same for the sandbox and production
HOME, TMPDIR /scratch
NO_COLOR 1

What an app may do#

memory 256 MiB for the process
CPU half a core; a tool waiting on your API uses none of it
disk the root filesystem and the project's folder are read-only. /scratch is 64 MiB in memory, emptied whenever the process starts again
network out the internet, through public resolvers (1.1.1.1, 8.8.8.8). Never private ranges (10/8, 172.16/12, 192.168/16, 100.64/10) or link-local addresses, so a database reachable only inside your network is out of reach
network in none. The agent's calls reach it over the socket it opens to the gateway

Every app runs under gVisor, a kernel of its own between your code and the machine, on a cluster apart from the gateway's.

A deploy never pushes the knowledge base. Production's documents are written in the agent's Knowledge ▸ Docs on production's console, or pushed once with pinecall docs push --prod, a separate step that replaces the base whole. See From sandbox to production.

Every day#

command what it does
pinecall deploy list --prod every app of the org: live, on its way, failed and why, or stopped
pinecall deploy releases --prod one app's releases, newest first: when, size, who, the note (--note on a deploy)
pinecall deploy logs --prod [--follow] the last 300 lines the process printed, fetched fresh
pinecall deploy rollback 3 --prod release 3's sources kept again as the next release, and started like any
pinecall deploy stop --prod · start the process drains and nothing runs; start runs the newest release again
pinecall deploy rm --prod the app removed: its releases deleted, its token revoked

Each takes --name <app> outside the app's folder. The console shows the same under Agents ▸ Apps. An app keeps its newest ten releases, and the one serving.

If a live process exits, Pinecall starts it again at once. After five exits in ten minutes it stops: the release is reported failed with its last lines, and the app answers nothing until the next release, a changed secret or a rollback.

From CI#

A pipeline deploys on a production server token from Settings ▸ Tokens, after the goldens:

YAML
# two steps of a GitHub Actions job, after checkout, setup-node 24 and npm ci
- run: npx pinecall test
  env: { PINECALL_KEY: "${{ secrets.PINECALL_SANDBOX_TOKEN }}" }
- run: npx pinecall deploy --prod --name support-line --note "${{ github.sha }}"
  env: { PINECALL_KEY: "${{ secrets.PINECALL_TOKEN }}" }

Next steps#