diff --git a/.gitignore b/.gitignore index 65d124e..2620aed 100644 --- a/.gitignore +++ b/.gitignore @@ -20,5 +20,4 @@ alignfirst-developer-tests/vendor/ # OpenClaw runtime state — recreated per-instance, not team-curated (a test # instance snapshots these into the workspace; we don't track them) -alignfirst-developer-tests/workspace/HEARTBEAT.md alignfirst-developer-tests/workspace/.openclaw/ diff --git a/alignfirst-developer-tests/Dockerfile b/alignfirst-developer-tests/Dockerfile index b523415..835fb0e 100644 --- a/alignfirst-developer-tests/Dockerfile +++ b/alignfirst-developer-tests/Dockerfile @@ -62,20 +62,20 @@ COPY --chown=claw:claw package.json package-lock.json /opt/openclaw-test/src/ COPY --chown=claw:claw vendor/ /opt/openclaw-test/src/vendor/ COPY --chown=claw:claw openclaw.json /home/claw/.openclaw/openclaw.json -# OpenClaw 2026.8.1 verifies managed plugin dependencies and capabilities at +# OpenClaw 2026.8 verifies managed plugin dependencies and capabilities at # gateway startup. Install the exact official artifacts instead of copying the # local package directory, which omits its runtime dependencies. Z.AI backs the # configured GLM model; Perplexity is auto-selected when OpenRouter is present. RUN npm ci --include=dev && \ OPENCLAW_CONFIG_PATH=/home/claw/.openclaw/openclaw.json \ npx openclaw plugins install --force --accept-capabilities \ - npm:@openclaw/codex@2026.8.1 && \ + npm:@openclaw/codex@2026.8.2 && \ OPENCLAW_CONFIG_PATH=/home/claw/.openclaw/openclaw.json \ npx openclaw plugins install --force --accept-capabilities \ - npm:@openclaw/zai-provider@2026.8.1 && \ + npm:@openclaw/zai-provider@2026.8.2 && \ OPENCLAW_CONFIG_PATH=/home/claw/.openclaw/openclaw.json \ npx openclaw plugins install --force --accept-capabilities \ - npm:@openclaw/perplexity-plugin@2026.8.1 && \ + npm:@openclaw/perplexity-plugin@2026.8.2 && \ OPENCLAW_CONFIG_PATH=/home/claw/.openclaw/openclaw.json \ npx openclaw plugins registry --refresh && \ npm cache clean --force diff --git a/alignfirst-developer-tests/openclaw.json b/alignfirst-developer-tests/openclaw.json index a953b6f..77529fd 100644 --- a/alignfirst-developer-tests/openclaw.json +++ b/alignfirst-developer-tests/openclaw.json @@ -14,8 +14,16 @@ "codex": { "enabled": true }, "discord-mock": { "enabled": true }, "slack-mock": { "enabled": true } - } + }, + "slots": { "memory": "none" } + }, + "memory": { + "search": { "enabled": false, "rememberAcrossConversations": false } + }, + "skills": { + "workshop": { "autonomous": { "mode": "off" } } }, + "update": { "checkOnStart": false }, "tools": { "profile": "coding", "alsoAllow": ["message", "browser"], @@ -85,8 +93,9 @@ "heartbeat": { "every": "24h", "target": "last", - "prompt": "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. Do not infer or repeat old tasks from prior chats. If nothing needs attention, reply exactly NO_REPLY." + "directPolicy": "allow" }, + "compaction": { "memoryFlush": { "enabled": false } }, "blockStreamingDefault": "on", "blockStreamingBreak": "text_end", "blockStreamingCoalesce": { "minChars": 1, "idleMs": 100 } diff --git a/alignfirst-developer-tests/package-lock.json b/alignfirst-developer-tests/package-lock.json index 2eb5eb4..818d3d1 100644 --- a/alignfirst-developer-tests/package-lock.json +++ b/alignfirst-developer-tests/package-lock.json @@ -13,7 +13,7 @@ "@paleo/openclaw-discord-mock": "file:vendor/openclaw-discord-mock.tgz", "@paleo/openclaw-slack-mock": "file:vendor/openclaw-slack-mock.tgz", "@paleo/openclaw-test": "file:vendor/openclaw-test.tgz", - "openclaw": "2026.8.1" + "openclaw": "2026.8.2" }, "devDependencies": { "@types/node": "~24.13.3", @@ -34,22 +34,22 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.239.tgz", - "integrity": "sha512-cIuZhK4u76S5Otq78U890GSA6BFT4SLqOuMqzU/bP/tWRWKhHhNp/3/pvgLwoVGlkdhD7luXWduqXKyLC+VNBQ==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.241.tgz", + "integrity": "sha512-pIHdCSTywFe30H0oWDCKZzC4ipBLtF5YMDRKjf6PHyARg57O4l/72v3b6QKnnefwtKKMe6uWJ1Y9lUJg/sKWyA==", "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" }, "optionalDependencies": { - "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.239", - "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.239" + "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.241", + "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.241" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", @@ -58,9 +58,9 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.239.tgz", - "integrity": "sha512-GGVGuCwFEUm6cMlnBX0LTC9JX5NdGzxddbuqWtRxEgo9EetS70SO3FW+reitALlotHghPTfnICQILbBDIRyX+Q==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.241.tgz", + "integrity": "sha512-v26ta54lKFMFEZzbOE+6p3YhKERWnDiEA6OmkSAg+3fAQHOa1+aLTKw222cfgzxgiVixwFtHMk8c63zsDd8aXQ==", "cpu": [ "arm64" ], @@ -71,9 +71,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.239.tgz", - "integrity": "sha512-QNbBXz3Pb3pQ7a+Kcbets6t9IrQhStKsfl5D518nYiGFoRMioO7efkZ6zHUcrGDqDC0LIzrs7tY2KNzH4RfwZA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.241.tgz", + "integrity": "sha512-5jweT0vft1ZCaGSoxZHF9vJlHbx8Yxx4+x5aHAIXTd4lx7ZbT4o5buEF8kpmTeHUB+Fw9jtFIm4QDsRiBXgf+Q==", "cpu": [ "x64" ], @@ -84,9 +84,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.239.tgz", - "integrity": "sha512-RE6tDtzU0xj58tsuxnlXMJO8ckJ4tx/1nUgR+D/fPEQVt84oOyXeVspKt1ffvycogh3Sr3MkCGwZrPmxu/V1nA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.241.tgz", + "integrity": "sha512-SxszQGffXiLzMEnAv+pJXEmQbA8haijKyRjjH/jOt1CLeMIfpjKcO9WQDv8dEA8nREWS3zJ103zjgecAF7oOQQ==", "cpu": [ "arm64" ], @@ -100,9 +100,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.239.tgz", - "integrity": "sha512-Ajc3cuszVdOwfMZVsGdxrCTmgWOeJpQWAIqu8jNEvERIeNnBxvWfGrjmLPxYT3/LJ9Uj/tFTpp52J4IcmrJE5w==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.241.tgz", + "integrity": "sha512-GslvPvSzehfCZyzOaJAt4lgodznm5zpl/LMXN8ygD12z5qnpM+I9/eFnmAaISJ0L8/vyohtlAP1jjaeR2jz1AQ==", "cpu": [ "arm64" ], @@ -116,9 +116,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.239.tgz", - "integrity": "sha512-q4YaDoPgqh0XM23RM1/Zje7OSKccuCTQE89KoppDFOsyGdRsUj5xr01LTtr5hnYQuZD7dfwAbz9zl1g0MF/7TA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.241.tgz", + "integrity": "sha512-gJRa922Qcm7loumHcXMDFEFg//tz1aOi7Nx0sQa9I9lC1JSN8yL6i7/idzOU5Hp193tEDFOgqIMFL/yRiXg+rw==", "cpu": [ "x64" ], @@ -132,9 +132,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.239.tgz", - "integrity": "sha512-zIUHiG4Romm/t6m/S9n8x4BKluyRCPk0147hPVo4xxkHkp4Di/7TnDMRKO3Wau4x361wRqlE2i5EpYT+CyJjHg==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.241.tgz", + "integrity": "sha512-kZigJ5Ug2I2G/n7Cunmwy4TGr0lOGnWrz6TkzyWiDcUmJOodoTH6GZECNarWAtETfN03AAeLfrpiz8z3hOEDqA==", "cpu": [ "x64" ], @@ -148,9 +148,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.239.tgz", - "integrity": "sha512-RxA29NdX9g3ZbpcXvSeWxpbg/Eoo3wXfO2eA1Vc7qa5JyAYjrl9xu6dIGAWMiyk/gnFxNh1WoFER77J9P6LTiQ==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.241.tgz", + "integrity": "sha512-/3yA9jQuCvHDVlILzhtslH6kFYOvydXyMZiKwnzqM8ZfvFTNO41w8TpiFpBLseyM+4A4E8QMeTKu3L01Xyb5IQ==", "cpu": [ "arm64" ], @@ -161,9 +161,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.239.tgz", - "integrity": "sha512-ylKIX0DfaK1EgWYbVEvBMYATVFdKjFcWvvypTIv2sJhM3KxJT/0lTzvqsai8jYeZN1FBHWlRNEUQJvJMjO/diA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.241.tgz", + "integrity": "sha512-cHYdAgORl9kynujMeYXyV1uj/hbmsBjRw9dRVkIW4/4sF7S6L4u/qDSzn1/wiNP7g2yWSJ4KbsvHDH2WWDnCBQ==", "cpu": [ "x64" ], @@ -309,9 +309,9 @@ } }, "node_modules/@grammyjs/types": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-4.0.0.tgz", - "integrity": "sha512-Z8lDLTvOlo12e5Vnly/vQh3JC9ppaitS1dGZ3w068gNitOd/y8tTSiib+Xm38aBGbtYGmUZwOc6afYrLs2CSTg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-5.0.0.tgz", + "integrity": "sha512-iq1Qrq1iPKkB8yAa0qSuIURMZOCuqTY5pWy5gHpCeL1oQ+GPadGhw/cDTVE8waJwuCzacUzuIjRv1sESvk7u7A==", "license": "MIT" }, "node_modules/@homebridge/ciao": { @@ -767,9 +767,9 @@ } }, "node_modules/@openclaw/ai": { - "version": "2026.8.1", - "resolved": "https://registry.npmjs.org/@openclaw/ai/-/ai-2026.8.1.tgz", - "integrity": "sha512-gUhfqsEZMRkgNZFegBMhKV5fw5OTziw+Pk2w0hOwOpNkT2W20VL2uS5Yz3ZbiC4snd5BQDBmmO33cVUgwr2aUg==", + "version": "2026.8.2", + "resolved": "https://registry.npmjs.org/@openclaw/ai/-/ai-2026.8.2.tgz", + "integrity": "sha512-Fx3f91YA7498buyxXQJoxITgkOZM0BHmSSroy0HLHeMLIod7qGWrNxarr41uhks1vDi15JLVueTZBEWtRV3KXQ==", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "0.120.0", @@ -777,7 +777,7 @@ "@mistralai/mistralai": "2.6.4", "openai": "7.5.0", "partial-json": "0.1.7", - "typebox": "1.3.16" + "typebox": "1.3.17" }, "engines": { "node": ">=22.19.0" @@ -805,9 +805,9 @@ } }, "node_modules/@openclaw/ai/node_modules/typebox": { - "version": "1.3.16", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.16.tgz", - "integrity": "sha512-Jac8dgnin+g2p1w1v9sk92Wvp49ZqsmSgNhrXDK+RqrovsjiORMZvYZ8t8id9b9XQp6LMfaAwnIRSHGsM+3FMw==", + "version": "1.3.17", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.17.tgz", + "integrity": "sha512-20PsSaZV1pN7pIfM/YEUHZNTv8X21+1ilPo/HN+6GtFbhCaQhLrIoKCkAkcBwIva3nYI+Ao0MxM1iDj5H3SOhw==", "license": "MIT" }, "node_modules/@openclaw/fs-safe": { @@ -845,9 +845,9 @@ } }, "node_modules/@paleo/openclaw-channel-mock-core": { - "version": "0.6.1", + "version": "0.7.0", "resolved": "file:vendor/openclaw-channel-mock-core.tgz", - "integrity": "sha512-xzfA+OTMSUxw/syKGKCePBXI5PY4Emir6V4kXfnH98llRGS4pWh7jtL6LcIfLNWzUMYwpbQoTRXdzO1b5VHjhg==", + "integrity": "sha512-TLY1ce8QKnb6SBSwkFN+SkJ7sVHw1ROoLdj2/6SJrviJAAe+nutdldI0duzwJFHUVBsKYP5qUCua+VlQXFCPGg==", "license": "MIT", "dependencies": { "typebox": "~1.3.23" @@ -861,12 +861,12 @@ } }, "node_modules/@paleo/openclaw-discord-mock": { - "version": "0.3.7", + "version": "0.3.8", "resolved": "file:vendor/openclaw-discord-mock.tgz", - "integrity": "sha512-pC9Nq9R0kQf6eNhzhYF6SS44VrjAjspttZUVdb98AngRatN6Ls5fpc6R+6mTyvtrfJG+I86Jff79Tqb8paiDUQ==", + "integrity": "sha512-5mXJWBScDTOoqcs+xl9UZNP0xj2agka02jx3kAKEHxedLBHPvt8/0I3l3HYCa+GePVOMm+Nyvfd5wkD3/5memg==", "license": "MIT", "dependencies": { - "@paleo/openclaw-channel-mock-core": "0.6.1" + "@paleo/openclaw-channel-mock-core": "0.7.0" }, "engines": { "node": ">=22.11.0" @@ -876,12 +876,12 @@ } }, "node_modules/@paleo/openclaw-slack-mock": { - "version": "0.3.7", + "version": "0.3.8", "resolved": "file:vendor/openclaw-slack-mock.tgz", - "integrity": "sha512-qDm4d+Q+O9/fMGmeNP3PhwdNdVydPtYtySokO87sGZrlwUEE3OMPYymzshbXjXOBQu6rEKwOoZFqPLjAsYMC2A==", + "integrity": "sha512-R25lYn36UpFmpWjrkhSB3PrZYamenAkNeF+I6P187wgqxJFLgpb3O7J8s0uvQUfvWfjrv8OJQq7xH4dQrXx1cw==", "license": "MIT", "dependencies": { - "@paleo/openclaw-channel-mock-core": "0.6.1" + "@paleo/openclaw-channel-mock-core": "0.7.0" }, "engines": { "node": ">=22.11.0" @@ -891,15 +891,15 @@ } }, "node_modules/@paleo/openclaw-test": { - "version": "0.15.5", + "version": "0.16.0", "resolved": "file:vendor/openclaw-test.tgz", - "integrity": "sha512-d/eXdKzM6hvh0A3c6OKCQ9iP7AAtxo8TIinY2fAVn7Bx3gv6bYu7LYHmle2s8owzSCcHGQLwLRmz5FG26ooRAA==", + "integrity": "sha512-fh2miIdZmPdRFwikCLC56UHXhloOmT3lqh1sBLLNcAFGkeVcVeO2EEYz1TYFJ3hCINhXP5kCoQMm+LCelZwO5Q==", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "~0.122.0", - "@paleo/openclaw-channel-mock-core": "0.6.1", - "@paleo/openclaw-discord-mock": "0.3.7", - "@paleo/openclaw-slack-mock": "0.3.7" + "@paleo/openclaw-channel-mock-core": "0.7.0", + "@paleo/openclaw-discord-mock": "0.3.8", + "@paleo/openclaw-slack-mock": "0.3.8" }, "bin": { "openclaw-test": "bin/cli.mjs" @@ -2820,12 +2820,12 @@ } }, "node_modules/grammy": { - "version": "1.45.1", - "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.45.1.tgz", - "integrity": "sha512-Y4VL/hqJMZZxwlUr5ZgM68CFu2iIeEkNLR1cY3+Ww68CIvWARDsoXFix7+31rmyC0+7L85ZI+Pq3E5JSG5+nLQ==", + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.46.0.tgz", + "integrity": "sha512-/8Qw+iisrUdOMk+p2mjEHouMm/BBdBEN1DHh16wiTpRUZkxDG3PxexdjCvR+wvK3LWPdrEvnQbdrwpU954sPhg==", "license": "MIT", "dependencies": { - "@grammyjs/types": "4.0.0", + "@grammyjs/types": "5.0.0", "abort-controller": "^3.0.0", "debug": "^4.4.3", "node-fetch": "^2.7.0" @@ -3743,14 +3743,14 @@ } }, "node_modules/openclaw": { - "version": "2026.8.1", - "resolved": "https://registry.npmjs.org/openclaw/-/openclaw-2026.8.1.tgz", - "integrity": "sha512-bSaFeaDFnQH/bU1vgKMac6eHkHHPHG0C/uwduXGI3eIS3lyiYSwmDU5ehhBUUhlPeV85tL5/KVwmoH48nX1tWw==", + "version": "2026.8.2", + "resolved": "https://registry.npmjs.org/openclaw/-/openclaw-2026.8.2.tgz", + "integrity": "sha512-I9aqK1attaONePpWs2gPqh23s1s1EDcN/6icF2AAfONdtowu4156QD7g6oD7KlA2vQ9yiqnvlAVH6yduvGH9Ig==", "hasInstallScript": true, "license": "MIT", "dependencies": { "@agentclientprotocol/sdk": "1.4.0", - "@anthropic-ai/claude-agent-sdk": "0.3.239", + "@anthropic-ai/claude-agent-sdk": "0.3.241", "@anthropic-ai/sdk": "0.120.0", "@clack/core": "1.4.3", "@clack/prompts": "1.7.0", @@ -3763,7 +3763,7 @@ "@mistralai/mistralai": "2.6.4", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "0.6.0", - "@openclaw/ai": "2026.8.1", + "@openclaw/ai": "2026.8.2", "@openclaw/fs-safe": "0.5.6", "@openclaw/proxyline": "0.3.7", "@silvia-odwyer/photon-node": "0.3.4", @@ -3780,7 +3780,7 @@ "execa": "10.0.1", "express": "5.2.1", "file-type": "22.0.2", - "grammy": "1.45.1", + "grammy": "1.46.0", "highlight.js": "11.12.0", "hosted-git-info": "10.1.1", "iconv-lite": "0.7.3", @@ -3807,11 +3807,11 @@ "tar": "7.5.22", "tree-sitter-bash": "0.25.1", "tslog": "4.11.0", - "typebox": "1.3.16", + "typebox": "1.3.17", "typescript": "6.0.3", "undici": "8.10.0", "web-push": "3.6.7", - "web-tree-sitter": "0.26.12", + "web-tree-sitter": "0.26.13", "ws": "8.21.3", "yaml": "2.9.0", "zod": "4.4.3" @@ -3848,9 +3848,9 @@ } }, "node_modules/openclaw/node_modules/typebox": { - "version": "1.3.16", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.16.tgz", - "integrity": "sha512-Jac8dgnin+g2p1w1v9sk92Wvp49ZqsmSgNhrXDK+RqrovsjiORMZvYZ8t8id9b9XQp6LMfaAwnIRSHGsM+3FMw==", + "version": "1.3.17", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.17.tgz", + "integrity": "sha512-20PsSaZV1pN7pIfM/YEUHZNTv8X21+1ilPo/HN+6GtFbhCaQhLrIoKCkAkcBwIva3nYI+Ao0MxM1iDj5H3SOhw==", "license": "MIT" }, "node_modules/openclaw/node_modules/typescript": { @@ -4840,9 +4840,9 @@ } }, "node_modules/typebox": { - "version": "1.3.24", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.24.tgz", - "integrity": "sha512-T7iofCTrR1NsT+lGTF56qU7Ai0kW4i9oQrQ9oa82WxGiAUs787Tpbh5vkPKBs/fzudP3T8qOryi5GXf2Qjy1+A==", + "version": "1.3.25", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.25.tgz", + "integrity": "sha512-glTozrjba2L9Mqqy9Y9joPmrXGTW7aINuBPl8tdZJJIUIXprRWT1EU8riXUHhPOXSk4K3pDKL6OV5CkpoOKcbw==", "license": "MIT" }, "node_modules/typescript": { @@ -4978,9 +4978,9 @@ } }, "node_modules/web-tree-sitter": { - "version": "0.26.12", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.12.tgz", - "integrity": "sha512-fvqTNZQBGUgUgfP0mHw+iHf9Yf6bRQrp0A3pSf2v/hSKxkT1beCoIWoLVmlPL7O6dmySfSb/t1aJoJvrgTRStw==", + "version": "0.26.13", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.13.tgz", + "integrity": "sha512-5bUZ7vbQ1kcondet96wzP974+JfCZDeQ7bTpacICm2nnvHpa5cO0ByRsoMcAhUP+743vpkb4m0BFlVSm+Ye9VA==", "license": "MIT" }, "node_modules/webidl-conversions": { diff --git a/alignfirst-developer-tests/package.json b/alignfirst-developer-tests/package.json index 2e77f84..ba5d92f 100644 --- a/alignfirst-developer-tests/package.json +++ b/alignfirst-developer-tests/package.json @@ -20,7 +20,7 @@ "@paleo/openclaw-discord-mock": "file:vendor/openclaw-discord-mock.tgz", "@paleo/openclaw-slack-mock": "file:vendor/openclaw-slack-mock.tgz", "@paleo/openclaw-test": "file:vendor/openclaw-test.tgz", - "openclaw": "2026.8.1" + "openclaw": "2026.8.2" }, "devDependencies": { "@types/node": "~24.13.3", diff --git a/docs/alignfirst-developer/openclaw-context-engineering.md b/docs/alignfirst-developer/openclaw-context-engineering.md index f6c2c71..d6e2e8f 100644 --- a/docs/alignfirst-developer/openclaw-context-engineering.md +++ b/docs/alignfirst-developer/openclaw-context-engineering.md @@ -12,7 +12,6 @@ These top-level files under `~/.openclaw/workspace/` are read on every turn and - `SOUL.md`, `IDENTITY.md`, `USER.md` — persona / context (optional) - `MEMORY.md` — curated long-term memory (optional) - `BOOTSTRAP.md` — first-run ritual (optional) -- `HEARTBEAT.md` — heartbeat checklist (optional, dynamic load) Loader: `loadWorkspaceBootstrapFiles()` in `src/agents/workspace.ts`. The bootstrap cache (`src/agents/bootstrap-cache.ts`) refreshes per turn keyed on inode/mtime, so live edits are picked up without restarting the gateway. This is why the harness can bind-mount the workspace and the playbook skill into the gateway and have playbook edits iterate without a rebuild. @@ -39,12 +38,18 @@ Defaults in `src/agents/bootstrap-budget.ts`: Over-budget files are truncated with a marker. Keep workspace files under these limits. -## Heartbeat sentinel: `NO_REPLY` +## Heartbeat: cron scratch and `NO_REPLY` -The workspace and alcode wake convention is `NO_REPLY`, OpenClaw's general silent-reply token. OpenClaw 2026.8.1 sends the configured heartbeat prompt verbatim as the scheduled user message and no longer adds a heartbeat-specific system-prompt section. The former `agents.defaults.heartbeat.includeSystemPromptSection` key is rejected. +The heartbeat checklist is the scratch of the system-owned `heartbeat:main` cron job (its declaration key; the listing shows it as `Heartbeat (main)`), a row in the shared SQLite store (`src/cron/heartbeat-monitor.ts`, `src/cron/scratch-store.ts`). The gateway creates the job at startup from `agents.defaults.heartbeat.every`; `openclaw cron scratch ` reads and writes the scratch. The runtime never reads a workspace `HEARTBEAT.md`; `openclaw doctor --fix` imports a leftover file into the scratch and deletes it (`src/commands/doctor-heartbeat-scratch-migration.ts`). A comment-only scratch makes the periodic tick skip its model call (`reason=empty-heartbeat-file`); a missing scratch runs the model. + +The workspace and alcode wake convention is `NO_REPLY`, OpenClaw's general silent-reply token. The stock heartbeat prompt (`src/auto-reply/heartbeat.ts`) follows the scratch and ends in `NO_REPLY`, and OpenClaw sends it verbatim as the scheduled user message, so neither the harness nor the deployment seed overrides `agents.defaults.heartbeat.prompt`. The former `agents.defaults.heartbeat.includeSystemPromptSection` key is rejected. OpenClaw still accepts the legacy `HEARTBEAT_OK` acknowledgment and suppresses token-only replies, including stray acknowledgments outside heartbeat turns. Keep new instructions on `NO_REPLY` so scheduled and event-driven wake paths share one convention. +## Background model runs disabled by the harness and the seed + +Three defaults schedule model turns without a user message: the memory-core dreaming sweep (daily, rewrites `MEMORY.md`), the weekly skill-collection review (`skills.workshop.autonomous.mode` defaults to `auto`) and the pre-compaction memory flush (`agents.defaults.compaction.memoryFlush`, writes `memory/YYYY-MM-DD.md`). `memory-core` owns the `memory` plugin slot and loads regardless of `plugins.allow`; `plugins.slots.memory: "none"` removes it along with the `memory_search`/`memory_get` tools. The harness config and the deployment seed set the same opt-outs, plus `update.checkOnStart: false` (the startup update check is also an anonymous version ping). + ## Practical implications - Keep top-level workspace files lean — every turn pays the token cost. diff --git a/docs/alignfirst-developer/upgrading-openclaw.md b/docs/alignfirst-developer/upgrading-openclaw.md index a1fbe1a..05acd07 100644 --- a/docs/alignfirst-developer/upgrading-openclaw.md +++ b/docs/alignfirst-developer/upgrading-openclaw.md @@ -31,6 +31,8 @@ git clone --quiet --depth=1 --branch v https://github.com/openclaw/open - Read the new release's section of the clone's `CHANGELOG.md` — top section only, the file is enormous. - Diff the surfaces our documentation describes: `git -C .local/openclaw diff v v --stat -- src/agents src/commands`, then the files behind any suspicious stat line. - Re-verify the claims of [openclaw-context-engineering.md](./openclaw-context-engineering.md) against the new tag; the document names its source files. Doctor does not flag silent behavior shifts (the 2026.8 subagent bootstrap narrowing, for example) — only this re-reading catches them. +- Compare the deployment template's workspace files (`skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/workspace/`) with `WORKSPACE_BOOTSTRAP_FILENAMES` in `src/agents/workspace.ts`. A file the runtime stopped reading must leave the template and its `chattr` lists; 2026.8.1 retired `HEARTBEAT.md` this way and the check above did not catch it. +- Diff the config help between the tags: `git -C .local/openclaw diff v v -- 'src/config/schema.help.*.ts'`. A default that turns on a background behavior (a scheduled model run, a memory feature, a telemetry ping) appears there and nowhere doctor looks; see [Propagate](#propagate-to-the-deployment-template). ## Bump the pins @@ -42,28 +44,44 @@ Then rebuild the harness image: `npm run env:build` in `alignfirst-developer-tes ## Run doctor in a throwaway container -Doctor is the upstream migration detector: it flags retired workspace files, retired config keys and pending state migrations. Run it against a scratch copy of the reference workspace — never the original, `--fix` rewrites files: +Doctor is the upstream migration detector: it flags retired workspace files, retired config keys and pending state migrations. Run it against scratch copies of both workspaces we ship, the harness reference and the deployment template (base files plus one surface's `AGENTS.md`) — never the originals, `--fix` rewrites files: ```sh cd alignfirst-developer-tests -cp -r workspace /tmp/doctor-workspace -docker run --rm -v /tmp/doctor-workspace:/home/claw/.openclaw/workspace \ - -e ANTHROPIC_API_KEY=x -e OPENROUTER_API_KEY=x -e ZAI_API_KEY=x \ - -e ALIGNFIRST_CODE_AGENT=claude \ - --entrypoint /usr/local/bin/openclaw \ - alignfirst-developer-tests-openclaw-test:latest doctor --json +template=../skills/alignfirst-setup-guide/assets/alignfirst-developer-template +cp -r workspace /tmp/doctor-harness +cp -r $template/base/infra/openclaw/workspace /tmp/doctor-template +cp $template/variants/surfaces/slack/infra/openclaw/workspace/AGENTS.md /tmp/doctor-template/ +for ws in /tmp/doctor-harness /tmp/doctor-template; do + docker run --rm -v $ws:/home/claw/.openclaw/workspace \ + -e ANTHROPIC_API_KEY=x -e OPENROUTER_API_KEY=x -e ZAI_API_KEY=x \ + -e ALIGNFIRST_CODE_AGENT=claude \ + --entrypoint /usr/local/bin/openclaw \ + alignfirst-developer-tests-openclaw-test:latest doctor --json +done ``` -Two findings are expected noise, because no gateway ever runs in this container: the heartbeat cron materialization warning (the gateway reconciles those jobs itself at startup — `reconcileHeartbeatMonitorJobs` in `src/gateway/server-cron.ts`) and the plaintext-secrets warning (the harness injects keys through the environment on purpose). Investigate anything else. +Three findings are expected noise, because no gateway ever runs in this container: the heartbeat cron materialization warning (the gateway reconciles those jobs itself at startup — `reconcileHeartbeatMonitorJobs` in `src/gateway/server-cron.ts`), the plaintext-secrets warning (the harness injects keys through the environment on purpose) and the node-hosting precondition about the loopback bind. Investigate anything else. -## Run the regression suite +## Inspect a running gateway + +`env:up` starts the worker gateways with the harness config. Ask one which jobs and plugins the release materialized on its own: ```sh npm run env:up +docker exec alignfirst-developer-tests-w1-gateway-1 openclaw cron list --all +docker exec alignfirst-developer-tests-w1-gateway-1 openclaw plugins list +``` + +Expected: `heartbeat:main` as the only enabled job (the skill-collection review may be listed as disabled), and no plugin outside `openclaw.json`. A new enabled job or an unlisted plugin is a default the release turned on; find its knob in the config help diff. + +## Run the regression suite + +```sh npm run e2e -- --channel all --all npm run env:down ``` ## Propagate to the deployment template -When the release retires a config key, the template's seed tolerates it (`set_json_tolerated` in `base/infra/openclaw/seed/common.sh`) — add an entry there. When it retires a workspace file or changes operator-visible behavior, update the setup-guide template docs and, for hardened installations, add a gotcha with the removal procedure (see "Legacy `TOOLS.md`" in the template's `gotchas.md`). +The seed targets the current release. When the release retires a config key the seed sets, delete or replace the line. When it retires a workspace file or changes operator-visible behavior, update the setup-guide template: it describes a fresh install on the current release, so retired files and keys leave it, and the consumers' own runbooks carry the migration. When it turns on a background behavior, add the opt-out to `base/infra/openclaw/seed/common.sh` and to `alignfirst-developer-tests/openclaw.json`, which carry the same opt-outs. Bump the `version` in the skill's `SKILL.md`. diff --git a/package-lock.json b/package-lock.json index c63511a..fef6d50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,23 +24,23 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.239.tgz", - "integrity": "sha512-cIuZhK4u76S5Otq78U890GSA6BFT4SLqOuMqzU/bP/tWRWKhHhNp/3/pvgLwoVGlkdhD7luXWduqXKyLC+VNBQ==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk/-/claude-agent-sdk-0.3.241.tgz", + "integrity": "sha512-pIHdCSTywFe30H0oWDCKZzC4ipBLtF5YMDRKjf6PHyARg57O4l/72v3b6QKnnefwtKKMe6uWJ1Y9lUJg/sKWyA==", "dev": true, "license": "SEE LICENSE IN README.md", "engines": { "node": ">=18.0.0" }, "optionalDependencies": { - "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.239", - "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.239", - "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.239" + "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.241", + "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.241", + "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.241" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", @@ -49,9 +49,9 @@ } }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.239.tgz", - "integrity": "sha512-GGVGuCwFEUm6cMlnBX0LTC9JX5NdGzxddbuqWtRxEgo9EetS70SO3FW+reitALlotHghPTfnICQILbBDIRyX+Q==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-arm64/-/claude-agent-sdk-darwin-arm64-0.3.241.tgz", + "integrity": "sha512-v26ta54lKFMFEZzbOE+6p3YhKERWnDiEA6OmkSAg+3fAQHOa1+aLTKw222cfgzxgiVixwFtHMk8c63zsDd8aXQ==", "cpu": [ "arm64" ], @@ -63,9 +63,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-darwin-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.239.tgz", - "integrity": "sha512-QNbBXz3Pb3pQ7a+Kcbets6t9IrQhStKsfl5D518nYiGFoRMioO7efkZ6zHUcrGDqDC0LIzrs7tY2KNzH4RfwZA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-darwin-x64/-/claude-agent-sdk-darwin-x64-0.3.241.tgz", + "integrity": "sha512-5jweT0vft1ZCaGSoxZHF9vJlHbx8Yxx4+x5aHAIXTd4lx7ZbT4o5buEF8kpmTeHUB+Fw9jtFIm4QDsRiBXgf+Q==", "cpu": [ "x64" ], @@ -77,9 +77,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.239.tgz", - "integrity": "sha512-RE6tDtzU0xj58tsuxnlXMJO8ckJ4tx/1nUgR+D/fPEQVt84oOyXeVspKt1ffvycogh3Sr3MkCGwZrPmxu/V1nA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64/-/claude-agent-sdk-linux-arm64-0.3.241.tgz", + "integrity": "sha512-SxszQGffXiLzMEnAv+pJXEmQbA8haijKyRjjH/jOt1CLeMIfpjKcO9WQDv8dEA8nREWS3zJ103zjgecAF7oOQQ==", "cpu": [ "arm64" ], @@ -94,9 +94,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-arm64-musl": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.239.tgz", - "integrity": "sha512-Ajc3cuszVdOwfMZVsGdxrCTmgWOeJpQWAIqu8jNEvERIeNnBxvWfGrjmLPxYT3/LJ9Uj/tFTpp52J4IcmrJE5w==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-arm64-musl/-/claude-agent-sdk-linux-arm64-musl-0.3.241.tgz", + "integrity": "sha512-GslvPvSzehfCZyzOaJAt4lgodznm5zpl/LMXN8ygD12z5qnpM+I9/eFnmAaISJ0L8/vyohtlAP1jjaeR2jz1AQ==", "cpu": [ "arm64" ], @@ -111,9 +111,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.239.tgz", - "integrity": "sha512-q4YaDoPgqh0XM23RM1/Zje7OSKccuCTQE89KoppDFOsyGdRsUj5xr01LTtr5hnYQuZD7dfwAbz9zl1g0MF/7TA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64/-/claude-agent-sdk-linux-x64-0.3.241.tgz", + "integrity": "sha512-gJRa922Qcm7loumHcXMDFEFg//tz1aOi7Nx0sQa9I9lC1JSN8yL6i7/idzOU5Hp193tEDFOgqIMFL/yRiXg+rw==", "cpu": [ "x64" ], @@ -128,9 +128,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-linux-x64-musl": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.239.tgz", - "integrity": "sha512-zIUHiG4Romm/t6m/S9n8x4BKluyRCPk0147hPVo4xxkHkp4Di/7TnDMRKO3Wau4x361wRqlE2i5EpYT+CyJjHg==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-linux-x64-musl/-/claude-agent-sdk-linux-x64-musl-0.3.241.tgz", + "integrity": "sha512-kZigJ5Ug2I2G/n7Cunmwy4TGr0lOGnWrz6TkzyWiDcUmJOodoTH6GZECNarWAtETfN03AAeLfrpiz8z3hOEDqA==", "cpu": [ "x64" ], @@ -145,9 +145,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-arm64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.239.tgz", - "integrity": "sha512-RxA29NdX9g3ZbpcXvSeWxpbg/Eoo3wXfO2eA1Vc7qa5JyAYjrl9xu6dIGAWMiyk/gnFxNh1WoFER77J9P6LTiQ==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-arm64/-/claude-agent-sdk-win32-arm64-0.3.241.tgz", + "integrity": "sha512-/3yA9jQuCvHDVlILzhtslH6kFYOvydXyMZiKwnzqM8ZfvFTNO41w8TpiFpBLseyM+4A4E8QMeTKu3L01Xyb5IQ==", "cpu": [ "arm64" ], @@ -159,9 +159,9 @@ ] }, "node_modules/@anthropic-ai/claude-agent-sdk-win32-x64": { - "version": "0.3.239", - "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.239.tgz", - "integrity": "sha512-ylKIX0DfaK1EgWYbVEvBMYATVFdKjFcWvvypTIv2sJhM3KxJT/0lTzvqsai8jYeZN1FBHWlRNEUQJvJMjO/diA==", + "version": "0.3.241", + "resolved": "https://registry.npmjs.org/@anthropic-ai/claude-agent-sdk-win32-x64/-/claude-agent-sdk-win32-x64-0.3.241.tgz", + "integrity": "sha512-cHYdAgORl9kynujMeYXyV1uj/hbmsBjRw9dRVkIW4/4sF7S6L4u/qDSzn1/wiNP7g2yWSJ4KbsvHDH2WWDnCBQ==", "cpu": [ "x64" ], @@ -715,9 +715,9 @@ } }, "node_modules/@grammyjs/types": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-4.0.0.tgz", - "integrity": "sha512-Z8lDLTvOlo12e5Vnly/vQh3JC9ppaitS1dGZ3w068gNitOd/y8tTSiib+Xm38aBGbtYGmUZwOc6afYrLs2CSTg==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@grammyjs/types/-/types-5.0.0.tgz", + "integrity": "sha512-iq1Qrq1iPKkB8yAa0qSuIURMZOCuqTY5pWy5gHpCeL1oQ+GPadGhw/cDTVE8waJwuCzacUzuIjRv1sESvk7u7A==", "dev": true, "license": "MIT" }, @@ -1241,9 +1241,9 @@ } }, "node_modules/@openclaw/ai": { - "version": "2026.8.1", - "resolved": "https://registry.npmjs.org/@openclaw/ai/-/ai-2026.8.1.tgz", - "integrity": "sha512-gUhfqsEZMRkgNZFegBMhKV5fw5OTziw+Pk2w0hOwOpNkT2W20VL2uS5Yz3ZbiC4snd5BQDBmmO33cVUgwr2aUg==", + "version": "2026.8.2", + "resolved": "https://registry.npmjs.org/@openclaw/ai/-/ai-2026.8.2.tgz", + "integrity": "sha512-Fx3f91YA7498buyxXQJoxITgkOZM0BHmSSroy0HLHeMLIod7qGWrNxarr41uhks1vDi15JLVueTZBEWtRV3KXQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1252,7 +1252,7 @@ "@mistralai/mistralai": "2.6.4", "openai": "7.5.0", "partial-json": "0.1.7", - "typebox": "1.3.16" + "typebox": "1.3.17" }, "engines": { "node": ">=22.19.0" @@ -3726,13 +3726,13 @@ } }, "node_modules/grammy": { - "version": "1.45.1", - "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.45.1.tgz", - "integrity": "sha512-Y4VL/hqJMZZxwlUr5ZgM68CFu2iIeEkNLR1cY3+Ww68CIvWARDsoXFix7+31rmyC0+7L85ZI+Pq3E5JSG5+nLQ==", + "version": "1.46.0", + "resolved": "https://registry.npmjs.org/grammy/-/grammy-1.46.0.tgz", + "integrity": "sha512-/8Qw+iisrUdOMk+p2mjEHouMm/BBdBEN1DHh16wiTpRUZkxDG3PxexdjCvR+wvK3LWPdrEvnQbdrwpU954sPhg==", "dev": true, "license": "MIT", "dependencies": { - "@grammyjs/types": "4.0.0", + "@grammyjs/types": "5.0.0", "abort-controller": "^3.0.0", "debug": "^4.4.3", "node-fetch": "^2.7.0" @@ -4953,15 +4953,15 @@ } }, "node_modules/openclaw": { - "version": "2026.8.1", - "resolved": "https://registry.npmjs.org/openclaw/-/openclaw-2026.8.1.tgz", - "integrity": "sha512-bSaFeaDFnQH/bU1vgKMac6eHkHHPHG0C/uwduXGI3eIS3lyiYSwmDU5ehhBUUhlPeV85tL5/KVwmoH48nX1tWw==", + "version": "2026.8.2", + "resolved": "https://registry.npmjs.org/openclaw/-/openclaw-2026.8.2.tgz", + "integrity": "sha512-I9aqK1attaONePpWs2gPqh23s1s1EDcN/6icF2AAfONdtowu4156QD7g6oD7KlA2vQ9yiqnvlAVH6yduvGH9Ig==", "dev": true, "hasInstallScript": true, "license": "MIT", "dependencies": { "@agentclientprotocol/sdk": "1.4.0", - "@anthropic-ai/claude-agent-sdk": "0.3.239", + "@anthropic-ai/claude-agent-sdk": "0.3.241", "@anthropic-ai/sdk": "0.120.0", "@clack/core": "1.4.3", "@clack/prompts": "1.7.0", @@ -4974,7 +4974,7 @@ "@mistralai/mistralai": "2.6.4", "@modelcontextprotocol/sdk": "1.30.0", "@mozilla/readability": "0.6.0", - "@openclaw/ai": "2026.8.1", + "@openclaw/ai": "2026.8.2", "@openclaw/fs-safe": "0.5.6", "@openclaw/proxyline": "0.3.7", "@silvia-odwyer/photon-node": "0.3.4", @@ -4991,7 +4991,7 @@ "execa": "10.0.1", "express": "5.2.1", "file-type": "22.0.2", - "grammy": "1.45.1", + "grammy": "1.46.0", "highlight.js": "11.12.0", "hosted-git-info": "10.1.1", "iconv-lite": "0.7.3", @@ -5018,11 +5018,11 @@ "tar": "7.5.22", "tree-sitter-bash": "0.25.1", "tslog": "4.11.0", - "typebox": "1.3.16", + "typebox": "1.3.17", "typescript": "6.0.3", "undici": "8.10.0", "web-push": "3.6.7", - "web-tree-sitter": "0.26.12", + "web-tree-sitter": "0.26.13", "ws": "8.21.3", "yaml": "2.9.0", "zod": "4.4.3" @@ -6771,9 +6771,9 @@ } }, "node_modules/typebox": { - "version": "1.3.16", - "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.16.tgz", - "integrity": "sha512-Jac8dgnin+g2p1w1v9sk92Wvp49ZqsmSgNhrXDK+RqrovsjiORMZvYZ8t8id9b9XQp6LMfaAwnIRSHGsM+3FMw==", + "version": "1.3.17", + "resolved": "https://registry.npmjs.org/typebox/-/typebox-1.3.17.tgz", + "integrity": "sha512-20PsSaZV1pN7pIfM/YEUHZNTv8X21+1ilPo/HN+6GtFbhCaQhLrIoKCkAkcBwIva3nYI+Ao0MxM1iDj5H3SOhw==", "dev": true, "license": "MIT" }, @@ -7068,9 +7068,9 @@ } }, "node_modules/web-tree-sitter": { - "version": "0.26.12", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.12.tgz", - "integrity": "sha512-fvqTNZQBGUgUgfP0mHw+iHf9Yf6bRQrp0A3pSf2v/hSKxkT1beCoIWoLVmlPL7O6dmySfSb/t1aJoJvrgTRStw==", + "version": "0.26.13", + "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.26.13.tgz", + "integrity": "sha512-5bUZ7vbQ1kcondet96wzP974+JfCZDeQ7bTpacICm2nnvHpa5cO0ByRsoMcAhUP+743vpkb4m0BFlVSm+Ye9VA==", "dev": true, "license": "MIT" }, @@ -7290,7 +7290,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11", @@ -7319,7 +7319,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" @@ -7340,7 +7340,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" @@ -7367,7 +7367,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" diff --git a/packages/openclaw-channel-mock-core/package.json b/packages/openclaw-channel-mock-core/package.json index bf62977..ec46607 100644 --- a/packages/openclaw-channel-mock-core/package.json +++ b/packages/openclaw-channel-mock-core/package.json @@ -46,7 +46,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11", diff --git a/packages/openclaw-discord-mock/package.json b/packages/openclaw-discord-mock/package.json index be2741e..c715214 100644 --- a/packages/openclaw-discord-mock/package.json +++ b/packages/openclaw-discord-mock/package.json @@ -68,7 +68,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" diff --git a/packages/openclaw-slack-mock/package.json b/packages/openclaw-slack-mock/package.json index c9884c7..18e2159 100644 --- a/packages/openclaw-slack-mock/package.json +++ b/packages/openclaw-slack-mock/package.json @@ -68,7 +68,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" diff --git a/packages/openclaw-test/package.json b/packages/openclaw-test/package.json index 46413b3..06384ce 100644 --- a/packages/openclaw-test/package.json +++ b/packages/openclaw-test/package.json @@ -56,7 +56,7 @@ }, "devDependencies": { "@types/node": "~24.13.3", - "openclaw": "~2026.8.1", + "openclaw": "~2026.8.2", "rimraf": "~6.1.3", "typescript": "~7.0.2", "vitest": "~4.1.11" diff --git a/skills/alignfirst-setup-guide/SKILL.md b/skills/alignfirst-setup-guide/SKILL.md index 6dc8944..83bca00 100644 --- a/skills/alignfirst-setup-guide/SKILL.md +++ b/skills/alignfirst-setup-guide/SKILL.md @@ -7,7 +7,7 @@ compatibility: Requires git and a Node.js package manager (npm, pnpm, yarn, or b license: CC0 1.0 metadata: author: Paleo - version: "0.30.2" + version: "0.31.0" repository: https://github.com/paleo/alignfirst --- diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/configuration.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/configuration.md index 54f4f94..c5cfb2f 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/configuration.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/configuration.md @@ -12,11 +12,12 @@ The seed is the record of the OpenClaw configuration. No copy of `openclaw.json` ## Sources - `infra/openclaw/.env` — every deployment value and secret the seed reads (gitignored; `.env.example` documents each variable). -- `infra/openclaw/seed/common.sh` — the baseline: model, heartbeat, skill allowlist, tools, thread sessions, identity, gateway, plugin allowlist. Also the helpers every module calls. +- `infra/openclaw/seed/common.sh` — the baseline: model, memory opt-outs, heartbeat, skill allowlist, tools, updates, thread sessions, identity, gateway, plugin allowlist. Also the helpers every module calls. - `infra/openclaw/seed/surface.sh` — the channel plugin, its credentials as SecretRefs, the allowlisted channel. - `infra/openclaw/seed/coding-agent.sh` — the delegated coding agent's global instructions (merged into its instruction file). - `infra/openclaw/environment.d/` — non-secret variables for the gateway and login shells (`common.conf`, `coding-agent.conf`; `runtime.conf` is generated). - `infra/openclaw/workspace/` — the workspace files, applied by `apply-workspace.sh`. +- `infra/openclaw/heartbeat-scratch.md` — the heartbeat job's checklist, pushed by `apply-heartbeat-scratch.sh` ([04 § 7](installations/04-openclaw.md#heartbeat-scratch)). - `infra/openclaw/alproject/` — `.alproject.json` (project parent, port range) and the guide appended to `alproject --guide`. ## Module contract diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/gotchas.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/gotchas.md index 62a6e87..84a2d35 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/gotchas.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/gotchas.md @@ -10,7 +10,7 @@ Behaviors that look like bugs and are intentional, with the reason. Read the rel ## No version manager in the service account's PATH -OpenClaw is installed under one prefix (`~/.npm-system-global/`, fed by `/usr/bin/npm`). A version manager shifts the active prefix: `which openclaw` returns nothing, and `openclaw update` installs the new version into the manager's prefix while the gateway unit keeps running the old one. `openclaw doctor` also flags version-manager Nodes as fragile runtimes. `openclaw update` is the upgrade path because it refreshes the plugins in lockstep with the core; it stays safe only with exactly one `npm` on `PATH`. A project that needs another Node runs it in a container. +OpenClaw is installed under one prefix (`~/.npm-system-global/`, fed by `/usr/bin/npm`). A version manager shifts the active prefix: `which openclaw` returns nothing, and `openclaw update` installs the new version into the manager's prefix while the gateway unit keeps running the old one. `openclaw doctor` also flags version-manager Nodes as fragile runtimes. `openclaw update` is the upgrade path because it refreshes the plugins in lockstep with the core; it stays safe only with exactly one `npm` on `PATH`. A pinned `npm install -g openclaw@` skips that lockstep: an external plugin built for the previous core fails to load on the new one, and each needs `openclaw plugins install npm:@openclaw/@ --accept-capabilities`. A project that needs another Node runs it in a container. ## Containers are per-user @@ -39,19 +39,21 @@ coding agent: `skills remove` would delete the canonical copy for both. `@paleo/workspace` stores each worktree as an absolute path in `.local-wt/workspace-registry/workspaces.json`. After a `mv`, every command fails with `The workspace name "" is already taken by `, and no command repairs it: `prune` skips main worktrees, `remove` is destructive. Rewrite the `worktree` string in place, keeping the name key, `createdAt`, `status` and `portIndex` (`portIndex` pins the linked worktrees' ports). `git worktree repair` is still needed for linked worktrees. `alproject` is unaffected: it reads git worktrees directly. -## Legacy `TOOLS.md` +## Heartbeat cost is a main-session problem -Tool notes live in the `## Environment` section of the workspace `AGENTS.md`. OpenClaw 2026.8+ neither loads nor recreates `TOOLS.md`, and the seed no longer ships it. Installations hardened before its retirement still carry a zero-byte, immutable live copy that `openclaw doctor` warns about and `--fix` cannot delete (`chattr +i` blocks the unlink). Remove it through a maintenance window: +A bill that climbs day after day with near-zero output (the agent waking, finding nothing) is the heartbeat re-sending an ever-growing main-session transcript; `session.threadBindings` and `resetByType.thread` govern threads only. The slope scales with the tick frequency: it appeared under 30-minute ticks. The seed sets `every: "24h"` and keeps the heartbeat on, because the `alcode` completion wake is a heartbeat-sourced turn; `isolatedSession` and `lightContext` would each break that wake. A comment-only scratch on the `heartbeat:main` job skips the model call on periodic ticks entirely. When the cost appears despite it, run `apply-heartbeat-scratch.sh` ([04 § 7](installations/04-openclaw.md#heartbeat-scratch)): it restores the snapshot when the agent has rewritten the scratch ([06](installations/06-security-hardening.md#configuration-and-workspace-files)). -```sh -sudo /usr/local/sbin/alignfirst-developer-maintenance workspace -- \ - rm /home/{{SERVICE_USER}}/.openclaw/workspace/TOOLS.md -sudo -i -u {{SERVICE_USER}} -- systemctl --user start openclaw-gateway -``` +## OpenClaw schedules background model runs on its own -## Heartbeat cost is a main-session problem +Three defaults spend tokens without a user message: the memory-core *dreaming* sweep (a daily 03:00 isolated turn that rewrites `MEMORY.md`), the weekly *skill collection review* (`skills.workshop.autonomous.mode` defaults to `auto`, which also lets the agent rewrite writable skills), and the pre-compaction *memory flush* (an agentic turn that writes `memory/YYYY-MM-DD.md` when a long session nears its token limit). The seed turns each off: `plugins.slots.memory none`, `skills.workshop.autonomous.mode off`, `agents.defaults.compaction.memoryFlush.enabled false`. After an upgrade, `openclaw cron list --all` must list `heartbeat:main` as the only enabled system-owned job ([update-developer.md](operations/update-developer.md#smoke-test)); a new one is a default the release turned on, to opt out of in `seed/common.sh`. A dated note under `workspace/memory/` means the flush is back on. -A bill that climbs day after day with near-zero output (the agent waking, finding nothing) is the heartbeat re-sending an ever-growing main-session transcript; `session.threadBindings` and `resetByType.thread` govern threads only. The slope scales with the tick frequency: it appeared under 30-minute ticks. The seed sets `every: "24h"` and keeps the heartbeat on, because the `alcode` completion wake is a heartbeat-sourced turn; `isolatedSession` and `lightContext` would each break that wake. A comment-only `HEARTBEAT.md` skips the model call on periodic ticks entirely — check that the live file is genuinely comment-only (ATX headers and blank lines) when the cost appears despite it. +## `plugins.allow` does not govern slot plugins + +`memory-core` is the default owner of the `memory` slot and loads whatever `plugins.allow` says; `plugins.slots.memory` is the switch. A leftover `plugins.entries.memory-core` block then warns *plugin disabled but config is present* and makes doctor propose an auto-enable: unset the block, do not tune it. + +## `gateway install` refuses group-writable systemd paths + +The installer inspects `~/.config`, `~/.config/systemd`, `~/.config/systemd/user`, the unit file, its `.bak` and its `.d/` directory, and aborts with `[unsafe-permissions]` when any is `g+w`, which the account's default umask (`0002`) produces. Run `chmod go-w` on the paths it names, without `-R`; it names one path per run. ## `sudo -i -u … bash -lc '…'` expands the string twice @@ -62,7 +64,9 @@ sudo -i -u {{SERVICE_USER}} -- bash -lc 'z=hello; printf "[%s]" "$z"' # prints sudo -H -u {{SERVICE_USER}} bash -lc 'z=hello; printf "[%s]" "$z"' # prints [hello] ``` -`sudo -i -u {{SERVICE_USER}} -- ` is fine for a command that defines no variable. Anything with an assignment or a loop uses `sudo -H -u {{SERVICE_USER}} bash -lc '…'`. +The re-escaping also mangles a `\`+newline inside the quoted script: it comes out as an escaped space, so the next `~/path` becomes `~/ path` and the files land in a directory named `~/ `. Keep a `bash -lc` script on one line, or feed a multi-line script on stdin: `sudo -H -u {{SERVICE_USER}} bash <<'EOF' … EOF`. + +`sudo -i -u {{SERVICE_USER}} -- ` is fine for a one-line command that defines no variable. Anything with an assignment or a loop uses `sudo -H -u {{SERVICE_USER}} bash -lc '…'`. ## apt without a TTY dies in a debconf dialog @@ -82,7 +86,7 @@ Two outbound paths deliver a local file with different read policies. The `MEDIA ## Prefer interactive `openclaw doctor` over `--fix` -`--fix` applies every recommendation without review. Plain `openclaw doctor` prompts before each change, so a recommendation that contradicts the seed can be declined. The one `--fix` is on first install ([04 § 3](installations/04-openclaw.md#3-seed)), to create the credential scaffolding. +`--fix` applies every recommendation without review. Plain `openclaw doctor` prompts before each change, so a recommendation that contradicts the seed can be declined; without a TTY it only reports. Two exceptions use `--fix`: the first install ([04 § 3](installations/04-openclaw.md#3-seed)), to create the credential scaffolding, and the migration after a core bump ([update-developer.md](operations/update-developer.md#migrate-after-a-core-bump)), because a release's state migrations apply in repair mode only, TTY or not. ## Gateway URLs answer curl with a redirect diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/04-openclaw.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/04-openclaw.md index d9456ee..04620b2 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/04-openclaw.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/04-openclaw.md @@ -20,6 +20,7 @@ infra/openclaw/ ├── bin/ # workspace, backup, kill-switch and maintenance scripts ├── alproject/ # .alproject.json and alproject-guide.md ├── workspace/ # curated workspace files (AGENTS.md, IDENTITY.md, …) +├── heartbeat-scratch.md # the heartbeat job's comment-only checklist (step 7) └── coding-agent/ # global instruction file of the delegated coding agent ``` @@ -58,7 +59,7 @@ The execute bits are tracked by git; no `chmod` is needed. ## 3. Seed -`seed.sh` runs `openclaw setup` when `openclaw.json` is missing, so the configuration starts from the installed version's defaults, then applies every customization through `openclaw config set`, which validates each key and survives schema migrations. It derives `~/.openclaw/secrets/secrets.json` (0600) from `.env`, registers a file SecretRef provider and writes every credential into `openclaw.json` as a reference to it. It writes `CONTEXT7_API_KEY` alone into `~/.openclaw/.env`, the gateway env file inherited by exec children. It installs `environment.d/*.conf` into `~/.config/environment.d/` and generates `runtime.conf` there with `DOCKER_HOST`. `openclaw secrets audit --check` then fails the seed on any residual plaintext or unresolved reference, before `openclaw config validate` and an interactive `openclaw doctor`. +`seed.sh` runs `openclaw setup` when `openclaw.json` is missing, so the configuration starts from the installed version's defaults, then applies every customization through `openclaw config set`, which validates each key and survives schema migrations. It derives `~/.openclaw/secrets/secrets.json` (0600) from `.env`, registers a file SecretRef provider and writes every credential into `openclaw.json` as a reference to it. It writes `CONTEXT7_API_KEY` alone into `~/.openclaw/.env`, the gateway env file inherited by exec children. It installs `environment.d/*.conf` into `~/.config/environment.d/` and generates `runtime.conf` there with `DOCKER_HOST`. `openclaw secrets audit` then fails the seed on any plaintext, unresolved or shadowed reference, or store residue (a provider OAuth login shows as an informational legacy-residue finding and passes), before `openclaw config validate` and an interactive `openclaw doctor`. The provider and model are deployment choices. The seed always pins `models.providers.{{RUNTIME_PROVIDER}}.agentRuntime.id` to `openclaw`. The embedded runtime owns the @@ -82,18 +83,15 @@ Later runs use plain `openclaw doctor` — see [gotchas.md](../gotchas.md). ## 4. Provider plugin -A model provider served by an OpenClaw plugin needs two more keys in `seed/common.sh`, next to `plugins.allow`, then the package installed once: +A model provider served by an OpenClaw plugin needs three more lines in `seed/common.sh`, next to `plugins.allow`: ```sh -set_json "plugins.entries..enabled" true +install_plugin_once set_json plugins.allow "[\"$surface_plugin_id\",\"$RUNTIME_PROVIDER\",\"browser\",\"\"]" +openclaw plugins enable "" --accept-capabilities ``` -```sh -sudo -i -u {{SERVICE_USER}} -- openclaw plugins install -``` - -Enabling does not install: a missing package shows in `openclaw config validate` as `plugin not installed: `. Skip this step for a provider that OpenClaw serves natively. +`install_plugin_once` installs the package when no copy is present. `plugins enable` writes `plugins.entries..enabled` and records consent to the plugin's declared capabilities; a run without a TTY stops at the consent prompt otherwise. Consent is recorded per plugin version, so the seed re-records it on every run, as the surface module does for the channel plugin. Skip this step for a provider that OpenClaw serves natively. An installed agent-harness plugin cannot claim this deployment's turns because the explicit `openclaw` runtime pin is authoritative. A provider plugin may still supply model transport, @@ -142,20 +140,34 @@ loginctl show-user {{SERVICE_USER}} | grep Linger `openclaw gateway install` writes the user unit: `ExecStart` points at the installed `dist/index.js`, and the current `PATH` is baked in as `Environment=PATH=`. With the `.bash_profile` of `03`, that is `/usr/bin:…:~/.npm-system-global/bin`, which is what lets exec children find `alcode` and the coding agent. +The installer refuses group-writable unit paths, and the account's default umask creates them that way ([gotchas.md](../gotchas.md#gateway-install-refuses-group-writable-systemd-paths)). Strip the bit first: + ```sh +sudo -H -u {{SERVICE_USER}} bash -lc 'mkdir -p ~/.config/systemd/user && chmod go-w ~/.config ~/.config/systemd ~/.config/systemd/user' sudo -i -u {{SERVICE_USER}} -- openclaw gateway install sudo -i -u {{SERVICE_USER}} -- systemctl --user enable --now openclaw-gateway.service sudo -i -u {{SERVICE_USER}} -- systemctl --user status openclaw-gateway.service ``` -After an OpenClaw upgrade, refresh the unit (version stamp, settings) with `--force`: +After an OpenClaw upgrade, refresh the unit (settings, node flags) with `--force`; the permission check now includes the unit file: ```sh +sudo -H -u {{SERVICE_USER}} bash -lc 'chmod go-w ~/.config ~/.config/systemd ~/.config/systemd/user ~/.config/systemd/user/openclaw-gateway.service' sudo -i -u {{SERVICE_USER}} -- openclaw gateway install --force sudo -i -u {{SERVICE_USER}} -- systemctl --user daemon-reload sudo -i -u {{SERVICE_USER}} -- systemctl --user restart openclaw-gateway ``` +### Heartbeat scratch + +The heartbeat checklist is the scratch of the system-owned `heartbeat:main` cron job, which the gateway creates at its first start from `agents.defaults.heartbeat.every`. `apply-heartbeat-scratch.sh` pushes the comment-only text from the snapshot when the live scratch differs from it: + +```sh +sudo -i -u {{SERVICE_USER}} -- /home/{{SERVICE_USER}}/seed/bin/apply-heartbeat-scratch.sh +``` + +A comment-only scratch makes the daily tick skip its model call ([gotchas.md](../gotchas.md#heartbeat-cost-is-a-main-session-problem)). The scratch carries no immutable flag; `06` records the accepted gap. + ## 8. Podman socket `DOCKER_HOST` is already in `~/.config/environment.d/runtime.conf`; the socket it names comes from the user manager (lingering keeps it across reboots): diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/06-security-hardening.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/06-security-hardening.md index e3440c3..c70871e 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/06-security-hardening.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/installations/06-security-hardening.md @@ -36,17 +36,19 @@ sudo /usr/local/sbin/alignfirst-developer-kill ## Configuration and workspace files -The workspace was applied during `04`. If it has changed since then, run [update-workspace.md](../operations/update-workspace.md), then rerun the kill switch before continuing. `HEARTBEAT.md` is comment-only, and locked all the same — see [gotchas.md](../gotchas.md). +The workspace was applied during `04`. If it has changed since then, run [update-workspace.md](../operations/update-workspace.md), then rerun the kill switch before continuing. ```sh sudo chown {{SERVICE_USER}}:{{SERVICE_USER}} /home/{{SERVICE_USER}}/.openclaw/openclaw.json \ - /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER,HEARTBEAT}.md + /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER}.md sudo chmod 600 /home/{{SERVICE_USER}}/.openclaw/openclaw.json -sudo chmod 644 /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER,HEARTBEAT}.md +sudo chmod 644 /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER}.md sudo chattr +i /home/{{SERVICE_USER}}/.openclaw/openclaw.json \ - /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER,HEARTBEAT}.md + /home/{{SERVICE_USER}}/.openclaw/workspace/{AGENTS,IDENTITY,SOUL,USER}.md ``` +Accepted gap: the heartbeat checklist is the `heartbeat:main` cron job's scratch, a SQLite row ([04 § 7](04-openclaw.md#heartbeat-scratch)). No flag protects it; the agent can rewrite it through `heartbeat_respond` or `openclaw cron scratch --set`. It joins the agent-written state the policy tolerates (memory, sessions), its reach is the daily tick, and [update-developer.md](../operations/update-developer.md#smoke-test) restores it. + The alproject configuration and guide are repository-managed; the registry stays service-owned and writable: ```sh diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/recover-developer.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/recover-developer.md index 603fa83..c3a6d47 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/recover-developer.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/recover-developer.md @@ -54,6 +54,8 @@ sudo /usr/local/sbin/alignfirst-developer-maintenance config -- install -m 600 \ /home/{{SERVICE_USER}}/.openclaw/openclaw.json ``` +The archive `*-openclaw-backup.tar.gz` holds the SQLite state (sessions, cron jobs and their scratch, plugin consent, device pairing) and the auth profiles. Unpack it with `openclaw backup restore --target `, then copy the needed files under `~/.openclaw/` through the `config` maintenance scope, gateway stopped. + Restoring the configuration rarely beats re-seeding: the seed rebuilds `openclaw.json`, `secrets.json`, `~/.openclaw/.env` and `environment.d/` from the repository and `.env`. Prefer the backup for the workspace files and the registry, which the seed does not write. ## Re-seed and validate diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-developer.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-developer.md index 702ea3a..818141f 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-developer.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-developer.md @@ -22,20 +22,30 @@ sudo install -m 755 -o root -g root infra/openclaw/bin/developer-maintenance.sh /usr/local/sbin/alignfirst-developer-maintenance ``` +## Back up + +Before a core bump, keep the state the migrations will rewrite: configuration, SQLite stores, workspace files ([recover-developer.md](recover-developer.md#restore)): + +```sh +sudo -i -u {{SERVICE_USER}} -- /home/{{SERVICE_USER}}/seed/bin/backup.sh +``` + ## npm packages -The prefix is root-owned and immutable ([06](../installations/06-security-hardening.md)). The maintenance wrapper gives the service account this scope for the command, then restores root ownership, modes and the immutable flag through an `EXIT` trap. `openclaw update` is channel-aware and refreshes its plugins; the other packages ride `@latest`. +The prefix is root-owned and immutable ([06](../installations/06-security-hardening.md)). The maintenance wrapper gives the service account this scope for the command, then restores root ownership, modes and the immutable flag through an `EXIT` trap. `openclaw update` is channel-aware and refreshes its plugins at the core's version; the other packages ride `@latest`. ```sh sudo /usr/local/sbin/alignfirst-developer-maintenance packages -- bash -lc ' -openclaw update --yes --no-restart +openclaw update --yes --no-restart --accept-capabilities /usr/bin/npm install -g @paleo/alproject@latest @paleo/alcode@latest ctx7@latest ' ``` +`--accept-capabilities` accepts the plugins' reviewed capability changes. Without it the post-update plugin sync stops with an unresolved review, which `openclaw update repair --accept-capabilities` finishes. + Update the coding agent through its package-scoped command: [08-coding-agent.md § Update](../installations/08-coding-agent.md#update). -`openclaw update` exits 1 when its post-install doctor attempts a config write, which the immutable `openclaw.json` blocks (`ENOTDIR: not a directory, scandir '…/openclaw.json'`). Exit 0 means no write was attempted. Either way the package update succeeded; the verify step is what counts. +`openclaw update` exits 1 when its post-install doctor attempts a config write, which the immutable `openclaw.json` blocks (`ENOTDIR: not a directory, scandir '…/openclaw.json'`). Exit 0 means no write was attempted. Either way the package update succeeded; the verify step is what counts, and the migration step below finishes what the lock interrupted. Verify — the listing must show exactly five packages (`openclaw`, the coding agent, `@paleo/alproject`, `@paleo/alcode`, `ctx7`); anything else is a stray from a mistyped install, to remove through another `packages` maintenance window: @@ -83,11 +93,27 @@ alproject list Workspace files follow [update-workspace.md](update-workspace.md). +## Migrate after a core bump + +A release can ship state migrations that only doctor's repair mode applies, with or without a TTY. `openclaw update repair` runs that repair, syncs the plugins at the core's version and refreshes the plugin registry; it needs the configuration and the workspace writable: + +```sh +sudo /usr/local/sbin/alignfirst-developer-maintenance config workspace -- \ + openclaw update repair --yes --accept-capabilities +``` + +Read its output: every imported or removed file is a change to port into the repository. + +## Re-seed after a core bump + +A new OpenClaw release can retire keys the seed sets, turn on new defaults and widen the channel plugin's declared capabilities. Re-seed through [configure-developer.md](configure-developer.md): `config set` under the new binary rewrites the config in the current schema, and the surface module re-records the plugin consent. A `config set` that fails names a retired key; the trailing interactive `openclaw doctor` shows the new defaults. Port both into the seed modules before starting the gateway. + ## Gateway unit and restart -After an OpenClaw version bump, doctor may report a unit installed by an older version. `ExecStart` already points at the updated code. Refresh the stamp, then start the contained gateway: +After an OpenClaw version bump, doctor may report a unit installed by an older version. `ExecStart` already points at the updated code. Refresh the unit, then start the contained gateway. The installer refuses group-writable paths ([gotchas.md](../gotchas.md#gateway-install-refuses-group-writable-systemd-paths)), hence the `chmod`: ```sh +sudo -H -u {{SERVICE_USER}} bash -lc 'chmod go-w ~/.config ~/.config/systemd ~/.config/systemd/user ~/.config/systemd/user/openclaw-gateway.service' sudo /usr/local/sbin/alignfirst-developer-maintenance config -- \ openclaw gateway install --force sudo -i -u {{SERVICE_USER}} -- systemctl --user daemon-reload @@ -100,6 +126,10 @@ sudo -i -u {{SERVICE_USER}} -- systemctl --user start openclaw-gateway ```sh sudo -i -u {{SERVICE_USER}} -- openclaw doctor --non-interactive +sudo -i -u {{SERVICE_USER}} -- openclaw cron list --all +sudo -i -u {{SERVICE_USER}} -- /home/{{SERVICE_USER}}/seed/bin/apply-heartbeat-scratch.sh ``` -Config-schema warnings here mean the update shipped a migration that the immutable `openclaw.json` blocked. Re-run the seed flow of [configure-developer.md](configure-developer.md): `config set` under the new binary rewrites the config in the current schema. When warnings persist on keys the seed does not set, run interactive `openclaw doctor` through another `config` maintenance window and port the accepted changes into the seed modules. +Config-schema warnings here mean a migration that the seed has not ported yet: back to the re-seed step. A repair doctor still proposes after the gateway ran (an orphaned session binding, for instance) needs one more migration window. The job list must show `heartbeat:main` as the only enabled system-owned job; another one is a default the release turned on, to opt out of in `seed/common.sh` ([gotchas.md](../gotchas.md#openclaw-schedules-background-model-runs-on-its-own)). `apply-heartbeat-scratch.sh` reports the scratch unchanged, or pushes `infra/openclaw/heartbeat-scratch.md` back when the release or the agent rewrote it ([04 § 7](../installations/04-openclaw.md#heartbeat-scratch)). + +Once the release has run for a while, `openclaw update cleanup --dry-run` (gateway stopped) previews the retirement of the archived pre-migration files; run it without `--dry-run` to reclaim the space. diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-workspace.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-workspace.md index 5df7568..7f5776f 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-workspace.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/operations/update-workspace.md @@ -11,8 +11,6 @@ read_when: Layout: repository → `~/seed/workspace/` (snapshot) → `~/.openclaw/workspace/` (live). Backups under `~/backups/workspace-backups//`. -`HEARTBEAT.md` is comment-only on purpose — [heartbeat](../gotchas.md#heartbeat-cost-is-a-main-session-problem). Keep it that way. - ## Procedure Diff the repository against the live files. The live files are locked, so the diff shows the edit being pushed and nothing else; anything else is drift worth a question to the user. diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/troubleshooting.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/troubleshooting.md index 86737e7..cd5ca08 100644 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/troubleshooting.md +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/docs/troubleshooting.md @@ -14,10 +14,10 @@ read_when: sudo -i -u {{SERVICE_USER}} -- systemctl --user status openclaw-gateway sudo -i -u {{SERVICE_USER}} -- journalctl --user -u openclaw-gateway --since today --no-pager sudo -i -u {{SERVICE_USER}} -- openclaw config validate -sudo -i -u {{SERVICE_USER}} -- openclaw secrets audit --check +sudo -i -u {{SERVICE_USER}} -- openclaw secrets audit ``` -Run `secrets audit` from a login shell, as above: the file provider resolves from `secrets.json`, and a shell without `~/.bash_profile` lacks the environment the gateway has. Look at the first failing event, not the last restart. +Run `secrets audit` from a login shell, as above: the file provider resolves from `secrets.json`, and a shell without `~/.bash_profile` lacks the environment the gateway has. A provider OAuth login appears as an informational legacy-residue finding; any other finding is a defect. Look at the first failing event, not the last restart. ## Project routing diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/apply-heartbeat-scratch.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/apply-heartbeat-scratch.sh new file mode 100755 index 0000000..52f500c --- /dev/null +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/apply-heartbeat-scratch.sh @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +# +# Pushes the heartbeat checklist from the seed snapshot (infra/openclaw/heartbeat-scratch.md) into +# the scratch of the system-owned `heartbeat:main` cron job when the two differ. Idempotent: an +# unchanged scratch is left alone. Needs the gateway running: cron commands go through it. +# +# Run as the service account: +# sudo -i -u {{SERVICE_USER}} -- /home/{{SERVICE_USER}}/seed/bin/apply-heartbeat-scratch.sh + +set -euo pipefail + +SOURCE_FILE="$HOME/seed/heartbeat-scratch.md" +JOB_ID= +CURRENT_REVISION= +CURRENT_CONTENT= + +main() { + check_preconditions + find_heartbeat_job + read_current_scratch + if [ "$CURRENT_CONTENT" = "$(cat "$SOURCE_FILE")" ]; then + echo "[apply-heartbeat-scratch] unchanged (job $JOB_ID, revision $CURRENT_REVISION)" + return + fi + push_scratch +} + +check_preconditions() { + if [ "$(id -un)" != "{{SERVICE_USER}}" ]; then + echo "Run as {{SERVICE_USER}}: sudo -i -u {{SERVICE_USER}} -- ~/seed/bin/apply-heartbeat-scratch.sh" >&2 + exit 1 + fi + if [ ! -f "$SOURCE_FILE" ]; then + echo "No heartbeat scratch at $SOURCE_FILE — refresh the seed snapshot first." >&2 + exit 1 + fi +} + +# The gateway derives the job from agents.defaults.heartbeat.every at its first start; its id is +# stable across restarts, its declaration key identifies it in the listing. +find_heartbeat_job() { + JOB_ID=$(openclaw cron list --all --json | node -e ' + const listing = JSON.parse(require("node:fs").readFileSync(0, "utf8")); + const jobs = Array.isArray(listing) ? listing : listing.jobs; + const job = jobs.find((entry) => entry.declarationKey === "heartbeat:main"); + if (!job) { + console.error("[apply-heartbeat-scratch] no heartbeat:main job; has the gateway started once?"); + process.exit(1); + } + console.log(job.id); + ') +} + +# One read gives the content to compare and the revision the push is conditioned on, so a scratch +# rewritten between the read and the push is reported instead of overwritten. +read_current_scratch() { + local result + result=$(openclaw cron scratch "$JOB_ID" --json) + CURRENT_REVISION=$(printf '%s' "$result" | node -e ' + const result = JSON.parse(require("node:fs").readFileSync(0, "utf8")); + console.log(result.currentRevision ?? 0); + ') + CURRENT_CONTENT=$(printf '%s' "$result" | node -e ' + const result = JSON.parse(require("node:fs").readFileSync(0, "utf8")); + process.stdout.write(result.scratch?.content ?? ""); + ') +} + +push_scratch() { + openclaw cron scratch "$JOB_ID" --file "$SOURCE_FILE" --expected-revision "$CURRENT_REVISION" \ + >/dev/null + echo "[apply-heartbeat-scratch] pushed $SOURCE_FILE (job $JOB_ID, was revision $CURRENT_REVISION)" +} + +main "$@" diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/backup.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/backup.sh index 3609eec..95838f1 100755 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/backup.sh +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/bin/backup.sh @@ -2,7 +2,7 @@ # # Copies the deployment state of the service account into ~/backups/deployment//: # openclaw.json, the secret store, the gateway env file, the workspace files, environment.d, -# and the alproject registry when present. +# the alproject registry when present, and OpenClaw's own archive of its SQLite state. # # Run as the service account: # sudo -i -u {{SERVICE_USER}} -- /home/{{SERVICE_USER}}/seed/bin/backup.sh @@ -25,10 +25,18 @@ main() { copy_workspace copy_environment copy_file "$REGISTRY_FILE" alproject-registry.json + create_openclaw_archive chmod -R go-rwx "$BACKUP_DIR" echo "$BACKUP_DIR" } +# OpenClaw's archive holds what the plain copies above cannot: the SQLite state (sessions, cron +# jobs and their scratch, plugin consent, device pairing) and the auth profiles. The workspace is +# already copied. +create_openclaw_archive() { + openclaw backup create --output "$BACKUP_DIR" --no-include-workspace --verify >/dev/null +} + create_backup_dir() { install -d -m 700 "$BACKUP_BASE" BACKUP_DIR=$(mktemp -d "$BACKUP_BASE/$(date +%Y%m%d-%H%M%S)-XXXXXX") diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/heartbeat-scratch.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/heartbeat-scratch.md new file mode 100644 index 0000000..c5f72b4 --- /dev/null +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/heartbeat-scratch.md @@ -0,0 +1,4 @@ +# Heartbeat + +# Keep this scratch comment-only (ATX headers and blank lines): the daily tick then skips its +# model call. Exec-exit wakes bypass the scratch gate entirely. diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed.sh index edbf2f6..7721ebc 100755 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed.sh +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed.sh @@ -139,8 +139,7 @@ install_environment_files() { } verify() { - echo "[seed] secrets audit" - openclaw secrets audit --check + audit_secrets echo "[seed] config validate" openclaw config validate echo "[seed] doctor (interactive; the first install adds --fix once, see 04-openclaw.md)" @@ -148,4 +147,21 @@ verify() { echo "[seed] done. Apply with: systemctl --user restart openclaw-gateway" } +audit_secrets() { + echo "[seed] secrets audit" + # Not `--check`: it fails on every finding, including the info-level LEGACY_RESIDUE that a + # provider OAuth login (04-openclaw.md § 10) always produces. Fail on the actionable counters. + openclaw secrets audit --json | node -e ' + const report = JSON.parse(require("node:fs").readFileSync(0, "utf8")); + const summary = report.summary; + const failures = summary.plaintextCount + summary.unresolvedRefCount + + summary.shadowedRefCount + summary.storeResidueCount; + console.log(`[seed] secrets audit: ${JSON.stringify(summary)}`); + if (failures > 0) { + console.error(JSON.stringify(report.findings, null, 2)); + process.exit(1); + } + ' +} + main "$@" diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed/common.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed/common.sh index a975ff1..3f25a95 100755 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed/common.sh +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/seed/common.sh @@ -12,12 +12,6 @@ secrets_provider_id="$(printf '%s' '{{DEVELOPER_NAME}}' | tr '[:upper:]' '[:lowe set_scalar() { openclaw config set "$1" "$2"; } set_json() { openclaw config set "$1" --json "$2"; } - -# set_json_tolerated : for keys the installed version may have removed. -set_json_tolerated() { - set_json "$1" "$2" || echo "[seed] skipped $1: $3" -} - unset_key() { openclaw config unset "$1" || true; } # ref : SecretRef into the file provider registered by seed.sh. The pointer is a JSON @@ -25,6 +19,16 @@ unset_key() { openclaw config unset "$1" || true; } ref() { printf '{"source":"file","provider":"%s","id":"%s"}' "$secrets_provider_id" "$1"; } set_secret_ref() { set_json "$1" "$(ref "$2")"; } +# install_plugin_once : installs an external npm plugin when no copy is present under +# ~/.openclaw/npm/ (the layout varies across versions). The caller records the capability consent +# with `openclaw plugins enable --accept-capabilities`, which also enables the plugin. +install_plugin_once() { + if ! find "$HOME/.openclaw/npm" -maxdepth 6 -type d -path "*/node_modules/$1" 2>/dev/null \ + | grep -q .; then + openclaw plugins install "$1" --accept-capabilities + fi +} + # merge_managed_block : replaces the block between # `` and `` in the target with the source content, keeps the # rest of the file, and writes nothing when the result already equals the target (a re-seed then @@ -97,27 +101,35 @@ configure_common() { else unset_key "models.providers.$RUNTIME_PROVIDER.apiKey" fi + + echo "[seed] memory — nothing persists across sessions" # Semantic recall is unused; disabled so it never binds a provider of its own. - set_json_tolerated agents.defaults.memorySearch.enabled false \ - "key removed upstream after 2026.7 (config-surface reduction); harmless when rejected" + set_json memory.search.enabled false + # Defaults on while session.dmScope is unset; doctor reports it "effectively enabled". + set_json memory.search.rememberAcrossConversations false + # The pre-compaction memory flush is an agentic turn that writes memory/YYYY-MM-DD.md when a + # long session nears its token limit. + set_json agents.defaults.compaction.memoryFlush.enabled false + # memory-core owns the memory slot and loads regardless of plugins.allow, bringing the + # memory_search/memory_get tools and a nightly "dreaming" turn that rewrites MEMORY.md. The + # slot is its only off switch. A leftover plugins.entries.memory-core block would warn + # "plugin disabled but config is present". + set_scalar plugins.slots.memory none + unset_key plugins.entries.memory-core echo "[seed] heartbeat — on, one periodic tick a day" # Heartbeat stays on: the alcode completion wake is a heartbeat-sourced turn. `every` only - # governs periodic ticks. isolatedSession, lightContext and activeHours would each break the - # wake (throwaway session, no workspace bootstrap, deferred run), so they are cleared. + # governs periodic ticks; the gateway derives the system-owned `heartbeat:main` cron job from + # it. isolatedSession, lightContext and activeHours would each break the wake (throwaway + # session, no workspace bootstrap, deferred run), so they are cleared. set_scalar agents.defaults.heartbeat.every "24h" # Explicit target: the implicit owner-DM default prepends a one-time operator-facing - # "First heartbeat alert" preamble to the first delivered wake report (2026.8+), and the + # "First heartbeat alert" preamble to the first delivered wake report, and the # owner route never resolves to a group. Wake reports must follow the ticket conversation, # which "last" targets. set_scalar agents.defaults.heartbeat.target "last" - set_scalar agents.defaults.heartbeat.prompt \ - "Read HEARTBEAT.md if it exists (workspace context). Follow it strictly. \ -Do not infer or repeat old tasks from prior chats. \ -If nothing needs attention, reply exactly NO_REPLY." - # Drops the built-in "reply exactly: HEARTBEAT_OK" section, which contradicts NO_REPLY. - set_json_tolerated agents.defaults.heartbeat.includeSystemPromptSection false \ - "key removed upstream after 2026.7 (config-surface reduction); harmless when rejected" + # Stock prompt: it follows the job's scratch (04-openclaw.md § 7) and ends in NO_REPLY. + unset_key agents.defaults.heartbeat.prompt unset_key agents.defaults.heartbeat.isolatedSession unset_key agents.defaults.heartbeat.lightContext unset_key agents.defaults.heartbeat.activeHours @@ -127,6 +139,15 @@ If nothing needs attention, reply exactly NO_REPLY." # command skills belong to the delegated coding agent only. set_json agents.defaults.skills \ '["alignfirst","alignfirst-setup-guide","alignfirst-developer-openclaw-playbook","sharp-writing"]' + # Skill Workshop defaults to "auto": a weekly system-owned cron job lets the agent rewrite or + # drop writable skills. Same rule as clawhub. + set_scalar skills.workshop.autonomous.mode off + + echo "[seed] updates — operator-driven (update-developer.md)" + # The startup check also sends an anonymous version ping to telemetry.openclaw.ai. Background + # auto-update could not write the root-owned npm prefix anyway. + set_json update.checkOnStart false + set_json update.auto.enabled false echo "[seed] tools" set_scalar tools.profile coding @@ -154,8 +175,7 @@ If nothing needs attention, reply exactly NO_REPLY." echo "[seed] plugins — explicit allowlist" # A provider served by an additional OpenClaw plugin (a runtime harness, for example) needs - # `plugins.entries..enabled true` and its id appended to `plugins.allow` here; the runbook - # 04 shows the form. + # `install_plugin_once`, its id appended to `plugins.allow` here and `openclaw plugins enable`; + # the runbook 04 shows the form. set_json plugins.allow "[\"$surface_plugin_id\",\"$RUNTIME_PROVIDER\",\"browser\"]" - set_json_tolerated plugins.bundledDiscovery '"allowlist"' "key removed upstream after 2026.7" } diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/workspace/HEARTBEAT.md b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/workspace/HEARTBEAT.md deleted file mode 100644 index 5ae5f4a..0000000 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/base/infra/openclaw/workspace/HEARTBEAT.md +++ /dev/null @@ -1,4 +0,0 @@ -# Heartbeat - -# Keep this file comment-only (ATX headers and blank lines): the periodic tick -# then skips its model call. Exec-exit wakes bypass this file entirely. diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/discord/infra/openclaw/seed/surface.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/discord/infra/openclaw/seed/surface.sh index 0096173..19495e4 100755 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/discord/infra/openclaw/seed/surface.sh +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/discord/infra/openclaw/seed/surface.sh @@ -19,14 +19,15 @@ validate_surface() { configure_surface() { echo "[seed] plugin — @openclaw/discord" - # External npm plugin; installed under ~/.openclaw/npm/ (layout varies across versions). - if ! find "$HOME/.openclaw/npm" -maxdepth 6 -type d -path '*/node_modules/@openclaw/discord' \ - 2>/dev/null | grep -q .; then - openclaw plugins install @openclaw/discord - fi - set_json plugins.entries.discord.enabled true + install_plugin_once @openclaw/discord + # Enables the plugin and records the capability consent, kept per plugin version outside + # openclaw.json, so a version bump needs it again. Idempotent. + openclaw plugins enable discord --accept-capabilities echo "[seed] Discord channel — single guild channel, DMs by pairing" + # A wake report follows the last conversation, which may be a paired DM. The explicit value + # (the default) also stops doctor's security check from asking for a pin. + set_scalar agents.defaults.heartbeat.directPolicy allow set_json channels.discord.enabled true set_secret_ref channels.discord.token /DISCORD_BOT_TOKEN # The owner is pre-trusted; another DM sender gets a pairing code (operations/pair-dm-sender.md). diff --git a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/slack/infra/openclaw/seed/surface.sh b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/slack/infra/openclaw/seed/surface.sh index 12c5f26..c2862be 100755 --- a/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/slack/infra/openclaw/seed/surface.sh +++ b/skills/alignfirst-setup-guide/assets/alignfirst-developer-template/variants/surfaces/slack/infra/openclaw/seed/surface.sh @@ -20,14 +20,15 @@ validate_surface() { configure_surface() { echo "[seed] plugin — @openclaw/slack" - # External npm plugin; installed under ~/.openclaw/npm/ (layout varies across versions). - if ! find "$HOME/.openclaw/npm" -maxdepth 6 -type d -path '*/node_modules/@openclaw/slack' \ - 2>/dev/null | grep -q .; then - openclaw plugins install @openclaw/slack - fi - set_json plugins.entries.slack.enabled true + install_plugin_once @openclaw/slack + # Enables the plugin and records the capability consent, kept per plugin version outside + # openclaw.json, so a version bump needs it again. Idempotent. + openclaw plugins enable slack --accept-capabilities echo "[seed] Slack channel — Socket Mode, single channel, DMs disabled" + # Inbound DMs are disabled, so heartbeat wake reports never target a DM. The explicit value + # also stops doctor's security check from asking for a pin. + set_scalar agents.defaults.heartbeat.directPolicy block set_json channels.slack.enabled true set_secret_ref channels.slack.botToken /SLACK_BOT_TOKEN set_secret_ref channels.slack.appToken /SLACK_APP_TOKEN diff --git a/skills/alignfirst-setup-guide/references/alignfirst-developer.md b/skills/alignfirst-setup-guide/references/alignfirst-developer.md index 1f3f927..42c5c8f 100644 --- a/skills/alignfirst-setup-guide/references/alignfirst-developer.md +++ b/skills/alignfirst-setup-guide/references/alignfirst-developer.md @@ -151,4 +151,4 @@ The generated runbooks contain the concrete Ubuntu commands. Keep root commands - Managed-project workspaces are isolated; reports return to the originating thread. - The gateway survives a reboot. - Kill switch, failed-command maintenance cleanup, backup, update and recovery have each been exercised. -- `openclaw secrets audit --check` passes; every credential in `openclaw.json` is a file SecretRef; the gateway environment holds no secret. +- `openclaw secrets audit` reports no plaintext, unresolved or shadowed reference and no store residue; every credential in `openclaw.json` is a file SecretRef; the gateway environment holds no secret.