@pinecall/skills 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +65 -0
  2. package/build.mjs +204 -0
  3. package/package.json +29 -0
  4. package/skills/pinecall-concepts/SKILL.md +41 -0
  5. package/skills/pinecall-concepts/references/concepts/agents-and-channels.md +155 -0
  6. package/skills/pinecall-concepts/references/concepts/deployment-topologies.md +120 -0
  7. package/skills/pinecall-concepts/references/concepts/hot-reload.md +119 -0
  8. package/skills/pinecall-concepts/references/concepts/philosophy.md +100 -0
  9. package/skills/pinecall-concepts/references/concepts/server-vs-client-llm.md +119 -0
  10. package/skills/pinecall-examples/SKILL.md +59 -0
  11. package/skills/pinecall-examples/references/examples/browser-widget.md +206 -0
  12. package/skills/pinecall-examples/references/examples/chat-bot.md +184 -0
  13. package/skills/pinecall-examples/references/examples/headless-agent.md +121 -0
  14. package/skills/pinecall-examples/references/examples/index.md +183 -0
  15. package/skills/pinecall-examples/references/examples/multi-channel-bot.md +173 -0
  16. package/skills/pinecall-examples/references/examples/outbound-dispatch.md +109 -0
  17. package/skills/pinecall-examples/references/examples/turn-detection.md +150 -0
  18. package/skills/pinecall-guides/SKILL.md +68 -0
  19. package/skills/pinecall-guides/references/guides/call-ringing.md +149 -0
  20. package/skills/pinecall-guides/references/guides/conversation-history.md +377 -0
  21. package/skills/pinecall-guides/references/guides/dev-mode.md +130 -0
  22. package/skills/pinecall-guides/references/guides/events.md +677 -0
  23. package/skills/pinecall-guides/references/guides/human-takeover.md +184 -0
  24. package/skills/pinecall-guides/references/guides/inbound-voice.md +201 -0
  25. package/skills/pinecall-guides/references/guides/knowledge-bases.md +166 -0
  26. package/skills/pinecall-guides/references/guides/live-listening.md +199 -0
  27. package/skills/pinecall-guides/references/guides/multi-tenant.md +158 -0
  28. package/skills/pinecall-guides/references/guides/outbound-calls.md +279 -0
  29. package/skills/pinecall-guides/references/guides/sse-streaming.md +207 -0
  30. package/skills/pinecall-guides/references/guides/testing-agents.md +272 -0
  31. package/skills/pinecall-guides/references/guides/tools-and-functions.md +254 -0
  32. package/skills/pinecall-guides/references/guides/webrtc-browser.md +200 -0
  33. package/skills/pinecall-guides/references/guides/whatsapp.md +370 -0
  34. package/skills/pinecall-guides/references/guides/ws-streaming.md +235 -0
  35. package/skills/pinecall-quickstart/SKILL.md +54 -0
  36. package/skills/pinecall-quickstart/references/index.md +123 -0
  37. package/skills/pinecall-quickstart/references/quickstart.md +185 -0
  38. package/skills/pinecall-reference/SKILL.md +43 -0
  39. package/skills/pinecall-reference/references/reference/cli.md +578 -0
  40. package/skills/pinecall-reference/references/reference/events.md +366 -0
  41. package/skills/pinecall-reference/references/reference/llm-providers.md +263 -0
  42. package/skills/pinecall-reference/references/reference/rest-api.md +122 -0
  43. package/skills/pinecall-reference/references/reference/session-limits.md +119 -0
  44. package/skills/pinecall-reference/references/reference/stt-providers.md +174 -0
  45. package/skills/pinecall-reference/references/reference/tts-providers.md +149 -0
  46. package/skills/pinecall-sdk-api/SKILL.md +56 -0
  47. package/skills/pinecall-sdk-api/references/api/agent.md +328 -0
  48. package/skills/pinecall-sdk-api/references/api/call.md +324 -0
  49. package/skills/pinecall-sdk-api/references/api/pinecall.md +186 -0
  50. package/skills/pinecall-sdk-api/references/api/reply-stream.md +148 -0
  51. package/skills/pinecall-security/SKILL.md +37 -0
  52. package/skills/pinecall-security/references/security.md +138 -0
  53. package/skills/pinecall-web-chat/SKILL.md +38 -0
  54. package/skills/pinecall-web-chat/references/web/chat/chat-session.md +178 -0
  55. package/skills/pinecall-web-chat/references/web/chat/overview.md +98 -0
  56. package/skills/pinecall-web-components/SKILL.md +37 -0
  57. package/skills/pinecall-web-components/references/web/components/overview.md +128 -0
  58. package/skills/pinecall-web-voice/SKILL.md +40 -0
  59. package/skills/pinecall-web-voice/references/web/core/datachannel-protocol.md +149 -0
  60. package/skills/pinecall-web-voice/references/web/core/overview.md +70 -0
  61. package/skills/pinecall-web-voice/references/web/core/state-and-phases.md +153 -0
  62. package/skills/pinecall-web-voice/references/web/core/voice-session.md +279 -0
  63. package/skills/pinecall-web-widget/SKILL.md +41 -0
  64. package/skills/pinecall-web-widget/references/web/widget/overview.md +67 -0
  65. package/skills/pinecall-web-widget/references/web/widget/props.md +291 -0
  66. package/skills/pinecall-web-widget/references/web/widget/theming.md +131 -0
  67. package/skills/pinecall-web-widget/references/web/widget/tools-api.md +381 -0
  68. package/skills/pinecall-web-widget/references/web/widget/use-voice-session-hook.md +130 -0
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # @pinecall/skills
2
+
3
+ **Agent Skills for the [Pinecall](https://pinecall.io) SDK.** Drop the Pinecall
4
+ docs into any agent (Claude Code, Google Antigravity, Cursor, GitHub Copilot,
5
+ Codex — anything that speaks the open [Agent Skills](https://github.com/agentskills/agentskills)
6
+ format) so it builds voice & chat agents the right way, offline, with the
7
+ correct defaults.
8
+
9
+ Each skill is a folder with a `SKILL.md` + a `references/` tree of the real docs
10
+ pages, loaded on demand (progressive disclosure). The whole package is
11
+ **generated from `sdk/docs/`** — one source of truth feeds the docs site, the
12
+ `/ask` knowledge base, and these skills.
13
+
14
+ ## Install
15
+
16
+ ```bash
17
+ # the open installer (softaworks/agent-toolkit) — picks an agent dir + symlinks
18
+ npx skills add pinecall/skills
19
+ ```
20
+
21
+ Or manually copy the skills you want into your agent's skills directory:
22
+
23
+ | Agent | Directory |
24
+ |-------|-----------|
25
+ | Claude Code | `.claude/skills/` |
26
+ | Google Antigravity | `.agents/skills/` (or the plugin's `skills/`) |
27
+ | Cursor / others | per the agent's docs |
28
+
29
+ ```bash
30
+ cp -R skills/pinecall-guides ~/your-project/.claude/skills/
31
+ ```
32
+
33
+ ## What's inside
34
+
35
+ | Skill | Covers |
36
+ |-------|--------|
37
+ | `pinecall-quickstart` | Install + first voice agent |
38
+ | `pinecall-concepts` | Agents/Channels/Calls, server vs client LLM, hot reload, topologies |
39
+ | `pinecall-guides` | Inbound/outbound, WhatsApp, tools, events, takeover, WebRTC, multi-tenant, testing… |
40
+ | `pinecall-examples` | Copy-paste full agents |
41
+ | `pinecall-sdk-api` | `@pinecall/sdk` API (Pinecall / Agent / Call / ReplyStream) |
42
+ | `pinecall-web-voice` | `@pinecall/web/core` — browser WebRTC voice |
43
+ | `pinecall-web-widget` | `@pinecall/web` React widget |
44
+ | `pinecall-web-chat` | `@pinecall/web/chat` — text chat |
45
+ | `pinecall-web-components` | Framework-agnostic web components |
46
+ | `pinecall-reference` | CLI, STT/TTS/LLM providers, events, limits, REST |
47
+ | `pinecall-security` | Security model |
48
+
49
+ Every skill carries the **house rules** so the agent never drifts:
50
+ `stt: "deepgram/flux"`, `llm: "openai/gpt-5-chat-latest"`, `voice: "elevenlabs/sarah"`,
51
+ never `nova-2`, and never set `turnDetection`/`vad` by hand.
52
+
53
+ ## Regenerate (keep in sync with the docs)
54
+
55
+ The `skills/` tree is generated and committed. Whenever `sdk/docs/` changes,
56
+ re-run the generator and commit the result — same flow as re-pushing the docs KB.
57
+
58
+ ```bash
59
+ node build.mjs # reads ../sdk/docs by default
60
+ DOCS_DIR=/path/to/sdk/docs node build.mjs
61
+ ```
62
+
63
+ The generator maps each `docs.json` navigation group to one skill, copies that
64
+ group's pages into `references/`, and writes a `SKILL.md` index + the house
65
+ rules. No dependencies.
package/build.mjs ADDED
@@ -0,0 +1,204 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @pinecall/skills — generator.
4
+ *
5
+ * Nourishes an Agent-Skills package straight from the SDK docs.
6
+ * Reads `sdk/docs/docs.json` + each page's frontmatter and emits one skill per
7
+ * docs group: skills/<skill>/SKILL.md + skills/<skill>/references/<page>.md
8
+ *
9
+ * Re-run whenever `sdk/docs/` changes — same flow as the KB push. Output is
10
+ * committed (so `npx skills add pinecall/skills` works offline).
11
+ *
12
+ * node build.mjs # default DOCS_DIR=../sdk/docs
13
+ * DOCS_DIR=/path node build.mjs
14
+ */
15
+ import { readFileSync, writeFileSync, mkdirSync, rmSync, existsSync } from "node:fs";
16
+ import { dirname, join, resolve } from "node:path";
17
+ import { fileURLToPath } from "node:url";
18
+
19
+ const HERE = dirname(fileURLToPath(import.meta.url));
20
+ const DOCS_DIR = resolve(HERE, process.env.DOCS_DIR || "../sdk/docs");
21
+ const OUT_DIR = join(HERE, "skills");
22
+
23
+ // --- House rules: injected into every SKILL.md so each skill is self-correcting.
24
+ const HOUSE_RULES = `## House rules — always apply
25
+
26
+ - **Example defaults** (use these exact strings unless the user asks otherwise):
27
+ \`stt: "deepgram/flux"\`, \`llm: "openai/gpt-5-chat-latest"\`, \`voice: "elevenlabs/sarah"\`.
28
+ **NEVER use \`deepgram/nova-2\`** — it is not supported. Use \`deepgram/nova-3\`
29
+ only for languages Flux doesn't support (e.g. Arabic).
30
+ - **Turn detection & VAD are auto-derived from the STT provider — never set
31
+ \`turnDetection\` or \`vad\` manually.** Flux → native turns + native VAD;
32
+ every other STT → \`smart_turn\` + \`silero\`.
33
+ - **Greeting**: inbound → \`greeting\` field in \`pc.agent()\`; outbound → \`greeting\`
34
+ field in \`agent.dial()\`. It is sugar for \`call.say()\` in \`call.started\`.
35
+ - **Auth**: \`new Pinecall()\` reads \`PINECALL_API_KEY\` from env and auto-connects.
36
+ - Full documentation: <https://docs.pinecall.io>`;
37
+
38
+ // --- Canonical example every voice skill should anchor on.
39
+ const CANONICAL_EXAMPLE = `\`\`\`typescript
40
+ import { Pinecall } from "@pinecall/sdk";
41
+
42
+ const pc = new Pinecall(); // reads PINECALL_API_KEY, auto-connects
43
+
44
+ const agent = pc.agent("mara", {
45
+ prompt: "You are Mara, a friendly voice assistant. Be concise.",
46
+ llm: "openai/gpt-5-chat-latest",
47
+ voice: "elevenlabs/sarah",
48
+ stt: "deepgram/flux",
49
+ language: "en",
50
+ greeting: "Hello! How can I help?",
51
+ });
52
+ \`\`\``;
53
+
54
+ // --- docs.json group name -> skill metadata. Unknown groups fall back to slug.
55
+ const GROUP_MAP = {
56
+ "Get Started": {
57
+ slug: "pinecall-quickstart",
58
+ blurb: "Install @pinecall/sdk and build your first voice agent in minutes.",
59
+ keywords: "install, quickstart, first agent, pc.agent, PINECALL_API_KEY, pinecall run",
60
+ },
61
+ Concepts: {
62
+ slug: "pinecall-concepts",
63
+ blurb: "The mental model — Pinecall, Agent, Channel, Call; server- vs client-side LLM; hot reload; deployment topologies.",
64
+ keywords: "agents and channels, server vs client llm, hot reload, deployment, mental model, architecture",
65
+ },
66
+ Guides: {
67
+ slug: "pinecall-guides",
68
+ blurb: "Task guides for building Pinecall agent features.",
69
+ keywords: "inbound, outbound, whatsapp, tools, function calling, events, live listening, conversation history, human takeover, webrtc, multi-tenant, dev mode, testing, agent.dial, call.say, tool()",
70
+ },
71
+ Examples: {
72
+ slug: "pinecall-examples",
73
+ blurb: "Copy-paste recipes — full working agents for common scenarios.",
74
+ keywords: "example, recipe, sample, outbound dispatch, chat bot, browser widget, multi-channel, headless",
75
+ },
76
+ "@pinecall/sdk (Node.js)": {
77
+ slug: "pinecall-sdk-api",
78
+ blurb: "@pinecall/sdk API reference — Pinecall, Agent, Call, ReplyStream.",
79
+ keywords: "api, pc.agent, agent.dial, call object, reply stream, replyStream, server sdk surface",
80
+ },
81
+ "@pinecall/web/core (Voice)": {
82
+ slug: "pinecall-web-voice",
83
+ blurb: "@pinecall/web/core — browser WebRTC voice (VoiceSession, state & phases, DataChannel protocol).",
84
+ keywords: "webrtc, voice session, browser voice, datachannel, @pinecall/web/core",
85
+ },
86
+ "@pinecall/web (React Widget)": {
87
+ slug: "pinecall-web-widget",
88
+ blurb: "@pinecall/web React widget — VoiceWidget props, theming, useVoiceSession hook, client tools.",
89
+ keywords: "react widget, voicewidget, useVoiceSession, theming, props, client tools, @pinecall/web",
90
+ },
91
+ "@pinecall/web/chat (Chat)": {
92
+ slug: "pinecall-web-chat",
93
+ blurb: "@pinecall/web/chat — browser text chat (ChatSession, ChatView).",
94
+ keywords: "chat, chatsession, text chat, @pinecall/web/chat",
95
+ },
96
+ "@pinecall/web (Web Components)": {
97
+ slug: "pinecall-web-components",
98
+ blurb: "@pinecall/web web components — framework-agnostic custom elements.",
99
+ keywords: "web components, custom element, framework-agnostic widget",
100
+ },
101
+ Reference: {
102
+ slug: "pinecall-reference",
103
+ blurb: "Reference tables — CLI commands, STT/TTS/LLM providers, events, session limits, REST API.",
104
+ keywords: "cli, commands, stt providers, tts providers, llm providers, events, session limits, rest api, reference",
105
+ },
106
+ };
107
+
108
+ const slugify = (s) =>
109
+ "pinecall-" +
110
+ s.toLowerCase().replace(/@pinecall\/?/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
111
+
112
+ // Minimal frontmatter reader (title + description), no deps.
113
+ function frontmatter(md) {
114
+ const m = md.match(/^---\n([\s\S]*?)\n---/);
115
+ const fm = {};
116
+ if (m) {
117
+ for (const line of m[1].split("\n")) {
118
+ const kv = line.match(/^(\w+):\s*"?(.*?)"?\s*$/);
119
+ if (kv) fm[kv[1]] = kv[2];
120
+ }
121
+ }
122
+ return fm;
123
+ }
124
+
125
+ function loadPage(slug) {
126
+ const file = join(DOCS_DIR, slug.endsWith(".md") ? slug : slug + ".md");
127
+ if (!existsSync(file)) return null;
128
+ const md = readFileSync(file, "utf8");
129
+ const fm = frontmatter(md);
130
+ return {
131
+ slug,
132
+ file,
133
+ md,
134
+ title: fm.title || slug.split("/").pop(),
135
+ description: fm.description || "",
136
+ };
137
+ }
138
+
139
+ // --- main
140
+ const docsJson = JSON.parse(readFileSync(join(DOCS_DIR, "..", "docs.json"), "utf8"));
141
+ const groups = docsJson.navigation.groups;
142
+
143
+ if (existsSync(OUT_DIR)) rmSync(OUT_DIR, { recursive: true });
144
+ mkdirSync(OUT_DIR, { recursive: true });
145
+
146
+ const built = [];
147
+ for (const group of groups) {
148
+ const meta = GROUP_MAP[group.group] || { slug: slugify(group.group), blurb: group.group, keywords: "" };
149
+ const skillDir = join(OUT_DIR, meta.slug);
150
+ mkdirSync(join(skillDir, "references"), { recursive: true });
151
+
152
+ const pages = group.pages.map(loadPage).filter(Boolean);
153
+
154
+ // Copy each page into references/, build the index rows.
155
+ const rows = [];
156
+ for (const p of pages) {
157
+ const refRel = join("references", p.slug + ".md");
158
+ const refAbs = join(skillDir, refRel);
159
+ mkdirSync(dirname(refAbs), { recursive: true });
160
+ writeFileSync(refAbs, p.md);
161
+ rows.push(
162
+ `| **${p.title}** | ${p.description || "—"} | [\`${refRel}\`](${refRel}) · [docs](https://docs.pinecall.io/${p.slug}) |`
163
+ );
164
+ }
165
+
166
+ const isVoice = /quickstart|guides|examples|sdk-api/.test(meta.slug);
167
+ const description =
168
+ `${meta.blurb} Use when the user is building, configuring, or debugging with @pinecall/sdk. ` +
169
+ `Keywords: ${meta.keywords}.`;
170
+
171
+ const body = `---
172
+ name: ${meta.slug}
173
+ description: >-
174
+ ${description.replace(/\n/g, " ")}
175
+ license: MIT
176
+ ---
177
+
178
+ # ${group.group}
179
+
180
+ ${meta.blurb}
181
+
182
+ This skill bundles the official Pinecall documentation for **${group.group}**. The
183
+ table below indexes every page; open the \`references/…\` file for the full text
184
+ (loaded on demand). Source of truth: <https://docs.pinecall.io>.
185
+
186
+ | Page | What it covers | Open |
187
+ |------|----------------|------|
188
+ ${rows.join("\n")}
189
+
190
+ ${isVoice ? "## Canonical agent\n\n" + CANONICAL_EXAMPLE + "\n" : ""}
191
+ ${HOUSE_RULES}
192
+
193
+ ---
194
+ *Generated from \`sdk/docs/\` by \`@pinecall/skills\` — do not edit by hand; edit the
195
+ docs and re-run \`node build.mjs\`.*
196
+ `;
197
+
198
+ writeFileSync(join(skillDir, "SKILL.md"), body);
199
+ built.push({ slug: meta.slug, group: group.group, pages: pages.length });
200
+ }
201
+
202
+ // eslint-disable-next-line no-console
203
+ console.log(`Built ${built.length} skills from ${DOCS_DIR}:`);
204
+ for (const b of built) console.log(` ${b.slug.padEnd(26)} ${String(b.pages).padStart(2)} pages (${b.group})`);
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "name": "@pinecall/skills",
3
+ "version": "0.1.0",
4
+ "description": "Agent Skills for the Pinecall SDK — installable into Claude Code, Antigravity, Cursor, Copilot and any agent that supports the open Skills format.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "homepage": "https://docs.pinecall.io",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "https://github.com/pinecall/skills"
11
+ },
12
+ "keywords": [
13
+ "pinecall",
14
+ "agent-skills",
15
+ "skills",
16
+ "claude-code",
17
+ "antigravity",
18
+ "voice-ai",
19
+ "sdk"
20
+ ],
21
+ "files": [
22
+ "skills",
23
+ "build.mjs",
24
+ "README.md"
25
+ ],
26
+ "scripts": {
27
+ "build": "node build.mjs"
28
+ }
29
+ }
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: pinecall-concepts
3
+ description: >-
4
+ The mental model — Pinecall, Agent, Channel, Call; server- vs client-side LLM; hot reload; deployment topologies. Use when the user is building, configuring, or debugging with @pinecall/sdk. Keywords: agents and channels, server vs client llm, hot reload, deployment, mental model, architecture.
5
+ license: MIT
6
+ ---
7
+
8
+ # Concepts
9
+
10
+ The mental model — Pinecall, Agent, Channel, Call; server- vs client-side LLM; hot reload; deployment topologies.
11
+
12
+ This skill bundles the official Pinecall documentation for **Concepts**. The
13
+ table below indexes every page; open the `references/…` file for the full text
14
+ (loaded on demand). Source of truth: <https://docs.pinecall.io>.
15
+
16
+ | Page | What it covers | Open |
17
+ |------|----------------|------|
18
+ | **Philosophy** | Why Pinecall is code-first and what that means for your architecture. | [`references/concepts/philosophy.md`](references/concepts/philosophy.md) · [docs](https://docs.pinecall.io/concepts/philosophy) |
19
+ | **Agents and Channels** | The mental model: how Pinecall, Agent, Channel, and Call fit together. | [`references/concepts/agents-and-channels.md`](references/concepts/agents-and-channels.md) · [docs](https://docs.pinecall.io/concepts/agents-and-channels) |
20
+ | **Server-side vs Client-side LLM** | The single most important architectural decision when building a Pinecall agent. | [`references/concepts/server-vs-client-llm.md`](references/concepts/server-vs-client-llm.md) · [docs](https://docs.pinecall.io/concepts/server-vs-client-llm) |
21
+ | **Hot-Reload** | Change voice, language, prompt, tools — even during an active call. | [`references/concepts/hot-reload.md`](references/concepts/hot-reload.md) · [docs](https://docs.pinecall.io/concepts/hot-reload) |
22
+ | **Deployment Topologies** | Embedded, standalone, or headless — pick the topology that fits your architecture. | [`references/concepts/deployment-topologies.md`](references/concepts/deployment-topologies.md) · [docs](https://docs.pinecall.io/concepts/deployment-topologies) |
23
+
24
+
25
+ ## House rules — always apply
26
+
27
+ - **Example defaults** (use these exact strings unless the user asks otherwise):
28
+ `stt: "deepgram/flux"`, `llm: "openai/gpt-5-chat-latest"`, `voice: "elevenlabs/sarah"`.
29
+ **NEVER use `deepgram/nova-2`** — it is not supported. Use `deepgram/nova-3`
30
+ only for languages Flux doesn't support (e.g. Arabic).
31
+ - **Turn detection & VAD are auto-derived from the STT provider — never set
32
+ `turnDetection` or `vad` manually.** Flux → native turns + native VAD;
33
+ every other STT → `smart_turn` + `silero`.
34
+ - **Greeting**: inbound → `greeting` field in `pc.agent()`; outbound → `greeting`
35
+ field in `agent.dial()`. It is sugar for `call.say()` in `call.started`.
36
+ - **Auth**: `new Pinecall()` reads `PINECALL_API_KEY` from env and auto-connects.
37
+ - Full documentation: <https://docs.pinecall.io>
38
+
39
+ ---
40
+ *Generated from `sdk/docs/` by `@pinecall/skills` — do not edit by hand; edit the
41
+ docs and re-run `node build.mjs`.*
@@ -0,0 +1,155 @@
1
+ ---
2
+ title: "Agents and Channels"
3
+ description: "The mental model: how Pinecall, Agent, Channel, and Call fit together."
4
+ ---
5
+
6
+ # Agents and Channels
7
+
8
+ The Pinecall SDK has four nouns. Understanding them is most of understanding the SDK.
9
+
10
+ ## The four nouns
11
+
12
+ ![The four nouns — Pinecall, Agent, Channel, Call](/assets/diagrams/four-nouns-hierarchy.png)
13
+
14
+ ### `Pinecall` — the client
15
+
16
+ One per process. Owns the WebSocket connection to `voice.pinecall.io`, handles auth and reconnection, and multiplexes events across multiple agents. **Auto-connects on construction.**
17
+
18
+ ```typescript
19
+ const pc = new Pinecall(); // reads PINECALL_API_KEY from env, connects automatically
20
+ ```
21
+
22
+ ### `Agent` — a personality
23
+
24
+ A configured assistant. Has a name (the agent ID), a voice, an STT provider, an LLM config, and a list of tools. Listens for events; owns channels.
25
+
26
+ ```typescript
27
+ const agent = pc.agent("support", {
28
+ voice: "elevenlabs/sarah",
29
+ language: "en",
30
+ llm: "openai/gpt-5-chat-latest",
31
+ stt: "deepgram/flux",
32
+ prompt: "...",
33
+ });
34
+ ```
35
+
36
+ You can have many agents on the same `Pinecall` instance — `support`, `sales`, `intake` — each with their own personality and channels.
37
+
38
+ ### `Channel` — a way to reach the agent
39
+
40
+ A surface through which calls arrive. Some channels need explicit registration; others work automatically:
41
+
42
+ ```typescript
43
+ // Phone number — declared in config
44
+ const agent = pc.agent("support", {
45
+ phoneNumber: "+13186330963",
46
+ whatsapp: [{ phoneNumberId: "123", accessToken: "..." }],
47
+ });
48
+
49
+ // Or imperatively:
50
+ agent.addPhoneNumber("+13186330963");
51
+ agent.addWhatsapp({ phoneNumberId: "123", accessToken: "..." });
52
+
53
+ // WebRTC + Chat: work via tokens, no registration needed
54
+ const token = await agent.createToken("webrtc");
55
+ ```
56
+
57
+ Channel types:
58
+
59
+ | Type | Registration | How users connect |
60
+ |---|---|---|
61
+ | `phone` | `phoneNumber: "+1..."` | Call the number |
62
+ | `whatsapp` | `whatsapp: [{...}]` | Send a WhatsApp message |
63
+ | `webrtc` | **None** (automatic) | Browser widget + token |
64
+ | `chat` | **None** (automatic) | WebSocket + token |
65
+
66
+ ### `Call` — a live session
67
+
68
+ Created automatically when someone connects on a channel. You receive a `Call` object in the `call.started` event. Use it to:
69
+
70
+ - Speak (`call.say`, `call.reply`, `call.replyStream`)
71
+ - Control the call (`call.hangup`, `call.forward`, `call.hold`)
72
+ - Update mid-call (`call.update`, `call.setPrompt`, `call.addContext`)
73
+ - Read state (`call.transcript`, `call.from`, `call.duration`)
74
+
75
+ ## Creating an agent
76
+
77
+ ### With `phoneNumber` (declarative)
78
+
79
+ Pass a phone number directly in the config:
80
+
81
+ ```typescript
82
+ const mara = pc.agent("mara", {
83
+ voice: "elevenlabs/sarah",
84
+ language: "es",
85
+ llm: "openai/gpt-5-chat-latest",
86
+ stt: "deepgram/flux",
87
+ prompt: "You are Mara. Be concise.",
88
+ phoneNumber: "+13186330963",
89
+ });
90
+ ```
91
+
92
+ WebRTC and Chat work automatically — no declaration needed. Just create tokens.
93
+
94
+ ### With `agent.addPhoneNumber()` (imperative)
95
+
96
+ Use `agent.addPhoneNumber()` when you need per-number config overrides:
97
+
98
+ ```typescript
99
+ const mara = pc.agent("mara", {
100
+ voice: "elevenlabs/sarah",
101
+ language: "es",
102
+ llm: "openai/gpt-5-chat-latest",
103
+ stt: "deepgram/flux",
104
+ prompt: "You are Mara. Be concise.",
105
+ });
106
+
107
+ mara.addPhoneNumber("+13186330963", {
108
+ voice: "elevenlabs/daniel",
109
+ });
110
+ ```
111
+
112
+ ## Per-number config overrides
113
+
114
+ The agent has defaults. Each phone number can override voice, language, and STT. This is how you give the same agent different settings per number:
115
+
116
+ ```typescript
117
+ const agent = pc.agent("support", {
118
+ llm: "openai/gpt-5-chat-latest",
119
+ stt: "deepgram/flux",
120
+ voice: "elevenlabs/sarah",
121
+ phoneNumber: { number: "+34911234567", voice: "elevenlabs/valentina", language: "es" },
122
+ });
123
+ ```
124
+
125
+ For multiple numbers with different overrides — including STT provider — use `phoneNumbers`:
126
+
127
+ ```typescript
128
+ const agent = pc.agent("global-support", {
129
+ prompt: "You are a multilingual support agent.",
130
+ llm: "openai/gpt-5-chat-latest",
131
+ phoneNumbers: [
132
+ { number: "+14155551234", language: "en", voice: "elevenlabs/sarah", stt: "deepgram/flux" },
133
+ { number: "+34612345678", language: "es", voice: "elevenlabs/valentina", stt: "deepgram/flux" },
134
+ // Arabic requires Nova-3 (Flux doesn't support it)
135
+ { number: "+972501234567", language: "ar", voice: "elevenlabs/ahmad", stt: "deepgram/nova-3" },
136
+ ],
137
+ });
138
+ ```
139
+
140
+ The agent's prompt, tools, and LLM stay the same — only the audio surface changes per number. Turn detection and VAD are auto-derived from the STT provider (Flux → native, Nova-3 → smart_turn + silero).
141
+
142
+ ## Why this design
143
+
144
+ The agent-and-channels split exists because voice agents have two completely different concerns:
145
+
146
+ 1. **Who the agent is** — personality, knowledge, tools, business logic
147
+ 2. **How users reach it** — a phone number, a SIP trunk, a browser widget, a WhatsApp chat
148
+
149
+ Most platforms conflate the two: you build a "Twilio bot" or a "WhatsApp bot." Pinecall keeps them separate so you can build the agent once and expose it through whatever channel you need today (or tomorrow).
150
+
151
+ ## What's next
152
+
153
+ - [Server-side vs client-side LLM](/concepts/server-vs-client-llm) — the most important architectural decision
154
+ - [Hot-reload](/concepts/hot-reload) — change voice, language, prompt, or tools mid-call
155
+ - [Deployment topologies](/concepts/deployment-topologies) — embedded, standalone, or headless
@@ -0,0 +1,120 @@
1
+ ---
2
+ title: "Deployment Topologies"
3
+ description: "Embedded, standalone, or headless — pick the topology that fits your architecture."
4
+ ---
5
+
6
+ # Deployment Topologies
7
+
8
+ Pinecall agents are just Node.js processes. Where you run them is your choice. There are three common topologies — each is valid, each has tradeoffs.
9
+
10
+ ## The fundamental split
11
+
12
+ Before topology, understand the two communication patterns:
13
+
14
+ **1. Backend channels** — phone, SIP, WhatsApp. These talk to your Node.js process via the SDK's WebSocket. Your code receives events through an in-process EventEmitter.
15
+
16
+ ![Backend channels flow](/assets/diagrams/backend-channels-flow.png)
17
+
18
+ **2. Browser channels** — WebRTC and chat. The browser connects **directly** to `voice.pinecall.io`. Your backend's only job is minting short-lived tokens.
19
+
20
+ ![Browser channels — WebRTC token flow](/assets/diagrams/webrtc-browser-arch.png)
21
+
22
+ This split is why some topologies support SSE event streaming and others don't — SSE requires the agent to be in the same process as your web server.
23
+
24
+ ## Topology 1: Embedded
25
+
26
+ Agent runs inside your existing web app (Express, Next.js, Hono, Remix). The web server and the agent share a Node.js process.
27
+
28
+ ![Embedded topology](/assets/diagrams/deployment-embedded.png)
29
+
30
+ **Pros:**
31
+ - SSE streaming works (you can build live dashboards)
32
+ - One deployment unit — easy ops
33
+ - Token endpoint is one route away from the agent
34
+
35
+ **Cons:**
36
+ - The agent process restarts every time you deploy the web app
37
+ - Web traffic and voice traffic share resources
38
+
39
+ **When to use:** small apps, dashboards that need live call event streaming, single-team projects.
40
+
41
+ ## Topology 2: Standalone
42
+
43
+ Agent runs as a separate process from your web app. The web app handles HTTP, the agent process handles voice.
44
+
45
+ ![Standalone topology](/assets/diagrams/deployment-standalone.png)
46
+
47
+ **Pros:**
48
+ - Independent deploys — restart the agent without touching the web app
49
+ - Independent scaling — give the agent its own resources
50
+ - Crash isolation — a web bug doesn't kill calls in flight
51
+
52
+ **Cons:**
53
+ - No SSE — the web app can't stream events from the agent process directly. If you need live dashboards, the agent has to expose its own SSE endpoint or push to a shared bus (Redis, NATS).
54
+ - Two deployments to manage
55
+
56
+ **When to use:** higher-traffic apps, when ops cares about independent scaling, when you want to avoid the "web deploy kills in-flight calls" problem.
57
+
58
+ ## Topology 3: Headless
59
+
60
+ No web server at all. Just the agent. Use this when you only need phone/SIP/WhatsApp — no browser channels, no dashboards, no tokens to mint.
61
+
62
+ ```typescript
63
+ // agent/index.js — a complete production agent, no web server needed
64
+ import { Pinecall } from "@pinecall/sdk";
65
+
66
+ const pc = new Pinecall();
67
+
68
+ export const agent = pc.agent("support", {
69
+ prompt: "You are a support agent for an online store...",
70
+ llm: "openai/gpt-5-chat-latest",
71
+ voice: "elevenlabs/sarah",
72
+ stt: "deepgram/flux",
73
+ language: "en",
74
+ phoneNumber: "+13186330963",
75
+ greeting: "Hi! How can I help?",
76
+ tools: [lookupOrder, processReturn],
77
+ });
78
+ ```
79
+
80
+ Run it with `pinecall run agent/index.js` for a polished boot banner and live transcript.
81
+
82
+ **Pros:**
83
+ - Lowest possible complexity
84
+ - No HTTP surface to attack or maintain
85
+ - Easy to ship as a container, a systemd unit, or a serverless function
86
+
87
+ **Cons:**
88
+ - No browser channels (no WebRTC, no chat) unless someone else mints tokens
89
+ - No SSE
90
+ - No dashboards from this process
91
+
92
+ **When to use:** IoT devices, intercoms, single-purpose phone bots, WhatsApp-only bots, scheduled outbound campaigns.
93
+
94
+ ## Comparison
95
+
96
+ | Feature | Embedded | Standalone | Headless |
97
+ |---|---|---|---|
98
+ | SSE (`agent.stream()`) | ✅ | ❌ | ❌ |
99
+ | WebRTC / Chat | ✅ | ✅ (token from web app) | ❌ (or you build it) |
100
+ | Phone / SIP | ✅ | ✅ | ✅ |
101
+ | WhatsApp | ✅ | ✅ | ✅ |
102
+ | Outbound calls | ✅ | ✅ | ✅ |
103
+ | Operational complexity | Medium | Medium | **Lowest** |
104
+ | Independent scaling | ❌ | ✅ | ✅ |
105
+ | Crash isolation | ❌ | ✅ | n/a |
106
+
107
+ ## Which one should you pick?
108
+
109
+ - **Just starting out** — embedded. Get something running, split later if you need to.
110
+ - **You need browser channels and a dashboard** — embedded.
111
+ - **You're scaling and ops cares** — standalone.
112
+ - **You're shipping a fixed-purpose device or WhatsApp-only bot** — headless.
113
+
114
+ Migration between topologies is cheap. The agent code is the same in all three. You're just choosing where to run it.
115
+
116
+ ## What's next
117
+
118
+ - [Multi-tenant dashboards](/guides/multi-tenant) — embed multiple agents, scope events per user
119
+ - [Dev mode](/guides/dev-mode) — run prod and dev agents on the same phone number
120
+ - [SSE streaming reference](/reference/events) — for embedded dashboards