Files
org/OPERATIONS.md

8.0 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 paperclip namespace (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
│   ├── countess.pem
│   ├── nancy.pem
│   ├── addison.pem
│   ├── gandalf.pem
│   ├── regina.pem
│   ├── hugh.pem
│   └── samuel.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
        └── marketing/
            └── samuel/.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 privilegedescalation org is private. Clone requires a valid token:

git clone https://x-access-token:<TOKEN>@github.com/privilegedescalation/agents.git

Use a personal access token or a GitHub App installation token. The repo remote must include the token for future pulls (see Routine Maintenance).

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" \
    "$AGENTS_DIR/marketing/samuel"; 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

  1. Create profile files in this repo: AGENTS.md, SOUL.md, HEARTBEAT.md, TOOLS.md, CONFIG.md
  2. Create the DB record via Paperclip API or direct SQL — include adapterConfig with:
    • cwd: agent directory path (e.g., /paperclip/privilegedescalation/agents/engineering/newagent)
    • env.HOME: same as cwd
    • env.GITHUB_APP_ID_<NAME>: the GitHub App ID
    • env.GITHUB_PEM_PATH_<NAME>: path to PEM (e.g., /paperclip/secrets/github-pems/newagent.pem)
    • instructionsFilePath: path to AGENTS.md
    • model: model ID (e.g., claude-opus-4-6)
  3. Create the GitHub App via GitHub UI manifest flow, install on the privilegedescalation org
  4. Add the PEM to the K8s Secret at /paperclip/secrets/github-pems/
  5. On the pod, create the .claude symlink:
    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
    '
    
  6. Pull the repo on the pod:
    kubectl exec -n paperclip deploy/paperclip -- bash -c '
      cd /paperclip/privilegedescalation/agents && git pull
    '
    
  7. Create DB records for company_memberships and principal_permission_grants
  8. Update COMPANY.md roster table
  9. 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 a GitHub App installation token:

kubectl exec -n paperclip deploy/paperclip -- bash -c '
  export GITHUB_APP_ID_COUNTESS=1234567
  export GITHUB_PEM_PATH_COUNTESS=/paperclip/secrets/github-pems/countess.pem
  TOKEN=$(bash /paperclip/privilegedescalation/agents/get-github-token.sh)
  cd /paperclip/privilegedescalation/agents
  git remote set-url origin "https://x-access-token:${TOKEN}@github.com/privilegedescalation/agents.git"
  git pull
'
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 env and model)

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