diff --git a/.github/workflows/privacy-scan.yml b/.github/workflows/privacy-scan.yml index 157e241..dfc1d48 100644 --- a/.github/workflows/privacy-scan.yml +++ b/.github/workflows/privacy-scan.yml @@ -15,17 +15,48 @@ jobs: with: fetch-depth: 0 + - name: Skip push scan when PR exists + id: pr_guard + if: github.event_name == 'push' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + REPO: ${{ github.repository }} + OWNER: ${{ github.repository_owner }} + BRANCH: ${{ github.ref_name }} + run: | + if [ "${BRANCH}" = "main" ]; then + echo "skip_scan=false" >> "$GITHUB_OUTPUT" + echo "Main branch push detected; running push scan." + exit 0 + fi + + prs=$(curl -sS \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${REPO}/pulls?state=open&head=${OWNER}:${BRANCH}&per_page=1") + + if [ "$(echo "$prs" | python3 -c "import sys, json; d=json.load(sys.stdin); print(len(d) if isinstance(d, list) else 0)")" -gt 0 ]; then + echo "skip_scan=true" >> "$GITHUB_OUTPUT" + echo "Open PR detected for branch ${BRANCH}; skipping push scan." + else + echo "skip_scan=false" >> "$GITHUB_OUTPUT" + echo "No open PR detected; running push scan." + fi + - name: Cleanup stale gitleaks temp file + if: steps.pr_guard.outputs.skip_scan != 'true' run: | sudo rm -f /tmp/gitleaks.tmp || rm -f /tmp/gitleaks.tmp || true - name: Run gitleaks + if: steps.pr_guard.outputs.skip_scan != 'true' uses: gitleaks/gitleaks-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Determine diff range id: range + if: steps.pr_guard.outputs.skip_scan != 'true' run: | if [ "${{ github.event_name }}" = "pull_request" ]; then echo "base=${{ github.event.pull_request.base.sha }}" >> "$GITHUB_OUTPUT" @@ -44,6 +75,7 @@ jobs: echo "three_dot=false" >> "$GITHUB_OUTPUT" - name: Run PII guard on added lines + if: steps.pr_guard.outputs.skip_scan != 'true' run: | if [ "${{ steps.range.outputs.three_dot }}" = "true" ]; then python3 scripts/pii_guard.py \ diff --git a/README.md b/README.md index 7728a42..af2ecd1 100644 --- a/README.md +++ b/README.md @@ -158,6 +158,19 @@ Detailed runbook: `docs/obsidian-operations.md`. The main configuration is in `config/openclaw.json` (JSON5 format). See `config/AGENTS.md` for complete reference. +### Memory Persistence Preferences + +This project uses explicit memory persistence preferences to reduce context loss between sessions: + +- **Long idle session window**: `session.reset.idleMinutes` is set to `1440` (24h) so conversations are less likely to reset before memory safeguards can run. +- **Pre-compaction memory flush enabled**: `agents.defaults.compaction.memoryFlush.enabled: true` with `softThresholdTokens: 4000` and `reserveTokensFloor: 40000`. +- **Memory checkpoint cron**: state repos should include a recurring checkpoint job that updates the **memory daily log** at `memory/YYYY-MM-DD.md` incrementally. +- **Dedup cursor file**: `memory/flush-state.json` tracks checkpoint progress to reduce repeated entries in the same day. + +Terminology note: +- Use **memory daily log** for `memory/YYYY-MM-DD.md`. +- Use **Obsidian daily note** only for vault files under `07-Daily/`. + ### Auxiliary ML Service (Optional) The auxiliary ML service runs in a dedicated container and is designed for queue-based, long-running jobs (minutes are acceptable). It currently starts with OCR (`glm-ocr`) and keeps a modular model registry for future additions. @@ -238,7 +251,8 @@ josemar-assistente/ │ ├── .sync-manifest # Files to version │ ├── .gitignore # Security ignore list │ ├── skills/ # User-owned state skills -│ └── cron/jobs.json # Cron definitions synced from state repo +│ ├── cron/jobs.json # Cron definitions synced from state repo +│ └── memory/flush-state.json # Checkpoint cursor for memory daily log dedup ├── config/ # OpenClaw configuration │ ├── AGENTS.md # Config reference │ └── openclaw.json # Main config diff --git a/config/openclaw.json b/config/openclaw.json index be685d5..e872378 100644 --- a/config/openclaw.json +++ b/config/openclaw.json @@ -186,6 +186,13 @@ workspace: "~/.openclaw/workspace", userTimezone: "${JOSEMAR_TIMEZONE}", envelopeTimezone: "${JOSEMAR_TIMEZONE}", + compaction: { + reserveTokensFloor: 40000, + memoryFlush: { + enabled: true, + softThresholdTokens: 4000, + }, + }, model: { primary: "ollama/kimi-k2.6:cloud", fallbacks: ["zai/glm-5", "zai/glm-4.7", "deepseek/deepseek-chat", "ollama/glm-5.1:cloud"], @@ -274,7 +281,7 @@ scope: "per-sender", reset: { mode: "idle", - idleMinutes: 60, + idleMinutes: 1440, }, store: "~/.openclaw/agents/josemar/sessions/sessions.json", }, diff --git a/templates/agent-state-template/.sync-manifest b/templates/agent-state-template/.sync-manifest index 37f8c3f..b4feb6f 100644 --- a/templates/agent-state-template/.sync-manifest +++ b/templates/agent-state-template/.sync-manifest @@ -13,6 +13,7 @@ skills/*/* # Memory logs (daily files matching YYYY-MM-DD.md) memory/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].md +memory/flush-state.json # Avatars avatars/* diff --git a/templates/agent-state-template/README.md b/templates/agent-state-template/README.md index 2f6e7fd..3d48274 100644 --- a/templates/agent-state-template/README.md +++ b/templates/agent-state-template/README.md @@ -40,6 +40,8 @@ Personality files (`SOUL.md`, `IDENTITY.md`, `USER.md`, `AGENTS.md`) are created Operational files (`TOOLS.md`, `BOOT.md`, `HEARTBEAT.md`) are pre-seeded in this template to document core capabilities available out of the box. +This template also includes a memory checkpoint cron job (`cron/jobs.json`) plus `memory/flush-state.json` to keep daily memory logs updated incrementally with reduced duplication. + ## Skill Ownership Model This project separates skills by ownership: diff --git a/templates/agent-state-template/cron/jobs.json b/templates/agent-state-template/cron/jobs.json index 10c974e..aff23b5 100644 --- a/templates/agent-state-template/cron/jobs.json +++ b/templates/agent-state-template/cron/jobs.json @@ -1,4 +1,31 @@ { "$schema": "https://openclaw.ai/schemas/cron-jobs.json", - "jobs": [] + "jobs": [ + { + "id": "9bb8cc42-bca2-4516-b7c0-4305d0315fc9", + "agentId": "josemar", + "sessionKey": "agent:josemar:main", + "name": "Checkpoint de memória", + "description": "Checkpoint incremental de memória para garantir memory daily log (memory/YYYY-MM-DD.md) sem duplicações", + "enabled": true, + "schedule": { + "expr": "0 10,15,21 * * *", + "kind": "cron", + "tz": "America/Sao_Paulo" + }, + "sessionTarget": "main", + "wakeMode": "now", + "payload": { + "kind": "agentTurn", + "message": "Checkpoint de memória (sem resposta ao usuário).\n\n1. Use NO_REPLY.\n2. Garanta que exista memory/YYYY-MM-DD.md para hoje; crie se não existir.\n3. Leia memory/YYYY-MM-DD.md e memory/flush-state.json antes de escrever.\n4. Faça um resumo incremental do que aconteceu desde o último checkpoint, sem repetir itens já registrados hoje.\n5. Escreva apenas fatos relevantes (decisões, mudanças de configuração, ações executadas, pendências).\n6. Se não houver novidade real desde o último checkpoint, não altere o memory daily log (memory/YYYY-MM-DD.md).\n7. Atualize memory/flush-state.json com lastCheckpointAt (ISO-8601) e lastSummaryHash (hash do resumo incremental).", + "toolsAllow": [ + "read", + "write" + ] + }, + "delivery": { + "mode": "none" + } + } + ] } diff --git a/templates/agent-state-template/memory/flush-state.json b/templates/agent-state-template/memory/flush-state.json new file mode 100644 index 0000000..5ee7cee --- /dev/null +++ b/templates/agent-state-template/memory/flush-state.json @@ -0,0 +1,4 @@ +{ + "lastCheckpointAt": null, + "lastSummaryHash": null +}