Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
3.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
This is a Paperclip adapter plugin that runs Claude Code agents as isolated Kubernetes Jobs instead of inside the main Paperclip process. It uses the @kubernetes/client-node library to interact with the K8s API.
CI/CD
Build and publish are handled by GitHub Actions on tag push — do not build locally. To release a new version, bump package.json with npm version and push the tag — CI handles the rest.
Common Commands
npm run typecheck # Type-check without emitting (local dev only)
npm test # Run tests (vitest run)
npm run test:watch # Run tests in watch mode
npm run coverage # Run tests with coverage
Do not run npm run build locally — it's run by the CI pipeline. To release: bump version (npm version), push, and CI publishes automatically.
Single test file: npx vitest run src/server/execute.test.ts
Architecture
Entry Point
src/index.ts exports createServerAdapter() which returns a ServerAdapterModule with all adapter capabilities. It re-exports types, models, and the execute function.
Server Module (src/server/)
execute.ts— Core execution flow: checks for concurrent runs, creates a K8s Job, waits for pod scheduling, streams logs, waits for job completion, parses Claude's stream-json output, and returns the result. Also handles cleanup and retention.job-manifest.ts— Builds the K8s Job manifest. Key design: an init container (busybox) writes the prompt to an emptyDir volume, then the mainclaudecontainer reads it via stdin. The shared PVC is mounted at/paperclipwithHOME=/paperclipto enable session resume.k8s-client.ts— Wrapper around@kubernetes/client-node. Caches the KubeConfig and self-pod introspection (getSelfPodInfo) which discovers the container image, imagePullSecrets, DNS config, PVC claim name, and env vars to forward to Job pods.config-schema.ts— Returns the UI config schema (typed asConfigFieldSchema[]) that Paperclip's web UI renders as a form.parse.ts— Parses Claude'sstream-jsonoutput format to extract session IDs, token usage, cost, and summaries.session.ts— Session codec for session resume.skills.ts/models.ts— ImplementlistSkills/syncSkillsandlistModelsfor theServerAdapterModuleinterface.
CLI Module (src/cli/)
format-event.ts— Formats Claude stream events for terminal output.
UI Parser (src/ui-parser.ts)
- Parses adapter-specific UI configuration fields.
Config Schema Note
The types in config-schema.ts (ConfigFieldSchema) must match what Paperclip's SchemaConfigFields component expects, since Paperclip's server calls adapter.getConfigSchema() and the UI reads the JSON at runtime.
Key Design Decisions
-
Pod introspection — On first
execute()call,getSelfPodInfo()reads the running pod's spec via K8s API and caches it. Every subsequent Job inherits the Deployment's image, secrets, DNS, and PVC without additional config. -
Concurrency guard — Before creating a Job,
execute.tslists existing Jobs labeled with the agent ID and blocks if any are still running (prevents session conflicts on the shared PVC). -
Prompt delivery — The prompt is written by a busybox init container to an
emptyDirvolume, then read by the mainclaudecontainer viastdin. This avoids escaping issues with env vars containing complex characters. -
Log streaming — Uses
k8s.Logfollow mode with automatic reconnection. If the follow stream ends before the job completes (API disconnect), a one-shot log read is used as fallback. -
Session resume — Works via the shared
/paperclipPVC mounted asHOME. TheruntimeSessionIdis passed via--resumeto the Claude CLI.