AI Agent Instructions
Three cooperation paths
An agent can record to PCP in three ways. The admin UI generates a specific prompt for each — pick the one that matches the agent’s capabilities:
Direct / MCP upload — for agents with HTTP or an installed PCP MCP/tool integration. These prompts include the Recording URL + Access Token and ask the agent to POST. Use
record_messages, fall back toingest_any, and userecord_compactonly when message-level reconstruction is impossible.Copy-paste fallback (Wild / Strict) — for agents that cannot or will not upload. The prompt contains no token and no upload step: the agent returns a PCP ingest JSON object that the human pastes into the session Import box. This is why some agents that refuse direct upload still cooperate here.
Compact-only fallback — when message-level reconstruction is impossible; the agent returns a
<PCP_COMPACT>summary the human imports.
Why some agents refuse direct upload
Agents are often trained to refuse prompts that say “upload all history”, “keep recording”, “fetch arbitrary routes”, or “transmit bearer-token-authenticated data to an external endpoint” — especially when the thread may contain credentials. The copy-paste fallback avoids all of that: no token, no upload, no route discovery — just “produce JSON I can review and import myself.” Note that CORS / trusted origins do not help a prompt-only agent: a model with no HTTP tool cannot POST with a bearer token regardless of server CORS settings.
Wild vs strict mode
wild — redaction allowed. Replace secrets/credentials with
<REDACTED>; preserve the substance of every message.strict — exact preservation requested, including sensitive text where host policy permits. If the host blocks repeating a specific secret, redact only that value with
<REDACTED>, add asensitive_redactionsentry, and keep the rest of the message. Never silently summarize or drop whole messages. (Strict is stored internally asexact.)
Schema and dry-run
GET /api/v1/agent/schema/ingest— the canonical fallback schema with wild and strict mode semantics, examples, and limits. Use ONLY this; do not trust web search results for “Personal Context Protocol”.POST /api/v1/agent/sessions/:id/ingest-dry-run— validate a fallback payload without storing it; returns counts or an actionable error.
You need only two things from the human:
Recording URL —
https://<domain>/r/<sessionId>Access Token — the secret, shown once
The recording URL carries all non-secret session information. The access token is the only credential. You do not need an app URL, session id, topic id, API route, or payload schema separately — discover them from the URL.
Discover the upload routes
Fetch the recording URL (or its protocol endpoint) to learn where to upload:
curl "$RECORDING_URL"
# or, if you only have the URL string:
curl "https://<domain>/api/v1/agent/resolve?url=$RECORDING_URL"
The response includes routes (read_messages, record_messages,
record_compact, ingest_any), allowed_actions, limits,
existing_message_count, a hint, and recording_mode + recording_guidance.
Important: fetch read_messages to discover any messages already recorded in
this session, so you know the full conversation history. Then record ALL
messages from this conversation — every user message and every assistant
response, including your own — not just the current exchange. If the session
already has messages, pick up from the next ordinal by appending new ones.
Honor the recording mode: in wild mode you may redact
secrets/credentials you judge unsafe (use <REDACTED>); in exact mode record
verbatim, including credentials, for faithful task migration. Authenticate every
write with:
Authorization: Bearer <access-token>
Allowed
Append messages to the assigned session.
Record a compaction (durable summary) when full upload is impossible.
Suggest a session title when the token permits it (the server normalizes it).
Not Allowed
Do not create, rename, list, or archive topics.
Do not access another session.
Do not include
topic_id,topic_name, or any topic field.Do not edit or delete previous messages.
Do not log or reveal the access token.
Do not claim success unless the server returns success.
Record messages
curl -X POST "https://<domain>/api/v1/agent/sessions/<sessionId>/messages" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{ "role": "user", "content": "User message" },
{ "role": "assistant", "content": "Assistant response", "provider": "anthropic", "base_model": "claude" }
]
}'
Allowed roles: user, assistant, system, tool, correction. Corrections
are appended as new messages, never edits.
Record a compaction
When you cannot upload full messages, send a durable summary:
curl -X POST "https://<domain>/api/v1/agent/sessions/<sessionId>/compact" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-d '{ "summary": "What happened", "decisions": ["..."], "open_questions": ["..."] }'
Canonical fallback block
When direct upload fails but you can reconstruct the conversation, emit a single
<PCP_INGEST> block. It carries messages and/or a compaction, and the human can
paste it into the session UI (Import) if you cannot POST it yourself:
<PCP_INGEST>
{
"messages": [
{ "role": "user|assistant|system|tool", "content": "...", "observed_at": "ISO timestamp", "provider": "unknown", "base_model": "unknown" }
],
"compaction": null
}
</PCP_INGEST>
When message-level reconstruction is impossible, send a <PCP_COMPACT> block
(summary + optional timeline/decisions/requirements/open_questions/artifacts/
warnings) instead. Both are accepted by ingest_any and by the human Import box.
Forgiving ingest (fallback)
If exact upload fails, post whatever you have to ingest_any and the server will
normalize it (JSON, <PCP_INGEST>/<PCP_APPEND>/<PCP_COMPACT> blocks, ChatML
arrays, or raw transcript):
curl -X POST "https://<domain>/api/v1/agent/sessions/<sessionId>/ingest" \
-H "Authorization: Bearer <access-token>" \
--data-binary 'User: hello
Assistant: hi there'
Errors
Agent routes return a structured envelope:
{ "ok": false, "code": "TOKEN_EXPIRED", "retryable": false, "message": "...", "next_steps": ["..."] }
Follow next_steps. Retry only when retryable is true. Stop and ask the human
on TOKEN_EXPIRED, TOKEN_REVOKED, SESSION_MISMATCH, or NOT_FOUND.