Project layout
What pinecall new writes, where each file goes, and several agents in one repository.
A project is a folder of one or more agents. Every verb of the CLI reads the same layout, so a file in the right place is all the configuration there is.
What pinecall new writes#
pinecall new front-desk writes a project of one agent into ./front-desk/, and nothing else: no
key, no install, no gateway.
$ pinecall new front-desk
▸ front-desk · a TypeScript agent
cd front-desk
npm install
pinecall link sign in, pick the org: its key goes to .env
pinecall chat talk to it here
pinecall test its goldens, against a real model
pinecall start answer calls
front-desk/
agents/front-desk/agent.tsx the class: its state, its tools, its prompt
test/front-desk/agent.test.ts the class as software: no network, no key, no model
test/front-desk/goldens/takes-the-message.json one conversation the model must hold
package.json "type": "module", @pinecall/agents and pinecall
tsconfig.json extends @pinecall/agents/tsconfig.tenant.json
vitest.config.ts legacy decorators and the framework's JSX runtime
.env.example PINECALL_KEY=
.gitignore .env, .pinecall/ and node_modules/
README.md
The name is the agent's slug: lowercase letters, digits and dashes, starting with a letter. The
folder must not exist, or must be empty. --ruby writes the same project in Ruby: agent.rb, its
view in agents/<name>/views/<name>.erb, a Gemfile and a Rakefile. --python writes it in
Python: agent.py, its view in agents/<name>/views/<name>.jinja, and a pyproject.toml for uv
and pytest.
How it works#
pinecall link writes. Never committed.
| path | what it holds |
|---|---|
agents/<name>/agent.tsx |
the class, as the default export. agent.ts also works for a class that renders no JSX |
agents/<name>/*.ts |
what only this agent uses: a client for your calendar, your CRM |
lib/ |
what two or more agents share |
test/<name>/agent.test.ts |
unit tests of the class |
test/<name>/goldens/ |
the conversations pinecall test runs; beside them docs.json and memory.json |
test/<name>/memory/ |
the extraction cases pinecall remember runs |
The CLI looks for agents/<name>/agent.tsx, then agent.ts, agent.rb and agent.py. A folder
nobody has written yet is empty, not an error: an agent with no goldens/ simply has no goldens.
The toolchain#
@pinecall/agents and pinecall are both dependencies of the project. The CLI never loads the
framework itself: it starts your agent with the project's own @pinecall/agents, so the version
that runs is the one you pinned. A project without it is refused.
Two compiler facts travel with the framework: legacy decorators, and a JSX runtime that renders to
text. tsconfig.json gets them from the preset. Vitest reads no tsconfig, so its config says them
again:
import { defineConfig } from "vitest/config";
export default defineConfig({
oxc: {
decorator: { legacy: true },
jsx: { runtime: "automatic", importSource: "@pinecall/agents/views" },
},
test: { include: ["test/**/*.test.ts", "test/**/*.test.tsx"] },
});
Keep
"type": "module"inpackage.json. The class is an ES module, and a CommonJS package makestscrefuse everyimportof it.
Several agents in one repository#
A second agent is a second folder under agents/, and the same folders under its name in test/.
pinecall generate agent <name> writes them from the same templates as the first:
agents/
front-desk/agent.tsx
sales/agent.tsx
lib/crm.ts
test/
front-desk/goldens/
sales/goldens/
At the root, pinecall start runs every agent in one process, and pinecall test runs each
agent's goldens in turn. A verb about one agent (chat, prompt, simulate, remember, line)
needs --agent <name> when there are several, and refuses with the names when it is missing.
What is not in the repository#
| what | where it lives |
|---|---|
| the voice, the models, the language, the greeting | Agent settings: your own in the sandbox, the team's, and production's |
| what the agent knows by heart | a setting: pinecall agent knowledge edit, or the agent's Configure ▸ Knowledge in the console |
| the documents it searches | a knowledge base kept by the gateway |
| the simulated callers | Personas, kept by the gateway |
| the phone numbers | Phone numbers, rows of the org |
A local docs/<name>/ folder is only what pinecall docs push sends when you name no folder.