Files
pig/docs/agents.md
T
karti 13dec6b4b8
CI / verify (push) Successful in 3m45s
CI / publish (push) Has been skipped
Rebuild the shell, add Calendar and Learn, and govern reads
Seven parallel agents and an adversarial verification pass. The three things
worth knowing before reading the diff:

RBAC WAS ALREADY BUILT. docs/build-plan.md marks F2 and F3 outstanding and is
stale — packages/core/src/permissions.ts and lib/mutation.ts shipped long ago.
So this does not rebuild them; it closes the gaps an audit found. The big one
is that reads were entirely ungoverned: every GET was "any authenticated
member", so a junior demand rep and a research contractor could both pull
per-block supplier cost and break-even prices from /api/capacity/margin, and
every contract's negotiated terms. For a company whose margin is the business,
that was the hole that mattered. Adds book:read / economics:read / team:read,
a readGuard middleware, and a `viewer` role below member.

THE BUTTON AND THE 403 DISAGREED — the exact thing F3 said must never happen.
Contracts.tsx never called can() at all, so its save button was always enabled
against a server requiring contract:sign; Capacity.tsx gated commitment
creation on deal:write/demand while the server wanted commitment:write/supply.

POST /api/activities was the one write bypassing executeMutation: no capability
check, and any member could mutate accounts.lastActivityAt as a side effect.
It is now a proper mutation() behind activity:write.

The shell becomes three panes — a collapsible shadcn sidebar with an account
switcher on the Piggy accent, a header with real search, and Piggy docked to
the right, page-aware and persistent across navigation. The phone keeps its
bottom tab bar, which is the thing this product already beat trycompai/crm on,
and gains the sidebar as a sheet.

Calendar is a projection over thirteen dated sources rather than a new table,
because a table would duplicate dates that already live on contracts, deals and
commitments and would drift — and one ledger answering the question is the
whole argument. It surfaces export_authorizations and compliance_artifacts,
which had indexed expires_at columns, schema comments saying they must be
alerted on, and no read endpoint or UI anywhere.

Learn carries two tracks. Concepts are members-only; the platform track can be
opened with a share code by someone with no account. The code mints a scoped
learn-only token and never a Principal — every route here resolves a principal
and then checks capabilities, so a principal-minting code would be one missing
check away from leaking the book. "Only platform-track rows may be code-visible"
is a database CHECK constraint as well as a write-path rule, and a test asserts
a valid learn token still gets 401 on /api/dashboard, /api/accounts and
/api/contracts — the same invariant scripts/deploy.sh refuses to ship without.

CD becomes tag-to-ship. CI publishes an image to the Gitea registry on a
release-* tag and cloud-2 pulls it, so no credential on the shared runner can
execute anything on production — by construction rather than by policy. Both
halves of deploy.sh's original rule survive: nothing on the runner reaches the
host, and a human still decides when it ships. deploy.sh gains a rollback and a
public-origin check, and PIG_IMAGE now reaches compose through `sudo env`,
without which sudo's env_reset silently resolved every release to pig:local.

Tests 141 -> 261.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-13 15:02:48 -07:00

4.3 KiB

Connecting an agent

PIG is a first-class application for agents. The same MCP server serves every client, so nobody is asked to use a different tool than the one they already work in.

This page is about connecting your agent to PIG. Piggy, the agent that lives inside PIG, is a different thing and is documented in the README — it drains a database queue and, in chat, reads and cites records for whoever is looking at the page.

Transport, and what that means for you

The MCP server speaks stdio only. There is no Streamable HTTP transport and no /mcp endpoint on the API, so each person runs their own copy locally against their own API key rather than pointing a client at a shared URL. That is a real limitation, not a security posture — see the build plan.

@pig/mcp is a workspace package and is not published to npm, so npx @pig/mcp does not work. Run it out of a clone.

Setup

Create an API key in PIG under Settings → API keys — the plaintext is shown once — then:

export PIG_URL=https://primeintellectgrowth.com
export PIG_API_KEY=pig_...

Scope the key to read unless the agent genuinely needs to write. An agent acting for you is a separate principal from you: it has its own audit trail and can be revoked without disturbing your session, and it can never reach further than you can — on a write, the key's write scope is checked first and then your own capability for that team.

⚠️ Reads are not yet gated. The read policy exists and is tested but is not mounted in app.ts, so a read-scoped key currently reaches every GET in the product, including supplier cost and margin. Treat any key you mint as cost-visible until that lands.

What connects

Client How
Claude Code claude mcp add pig -- pnpm --dir /path/to/pig exec tsx apps/mcp/src/stdio.ts
Codex Add the same command as an MCP server in its config, with the same two environment variables
prime-agent It is an MCP client; register the same stdio command
Buzz Agents reach PIG through the ACP bridge's MCP support

CLI

The pig CLI is the HTTP API surface for scripts and Prime Agent kernels. It never receives database credentials and has no arbitrary-request, shell, or filesystem command. Configure it separately from the MCP process:

export PIG_API_URL=https://primeintellectgrowth.com
export PIG_API_KEY=pig_...

pnpm run pig -- me
pnpm run pig -- --json capacity idle --threshold 0.2
pnpm run pig -- --json capacity search --gpu-type H100_80GB --min-gpu-count 8

--api-url and --api-key override the environment for one invocation. In --json mode success writes one JSON value to stdout, while failures write one JSON error to stderr and exit non-zero. The key is sent only as a bearer token and is redacted if an upstream error happens to echo it.

The tools

Tool What it answers
pig_whoami Who am I acting for, and which teams am I on?
pig_my_pipeline Where are we? What needs attention?
pig_capacity_match What have we bought that would serve this customer?
pig_margin_report What is each block earning against what it cost?
pig_idle_capacity What are we paying for and not selling?
pig_inventory_search What could we buy to cover demand we cannot serve?
pig_search Find an account
pig_get_account Everything about one account
pig_log_activity Record a call, meeting or note

pig_capacity_match is the one worth learning. Ask it in plain language:

"A customer wants 128 H100s with InfiniBand for three months, ceiling $2.80 per GPU-hour. What have we got?"

It returns ranked matches, preferring blocks that are sitting idle — those hours are already paid for — and warns explicitly when a match would sell below break-even.

Why the surface is small

Nine tools, each doing one thing. A sprawling tool list measurably degrades model performance, and anything genuinely niche is reachable through pig_search or the HTTP API. If you need something that is not here, it is probably better added as a service method than as a tenth tool.

What it cannot do

The MCP server holds an API key and calls the same HTTP API a browser does. It has no database credentials and no privileged path. There is deliberately no tool that provisions infrastructure, spends money, or emails a customer.