Put Piggy on Prime Agent, and let it write to the book
CI / verify (push) Successful in 7m6s
CI / publish (push) Has been skipped

Piggy was a hand-rolled OpenAI tool loop. It is now a Prime Agent session —
Prime Intellect's own harness, embedded as a Node library — answering from
PIG's tools and, for the first time, able to put information into the CRM
rather than only read it out.

The harness is a coding agent, so the first job was taking the coding agent
away from it. `noTools: 'all'` plus an explicit allowlist leaves the model
with PIG's ten `pig_*` tools and no bash, no filesystem, no IPython. That
holds under attack: a hostile extension, a skill and a settings file planted
in the agent's own directory, then `setActiveToolsByName` called with every
built-in, still leaves ten tools, all ours. Both lines are load-bearing —
`noTools` alone registers nothing, and the allowlist is what admits our own.

Writing is gated rather than assumed. A change is proposed, not made: the
tool returns a description, the transcript renders a diff card, and nothing
reaches the database until someone presses Apply. Contracts, commitments,
allocations and compliance always stop for a human whatever the mode. Every
write runs through `executeMutation` as the calling user, so their
capabilities and the audit trail apply exactly as they would to a human's.

Four things about the SDK are wrong in its own documentation and cost a
debugging cycle each: models.json does not resolve an env var name for
`apiKey`, it sends the literal string; there is no built-in prime-inference
provider in 0.84.1; a ResourceLoader you pass in is never reloaded for you;
and the stock system prompt is a coding-assistant prompt that must be
replaced — but replacing it also silently removes the tool list, because the
harness only renders that section when it owns the prompt. AGENTS.md records
all four.

The expensive one was thinking level. The harness defaults to `medium`, and
nemotron spent an entire 4,096-token budget reasoning and returned an empty
answer. `low` was worse; `off` omits the parameter so the endpoint's default
wins. An explicit `reasoning_effort: none` via `thinkingLevelMap` took a turn
from 6,195 output tokens to 149.

And a turn is now bounded. The harness loop is `while (true)` with no
iteration cap; a runaway on a frontier model would have eaten the credit it
is supposed to report on. Ceilings on model calls and tokens, enforced both
through the harness hook and independently from the event stream, plus a
per-user daily spend limit — and the ledger now records spend on turns that
fail, which it previously discarded.

Signing in lands on /piggy, which is a workspace: conversations down one
side, the agent in the middle, what it did and what it cost beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
claude
2026-08-14 05:26:28 -07:00
parent 99d165b5e5
commit f0173440e4
77 changed files with 28108 additions and 1672 deletions
+59
View File
@@ -113,11 +113,70 @@ services:
# identity every worker shares — the one thing a lease exists to prevent.
# A blank line in .env still passes the empty string, which is why the
# optional keys are commented out in .env.example rather than left blank.
#
# The credential USED to share that hazard, and it was the nastiest
# instance of it: PRIME_API_KEY and PIGGY_INFERENCE_API_KEY are alternative
# spellings of one key, and a blank line for the spelling you did NOT use is
# not absent — it is an empty string. Piggy crash-looped complaining about a
# key that was set perfectly well under its other name. Both are now read
# through a preprocess that treats '' as absent (apps/piggy/src/config.ts),
# so a leftover blank line for either spelling is harmless. Every OTHER key
# in this block still coerces from the empty string, so the rule above
# stands: comment out what you are not setting rather than leaving it blank.
environment:
- DATABASE_URL=postgres://${POSTGRES_USER:-pig}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB:-pig}
# The model credential. One key serves Prime Inference and the Prime
# platform API, and apps/piggy/src/config.ts accepts either spelling:
# PIGGY_INFERENCE_API_KEY is kept as the legacy alias so a .env written
# before the harness swap still boots. Both are listed because either may
# be the one the operator set, and the config resolves whichever it finds
# into a single value; setting both to different keys is not a supported
# arrangement — PRIME_API_KEY wins.
- PRIME_API_KEY
- PIGGY_INFERENCE_API_KEY
- PIGGY_INFERENCE_BASE
- PIGGY_MODEL
# Prime Agent settings. Every one of these has a default in
# apps/piggy/src/config.ts, so they are listed in the bare form: absent
# from .env means absent from the container, which is what lets the code
# own the default. The note above the block says why the mapped form
# would be wrong here.
- PIGGY_AGENT_MODEL
- PIGGY_AGENT_MODE
# How hard the model thinks before answering, and the single setting most
# likely to make a working deployment look broken. The harness defaults
# this to `medium`, which is tuned for a coding agent: on nemotron that
# produced 6,195 output tokens of reasoning and an EMPTY answer, because
# the turn hit its token ceiling while still thinking (finish_reason
# `length`). `low` was worse. `off` is Piggy's default and maps to the
# endpoint's `reasoning_effort: none` — 149 output tokens and a correct
# answer for the same question. This is PER MODEL: a deployment that
# changes PIGGY_AGENT_MODEL may need a thinkingLevelMap entry for the new
# model in apps/piggy/src/agent/models.json before raising this.
- PIGGY_AGENT_THINKING
- PIGGY_AGENT_MAX_TOKENS
# Fixed for this container, like the chat host below, and for a stronger
# reason than convenience.
#
# The harness discovers extensions, skills and context files from its cwd,
# and Piggy hands it this directory as both cwd and agent directory. Point
# it at a checkout — or bind-mount one over it — and repo contents become
# reachable from a CRM agent's prompt. The image creates this path owned
# by `node`, mode 0700.
#
# Set explicitly rather than left to the `~/.pig/piggy-agent` default,
# which resolves through HOME: under `docker run` that is /home/node and
# works, but a runtime that starts this image with a numeric user and no
# passwd entry leaves HOME unset, os.homedir() answers `/`, and the agent
# dies creating its directory on the first turn — long after the deploy
# reported success.
#
# NOT persisted, deliberately. Nothing here is worth keeping across a
# restart: models.json is rewritten from the image at every boot, the
# credential store is in-memory by design, sessions are in-memory, and the
# conversations live in Postgres. A volume here would only be a way for a
# file to outlive the image that wrote it.
- PIGGY_AGENT_DIR=/var/lib/piggy-agent
- PIGGY_LEASE_SECONDS
- PIGGY_POLL_INTERVAL_MS
- PIGGY_MAX_TOKENS