From b359335763630a2390de6b8248610b381f58d972 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Tue, 10 Nov 2026 22:41:41 +0100 Subject: [PATCH 1/2] feat(agentic-engineer): run the kagent lane's full run on its own harness image Pin the lane's Harness to the image main published from platform#6011 (kagent's Claude harness plus gh, jq, yq, curl and the whole agentic-engineering plugin), and replace the canary prompt with the full run: restore memory from the lane store, run the plugin's agentic-engineer entrypoint against the monorepo contract, and leave memory, transcript and report in the store however the run ends. The schedule stays paused: the full run is first tried once from the kagent UI before the PR that unpauses it. Co-Authored-By: Claude Opus 5.5 --- .../apps/agentic-engineer/harness.yaml | 6 +++ .../apps/agentic-engineer/job-schedule.yaml | 48 +++++++++++++------ .../test-kagent-claude-harness-wrapper.sh | 8 ++++ 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/k8s/providers/hetzner/apps/agentic-engineer/harness.yaml b/k8s/providers/hetzner/apps/agentic-engineer/harness.yaml index 660ac5e7a1..ef4a21b95d 100644 --- a/k8s/providers/hetzner/apps/agentic-engineer/harness.yaml +++ b/k8s/providers/hetzner/apps/agentic-engineer/harness.yaml @@ -11,6 +11,12 @@ metadata: namespace: agentic-engineer spec: claude: {} + # The lane's own harness image, pinned by digest as kagent requires: kagent's + # Claude harness plus the engineer's tools and the whole agentic-engineering + # plugin (scripts/kagent-claude-harness, devantler-tech/monorepo#4867, #4868). + # Main publishes and signs it; move this pin after each publish. + workload: + image: ghcr.io/devantler-tech/platform-kagent-claude-harness@sha256:5777ced3082c426842d7d43e73869d3cdc8828f93ec96ce78c9a30b558862097 substrate: workerPoolRef: name: agentic-engineer diff --git a/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml b/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml index 735b805480..9bc921825c 100644 --- a/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml +++ b/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml @@ -74,8 +74,9 @@ spec: - name: TIME_ZONE value: Europe/Copenhagen # Paused until every sub-issue of devantler-tech/monorepo#4866 is - # done (ADR 0014, point 6). The canary runs once, started from the - # kagent UI; the PR that swaps in the full run message unpauses it. + # done (ADR 0014, point 6). The full run is first tried once, started + # from the kagent UI with "run now", which works while paused; the + # PR that unpauses it follows that run and the maintainer's go-ahead. - name: PAUSED value: "true" # A run has no time limit: cutting one off mid-task wastes what it @@ -86,20 +87,39 @@ spec: # reaches. - name: EXECUTION_TIMEOUT value: 315360000s - # The current message is the canary (devantler-tech/monorepo#4869): - # it proves the model, GitHub and Git paths and changes nothing. - # The full engineering run replaces it once the canary has passed. + # The full run: the same thin pointer the host lanes' scheduler + # entries use, plus the lane store, because each run starts in a + # fresh sandbox (devantler-tech/monorepo#4869). The role itself + # comes from the agentic-engineering plugin in the harness image, + # never from this prompt. - name: PROMPT value: | - Canary run. Change nothing: create no branch, commit, issue, comment or - pull request. - 1. Name the model you are running as. - 2. Run `git -c http.extraHeader='Authorization: Basic kagent-credential-injected' ls-remote https://github.com/devantler-tech/monorepo.git HEAD` - and report the commit it prints. - 3. Shallow-clone that repository the same way and report the first line of - its AGENTS.md. - 4. Report which of the commands gh, curl, jq and yq exist in your sandbox. - Reply with a short report of each step and anything that failed. + Scheduled run of the devantler-tech Agentic Engineer on its kagent lane: + instance `kagent-cluster`, writer namespace `kagent/*`, one run a day. + + 1. Restore your native memory from the lane store. List memory/ with a + WebDAV PROPFIND (`curl -fsS -X PROPFIND -H 'Depth: 1'` plus the store + header) and download every file into ~/lane-memory/. Only a 404 for + memory/ means a first run, so start with an empty ~/lane-memory/. Any + other failure means the store is unreachable: stop and report it. + 2. Shallow-clone devantler-tech/monorepo, read its AGENTS.md, load the + agentic-engineering plugin and invoke its agentic-engineer entrypoint + as this scheduled run. ~/lane-memory/ is your native memory (the + legacy layout), as the durable-memory guide says for this lane. + Follow the consumer contract and fail closed on missing deployment + facts. Do not duplicate the role here. + 3. Before you stop, however the run ended, upload ~/lane-memory/ back to + memory/ on the lane store, and upload this session's transcript (the + newest Claude Code session JSONL under your Claude config directory) + and your run report to runs//transcript.jsonl and + runs//report.md. Create a missing folder with MKCOL before + writing into it, and check that every upload succeeded. + + This run may open, update and review devantler-tech pull requests and + issues, per AGENTS.md. It never merges. Only when genuinely blocked on a + decision only the maintainer can make, and only after trying to resolve + it yourself, open one public-safe `maintainer-ask` issue, following + AGENTS.md#Maintainer channels. # Retries of one Job share its uid, so a create whose reply was lost # returns the schedule it made instead of making a second one. - name: REQUEST_ID diff --git a/scripts/tests/test-kagent-claude-harness-wrapper.sh b/scripts/tests/test-kagent-claude-harness-wrapper.sh index fc3445ad77..85e77bd283 100755 --- a/scripts/tests/test-kagent-claude-harness-wrapper.sh +++ b/scripts/tests/test-kagent-claude-harness-wrapper.sh @@ -60,6 +60,14 @@ manager="$(jq -c '[.customManagers[] | select(.depNameTemplate == "devantler-tec | select(any(.matchStrings[]; startswith("ARG AGENT_PLUGINS_COMMIT=")))] | length' \ "${root}/.github/renovate.json")" [[ "${manager}" == 1 ]] || fail 'Renovate does not move the plugin commit' +# The lane's Harness runs this image, pinned by digest as kagent requires; the built-in image has +# neither the tools nor the whole plugin. +command -v yq >/dev/null || fail 'yq is required' +harness_image="$(yq '.spec.workload.image' "${root}/k8s/providers/hetzner/apps/agentic-engineer/harness.yaml")" +[[ "${harness_image}" =~ ^ghcr\.io/devantler-tech/platform-kagent-claude-harness@sha256:[0-9a-f]{64}$ ]] || + fail "the lane's Harness does not run this image by digest: ${harness_image}" +grep -Fq 'IMAGE: ghcr.io/devantler-tech/platform-kagent-claude-harness' "${root}/.github/workflows/publish-kagent-claude-harness.yaml" || + fail 'the Harness image is not the one the publish workflow builds' # The stub Claude Code records its arguments one per line, then its input, and exits with $STUB_EXIT. cat >"${work}/real-claude" <<'STUB' From 554dd3867f5d0c0feee2cb2fe325cdb04d647f36 Mon Sep 17 00:00:00 2001 From: Nikolai Emil Damm Date: Tue, 10 Nov 2026 22:58:36 +0100 Subject: [PATCH 2/2] fix(agentic-engineer): never let a second run in a day replace the first's record Two runs on one UTC date, such as a manual run beside the scheduled one, uploaded to the same runs// paths, so the later run replaced the earlier transcript and report. A later run now writes time-suffixed files beside them. The date folder stays, because the Improver's reader (kagent-lane-runs.sh) reads runs// and treats any other folder name as unreadable. Co-Authored-By: Claude Opus 5.5 --- .../hetzner/apps/agentic-engineer/job-schedule.yaml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml b/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml index 9bc921825c..9fb74e8613 100644 --- a/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml +++ b/k8s/providers/hetzner/apps/agentic-engineer/job-schedule.yaml @@ -112,8 +112,11 @@ spec: memory/ on the lane store, and upload this session's transcript (the newest Claude Code session JSONL under your Claude config directory) and your run report to runs//transcript.jsonl and - runs//report.md. Create a missing folder with MKCOL before - writing into it, and check that every upload succeeded. + runs//report.md. If an earlier run that day already wrote + them, never replace them: write yours beside them as + transcript-.jsonl and report-.md. + Create a missing folder with MKCOL before writing into it, and check + that every upload succeeded. This run may open, update and review devantler-tech pull requests and issues, per AGENTS.md. It never merges. Only when genuinely blocked on a