- Fix $AGENT\_HOME → $AGENT_HOME in Karen, Nancy, Regina AGENTS.md - Standardize section dividers: *** → --- in Gandalf and Hugh SOUL.md - Replace get-github-token.sh reference in TOOLS.md and OPERATIONS.md with github-app-token skill Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
7.5 KiB
Privileged Escalation — Pod Operations Runbook
This document covers the pod-side setup required to run Privileged Escalation agents on the Paperclip pod. All agents run as child processes of the Paperclip server inside the paperclip namespace.
Prerequisites
- Paperclip pod running in
paperclipnamespace (kubectl -n paperclip) - Shared Claude credentials at
/paperclip/.claude/.credentials.json - GitHub App PEM keys mounted at
/paperclip/secrets/github-pems/(via K8s Secret) - Agent records created in the Paperclip DB with correct
adapterConfig
Directory Layout (on pod)
/paperclip/
├── .claude/.credentials.json # Shared Anthropic credentials (all agents symlink to this)
├── secrets/github-pems/ # K8s Secret mount — one PEM per GitHub App
│ ├── privilegedescalation-ceo.pem
│ ├── privilegedescalation-cto.pem
│ ├── privilegedescalation-engineer.pem
│ └── privilegedescalation-qa.pem
└── privilegedescalation/
└── agents/ # This repo, cloned here
├── ceo/
│ └── .claude/.credentials.json -> /paperclip/.claude/.credentials.json
├── cto/
│ └── .claude/.credentials.json -> /paperclip/.claude/.credentials.json
├── cmo/
│ └── .claude/.credentials.json -> /paperclip/.claude/.credentials.json
├── engineering/
│ ├── gandalf/.claude/.credentials.json -> /paperclip/.claude/.credentials.json
│ ├── regina/.claude/.credentials.json -> /paperclip/.claude/.credentials.json
│ └── hugh/.claude/.credentials.json -> /paperclip/.claude/.credentials.json
Initial Setup
1. Clone the repo
kubectl exec -n paperclip deploy/paperclip -- bash -c '
mkdir -p /paperclip/privilegedescalation
cd /paperclip/privilegedescalation
git clone https://github.com/privilegedescalation/agents.git
'
Note: The
privilegedescalationorg is private. Clone requires a valid token:git clone https://x-access-token:<TOKEN>@github.com/privilegedescalation/agents.gitUse a personal access token or a GitHub App installation token. The repo remote must include the token for future pulls (see Routine Maintenance).
2. Create .claude directories and symlink credentials
Each agent's HOME is set to its directory in this repo (e.g., /paperclip/privilegedescalation/agents/ceo). Claude Code expects credentials at $HOME/.claude/.credentials.json. All agents share the same Anthropic credentials, so we symlink.
kubectl exec -n paperclip deploy/paperclip -- bash -c '
AGENTS_DIR=/paperclip/privilegedescalation/agents
CRED_SOURCE=/paperclip/.claude/.credentials.json
for agent_dir in \
"$AGENTS_DIR/ceo" \
"$AGENTS_DIR/cto" \
"$AGENTS_DIR/cmo" \
"$AGENTS_DIR/engineering/gandalf" \
"$AGENTS_DIR/engineering/regina" \
"$AGENTS_DIR/engineering/hugh"; do
mkdir -p "$agent_dir/.claude"
ln -sf "$CRED_SOURCE" "$agent_dir/.claude/.credentials.json"
done
'
3. Verify GitHub PEM keys
PEM keys are mounted from a K8s Secret at /paperclip/secrets/github-pems/. Each agent's adapterConfig.env references its PEM via GITHUB_PEM_PATH_<NAME>. Verify they exist:
kubectl exec -n paperclip deploy/paperclip -- ls -la /paperclip/secrets/github-pems/
To add a new PEM, update the K8s Secret (managed via sealed-secrets or SOPS) and the mount will auto-refresh.
Adding a New Agent
- Create profile files in this repo:
AGENTS.md,SOUL.md,HEARTBEAT.md,TOOLS.md,CONFIG.md - Create the DB record via Paperclip API or direct SQL — include
adapterConfigwith:cwd: agent directory path (e.g.,/paperclip/privilegedescalation/agents/engineering/newagent)env.HOME: same ascwdenv.GITHUB_APP_ID_<NAME>: the GitHub App IDenv.GITHUB_PEM_PATH_<NAME>: path to PEM (e.g.,/paperclip/secrets/github-pems/newagent.pem)instructionsFilePath: path toAGENTS.mdmodel: model ID (e.g.,claude-opus-4-6)
- Create the GitHub App via GitHub UI manifest flow, install on the
privilegedescalationorg - Add the PEM to the K8s Secret at
/paperclip/secrets/github-pems/ - On the pod, create the
.claudesymlink:kubectl exec -n paperclip deploy/paperclip -- bash -c ' mkdir -p /paperclip/privilegedescalation/agents/engineering/newagent/.claude ln -sf /paperclip/.claude/.credentials.json \ /paperclip/privilegedescalation/agents/engineering/newagent/.claude/.credentials.json ' - Pull the repo on the pod:
kubectl exec -n paperclip deploy/paperclip -- bash -c ' cd /paperclip/privilegedescalation/agents && git pull ' - Create DB records for
company_membershipsandprincipal_permission_grants - Update COMPANY.md roster table
- Commit, push, pull on pod
Routine Maintenance
Pulling repo updates
The privilegedescalation org is private. The git remote must include a valid token. If git pull fails with auth errors, use a personal access token:
GH_TOKEN=$(gh auth token) # or any valid PAT with repo access
kubectl exec -n paperclip deploy/paperclip -- bash -c "
cd /paperclip/privilegedescalation/agents
git -c url.\"https://${GH_TOKEN}@github.com/\".insteadOf=\"https://github.com/\" pull
"
Or regenerate using the github-app-token skill to obtain a fresh installation access token, then use it to authenticate git.
Verifying credential symlinks
kubectl exec -n paperclip deploy/paperclip -- bash -c '
find /paperclip/privilegedescalation/agents -maxdepth 4 -name ".credentials.json" -type l -exec ls -la {} \;
'
Checking agent HOME isolation
Each agent must have its own HOME to prevent cross-contamination of caches, config, and tool state. Verify:
kubectl exec -n paperclip deploy/paperclip -- bash -c '
psql "$DATABASE_URL" -c "
SELECT name, adapter_config->'\''env'\''->'\''HOME'\''->'\''value'\'' as home
FROM agents
WHERE company_id = '\''38ad87cc-54cd-41c6-93f5-1bc68be94349'\''
ORDER BY name;
"
'
Special: Regina (opencode_local)
Regina uses the opencode_local adapter, not claude_local. Her prompt is stored as promptTemplate in the DB, not loaded from a file. See COMPANY.md "Known Issues" section for:
- Prompt restoration after UI saves (which wipe
promptTemplate) - Env/model restoration after UI saves (which wipe
envandmodel)
Troubleshooting
Agent says "Claude credentials not found"
The .claude/.credentials.json symlink is missing or broken. Re-create it:
mkdir -p /paperclip/privilegedescalation/agents/<path>/.claude
ln -sf /paperclip/.claude/.credentials.json /paperclip/privilegedescalation/agents/<path>/.claude/.credentials.json
Agent says "PEM file not found"
The K8s Secret mount may not have refreshed, or the PEM name doesn't match GITHUB_PEM_PATH_<NAME> in the agent's adapter config. Check:
ls -la /paperclip/secrets/github-pems/
Git pull auth failure
The privesc org is private — tokens expire. Use a PAT or regenerate an installation token (see Routine Maintenance above).
Agent can't reach API (HTTP 000)
Transient issue at heartbeat startup — the server may be briefly busy spawning the agent process. Agents self-recover by retrying. If persistent, verify PAPERCLIP_API_URL resolves correctly:
curl -s http://localhost:3100/api/health