Ship filesystem log tailing as 0.2.0 (port c8429cf path fix from claude-k8s before merge) #2

Open
opened 2026-04-30 13:09:46 +00:00 by cpfarhood · 0 comments
cpfarhood commented 2026-04-30 13:09:46 +00:00 (Migrated from github.com)

Goal

Land the filesystem-log-tail rewrite as 0.2.0. The branch exists locally but has two latent bugs that already bit paperclip-adapter-claude-k8s 0.2.1 in production. Port the fix before merging, otherwise every Job will fail with an init-container exit code 1.

Current state

  • Local branch feat/filesystem-log-tail-and-liveness-flag is not pushed to origin yet. It's at commit 127eab8 with the K8s log-API → PVC filesystem-tail rewrite (78d655e feat: replace K8s log streaming with PVC filesystem tailing).
  • A small WIP refactor is stashed as stash@{0} on that branch — fs.stat dynamic-import destructuring + vi.hoisted test mock fix. Pop it when you check the branch out.
  • Master is at 0.1.39, which contains the CJS ui-parser fix and the @paperclipai/adapter-utils bump to ^2026.428.0. Do not let the feature-branch merge clobber those (PR #11 in claude-k8s did exactly that and we had to redo the work).

What's broken in the branch

Both bugs are in src/server/job-manifest.ts and were fixed in paperclip-adapter-claude-k8s commit c8429cf ("fix: write logs to /paperclip/instances/default/data/run-logs/ to match server PVC layout"). Port that fix verbatim.

Bug 1 — init container can't mkdir the log dir

The init container runs:

```
mkdir -p /paperclip/instances/default/run-logs// && cp ... /tmp/prompt/prompt.txt
```

at lines 464 (large-prompt secret variant) and 471 (env-var variant). The PVC is not mounted in the init container — only `prompt` and `prompt-secret` volumes are mounted there. So the mkdir runs against init's ephemeral rootfs as UID 1000 in a path that doesn't exist, exits 1, the `&&` short-circuits, the prompt copy never happens, and the Job dies with `Init container 'write-prompt' failed with exit code 1`.

Fix: drop the `mkdir -p ... &&` from both init container variants. The directory already exists on the PVC because the Paperclip server creates it. Both containers run as UID 1000 with fsGroup 1000, so the main container's `tee` writes to the pre-existing path with no setup needed.

Bug 2 — log path missing `/data/` segment

`buildPodLogPath()` in `src/server/job-manifest.ts:27-29` returns:

```
/paperclip/instances/default/run-logs///.pod.ndjson
```

but the Paperclip server creates and tails from:

```
/paperclip/instances/default/data/run-logs///.pod.ndjson
```

Even if the mkdir worked, the server wouldn't see the file. Fix: add `/data/` to the constant in `buildPodLogPath()`. Update the same path in both init-container command strings (lines 464 and 471) for consistency, even though those will go away once the mkdir is dropped.

Plan

  1. `git checkout feat/filesystem-log-tail-and-liveness-flag`
  2. `git stash pop` to restore the WIP refactor
  3. `git rebase master` — pulls in the CJS bundle step + adapter-utils bump from 0.1.39. Resolve any `package.json` conflicts in favor of master's deps.
  4. Apply the c8429cf-equivalent fixes:
    • `src/server/job-manifest.ts:27`: change path to `/paperclip/instances/default/data/run-logs/...`
    • `src/server/job-manifest.ts:464,471`: drop `mkdir -p ... &&` from both init command strings
    • Update `src/server/job-manifest.test.ts` expectations for the new path / no-mkdir
  5. `npm run typecheck && npm test` — must be green
  6. `npm run build` — verify `dist/ui-parser.js` still emits CJS (`grep "module.exports" dist/ui-parser.js` should match)
  7. Open PR, merge to master
  8. `npm version minor` — produces v0.2.0
  9. `git push origin master && git push origin v0.2.0`
  10. Verify the outcome, don't trust exit 0. Per CLAUDE.md:
    • `gh run watch` until the v0.2.0 publish run is green
    • `npm view paperclip-adapter-opencode-k8s@0.2.0 version` returns 0.2.0
    • Run an actual opencode_k8s agent against the new version and confirm:
      • The Job's init container exits 0 (no mkdir failure)
      • The pod's claude-equivalent container writes to `/paperclip/instances/default/data/run-logs/...`
      • The transcript renders structured entries (assistant / tool_call / tool_result), not raw JSONL

Reference commits

  • `paperclip-adapter-claude-k8s@c8429cf` — the path/mkdir fix to port
  • `paperclip-adapter-claude-k8s@7a6d1a4` — CJS ui-parser fix already in opencode-k8s 0.1.39 (don't re-do)
  • `paperclip-adapter-opencode-k8s@480f7cf` — current master, has the CJS + adapter-utils fixes that the feature branch must not clobber

Why this matters

claude-k8s shipped 0.2.1 with these two bugs, every run failed in production for a day, fix shipped as 0.2.2. The opencode-k8s feature branch has the identical pre-fix pattern. Don't repeat the cycle.

## Goal Land the filesystem-log-tail rewrite as `0.2.0`. The branch exists locally but has two latent bugs that already bit `paperclip-adapter-claude-k8s` 0.2.1 in production. Port the fix before merging, otherwise every Job will fail with an init-container exit code 1. ## Current state - Local branch `feat/filesystem-log-tail-and-liveness-flag` is **not pushed** to origin yet. It's at commit `127eab8` with the K8s log-API → PVC filesystem-tail rewrite (`78d655e feat: replace K8s log streaming with PVC filesystem tailing`). - A small WIP refactor is **stashed** as `stash@{0}` on that branch — `fs.stat` dynamic-import destructuring + `vi.hoisted` test mock fix. Pop it when you check the branch out. - Master is at `0.1.39`, which contains the CJS ui-parser fix and the `@paperclipai/adapter-utils` bump to `^2026.428.0`. **Do not let the feature-branch merge clobber those** (PR #11 in claude-k8s did exactly that and we had to redo the work). ## What's broken in the branch Both bugs are in `src/server/job-manifest.ts` and were fixed in `paperclip-adapter-claude-k8s` commit `c8429cf` (\"fix: write logs to /paperclip/instances/default/data/run-logs/ to match server PVC layout\"). Port that fix verbatim. ### Bug 1 — init container can't mkdir the log dir The init container runs: \`\`\` mkdir -p /paperclip/instances/default/run-logs/<companyId>/<agentId> && cp ... /tmp/prompt/prompt.txt \`\`\` at lines 464 (large-prompt secret variant) and 471 (env-var variant). The PVC is **not** mounted in the init container — only \`prompt\` and \`prompt-secret\` volumes are mounted there. So the mkdir runs against init's ephemeral rootfs as UID 1000 in a path that doesn't exist, exits 1, the \`&&\` short-circuits, the prompt copy never happens, and the Job dies with \`Init container 'write-prompt' failed with exit code 1\`. **Fix:** drop the \`mkdir -p ... &&\` from both init container variants. The directory already exists on the PVC because the Paperclip server creates it. Both containers run as UID 1000 with fsGroup 1000, so the main container's \`tee\` writes to the pre-existing path with no setup needed. ### Bug 2 — log path missing \`/data/\` segment \`buildPodLogPath()\` in \`src/server/job-manifest.ts:27-29\` returns: \`\`\` /paperclip/instances/default/run-logs/<companyId>/<agentId>/<runId>.pod.ndjson \`\`\` but the Paperclip server creates and tails from: \`\`\` /paperclip/instances/default/data/run-logs/<companyId>/<agentId>/<runId>.pod.ndjson \`\`\` Even if the mkdir worked, the server wouldn't see the file. **Fix:** add \`/data/\` to the constant in \`buildPodLogPath()\`. Update the same path in both init-container command strings (lines 464 and 471) for consistency, even though those will go away once the mkdir is dropped. ## Plan 1. \`git checkout feat/filesystem-log-tail-and-liveness-flag\` 2. \`git stash pop\` to restore the WIP refactor 3. \`git rebase master\` — pulls in the CJS bundle step + adapter-utils bump from 0.1.39. Resolve any \`package.json\` conflicts in favor of master's deps. 4. Apply the c8429cf-equivalent fixes: - \`src/server/job-manifest.ts:27\`: change path to \`/paperclip/instances/default/data/run-logs/...\` - \`src/server/job-manifest.ts:464,471\`: drop \`mkdir -p ... &&\` from both init command strings - Update \`src/server/job-manifest.test.ts\` expectations for the new path / no-mkdir 5. \`npm run typecheck && npm test\` — must be green 6. \`npm run build\` — verify \`dist/ui-parser.js\` still emits CJS (\`grep \"module.exports\" dist/ui-parser.js\` should match) 7. Open PR, merge to master 8. \`npm version minor\` — produces v0.2.0 9. \`git push origin master && git push origin v0.2.0\` 10. **Verify the outcome, don't trust exit 0.** Per CLAUDE.md: - \`gh run watch\` until the v0.2.0 publish run is green - \`npm view paperclip-adapter-opencode-k8s@0.2.0 version\` returns 0.2.0 - Run an actual opencode_k8s agent against the new version and confirm: - The Job's init container exits 0 (no mkdir failure) - The pod's claude-equivalent container writes to \`/paperclip/instances/default/data/run-logs/...\` - The transcript renders structured entries (assistant / tool_call / tool_result), not raw JSONL ## Reference commits - \`paperclip-adapter-claude-k8s@c8429cf\` — the path/mkdir fix to port - \`paperclip-adapter-claude-k8s@7a6d1a4\` — CJS ui-parser fix already in opencode-k8s 0.1.39 (don't re-do) - \`paperclip-adapter-opencode-k8s@480f7cf\` — current master, has the CJS + adapter-utils fixes that the feature branch must not clobber ## Why this matters claude-k8s shipped 0.2.1 with these two bugs, every run failed in production for a day, fix shipped as 0.2.2. The opencode-k8s feature branch has the identical pre-fix pattern. Don't repeat the cycle.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: farhoodlabs/paperclip-adapter-opencode-k8s#2