Skip to content

feat: add guard.app.update and guard.app.updateCheck command operations#1310

Merged
kantorcodes merged 7 commits into
mainfrom
fix/guard-app-update-command
Jul 5, 2026
Merged

feat: add guard.app.update and guard.app.updateCheck command operations#1310
kantorcodes merged 7 commits into
mainfrom
fix/guard-app-update-command

Conversation

@kantorcodes

Copy link
Copy Markdown
Member

Summary

Add two new command queue operations for remote Guard CLI updates:

  1. guard.app.update — executes run_guard_update(dry_run=False) on the agent machine. Returns the update payload and exit code. Does not require a harness (updates hol-guard itself, not a harness adapter).

  2. guard.app.updateCheck — calls build_guard_update_status_payload() read-only. Returns current_version, latest_version, update_available, auto_updatable, and blocked_reason. Used by the portal to display version status in the agent list.

Auto-update

_maybe_auto_update() runs during the empty poll path when no job was leased. Throttled to once per 6 hours via guard_auto_update_state KV. Only self-applies when:

  • auto_updatable=True
  • update_available=True
  • blocked_reason=None

Source/editable installs are excluded by the existing auto_updatable flag in build_guard_update_status_payload.

Tests

9 new tests in test_guard_command_executors_update.py:

  • Update check returns status payload
  • Update calls run_guard_update
  • Update handles failure exit code
  • Unsupported app operation returns failure
  • Auto-update skipped within throttle window
  • Auto-update runs after throttle window
  • Auto-update skipped when not auto_updatable
  • Auto-update skipped when no update available
  • Operations registered in APP_OPERATIONS

All 77 existing command queue tests still pass.

@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@greptile-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds remote Guard CLI update operations and a throttled auto-update path. The main changes are:

  • New guard.app.update command that runs the Guard updater with runtime context and store.
  • New guard.app.updateCheck command that returns the current update status payload.
  • Empty-poll auto-update logic that checks eligibility, applies updates, and persists throttle/update state.
  • Tests for command registration, executor output, failures, throttling, eligibility, and malformed state.

Confidence Score: 5/5

Safe to merge with low risk.

The updated paths are scoped to new command operations and an empty-poll update hook. The updater receives the runtime store and context. Tests cover the main command and auto-update control-flow branches. No new blocking issues were identified.

No files require special attention.

T-Rex T-Rex Logs

What T-Rex did

  • The guard-update-tests-02 suite was executed and ten tests passed in 0.37 seconds with a clean exit.
  • The guard-command-queue-update-coverage-01 suite was executed and 79 tests passed in 4.06 seconds with a clean exit.
  • A concise command validation summary was generated to provide a quick review of the results.

View all artifacts

T-Rex Ran code and verified through T-Rex

Important Files Changed

Filename Overview
src/codex_plugin_scanner/guard/runtime/auto_update.py Adds throttled empty-poll auto-update checks with persisted status and update results.
src/codex_plugin_scanner/guard/runtime/command_executors.py Registers and executes guard.app.update and guard.app.updateCheck, passing runtime store/context to the updater.
src/codex_plugin_scanner/guard/runtime/command_queue.py Invokes auto-update only on the empty lease path after saving idle poll state.
tests/test_guard_command_executors_update.py Adds focused coverage for update commands, registration, throttling, update eligibility, and malformed in-memory state.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant Portal as Guard Cloud / Portal
participant Queue as command_queue.poll_command_queue_once
participant Exec as command_executors
participant Update as update_commands
participant Store as GuardStore

Portal->>Queue: lease command
alt job leased: guard.app.update
    Queue->>Exec: execute_guard_command_job(job)
    Exec->>Update: "run_guard_update(dry_run=False, context, store)"
    Update-->>Exec: update payload + exit code
    Exec-->>Queue: result data
else job leased: guard.app.updateCheck
    Queue->>Exec: execute_guard_command_job(job)
    Exec->>Update: build_guard_update_status_payload()
    Update-->>Exec: status payload
    Exec-->>Queue: result data
else no job leased
    Queue->>Store: save idle state
    Queue->>Update: maybe_auto_update(store, context)
    Update->>Store: read guard_auto_update_state
    alt throttle elapsed and update eligible
        Update->>Update: build_guard_update_status_payload()
        Update->>Update: "run_guard_update(dry_run=False, context, store)"
        Update->>Store: persist last update result
    else throttled or not eligible
        Update->>Store: persist last check status when checked
    end
end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant Portal as Guard Cloud / Portal
participant Queue as command_queue.poll_command_queue_once
participant Exec as command_executors
participant Update as update_commands
participant Store as GuardStore

Portal->>Queue: lease command
alt job leased: guard.app.update
    Queue->>Exec: execute_guard_command_job(job)
    Exec->>Update: "run_guard_update(dry_run=False, context, store)"
    Update-->>Exec: update payload + exit code
    Exec-->>Queue: result data
else job leased: guard.app.updateCheck
    Queue->>Exec: execute_guard_command_job(job)
    Exec->>Update: build_guard_update_status_payload()
    Update-->>Exec: status payload
    Exec-->>Queue: result data
else no job leased
    Queue->>Store: save idle state
    Queue->>Update: maybe_auto_update(store, context)
    Update->>Store: read guard_auto_update_state
    alt throttle elapsed and update eligible
        Update->>Update: build_guard_update_status_payload()
        Update->>Update: "run_guard_update(dry_run=False, context, store)"
        Update->>Store: persist last update result
    else throttled or not eligible
        Update->>Store: persist last check status when checked
    end
end
Loading

Reviews (8): Last reviewed commit: "fix(guard): persist throttle state on ve..." | Re-trigger Greptile

Comment thread src/codex_plugin_scanner/guard/runtime/command_queue.py Outdated
Comment thread src/codex_plugin_scanner/guard/runtime/command_queue.py
Comment thread src/codex_plugin_scanner/guard/runtime/command_executors.py Outdated
Comment thread src/codex_plugin_scanner/guard/runtime/auto_update.py Outdated
Comment thread src/codex_plugin_scanner/guard/runtime/auto_update.py Outdated
Comment thread src/codex_plugin_scanner/guard/runtime/command_queue.py
Comment thread tests/test_guard_command_executors_update.py
@kilo-code-bot

kilo-code-bot Bot commented Jul 5, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • src/codex_plugin_scanner/guard/runtime/command_queue.py
Previous Review Summaries (4 snapshots, latest commit 7191d1e)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 7191d1e)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • src/codex_plugin_scanner/guard/runtime/command_queue.py

Previous review (commit d744e28)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (1 file)
  • src/codex_plugin_scanner/guard/runtime/command_queue.py

Previous review (commit 1768f73)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 1
Issue Details (click to expand)

CRITICAL

File Line Issue

WARNING

File Line Issue
src/codex_plugin_scanner/guard/runtime/auto_update.py 30 json.loads can return None for literal "null", causing state.get(...) to fail
src/codex_plugin_scanner/guard/runtime/auto_update.py 79 finally block calling store.set_kv can mask exceptions from run_guard_update
src/codex_plugin_scanner/guard/runtime/command_queue.py 435 _maybe_auto_update is called without error handling in the empty-poll path

SUGGESTION

File Line Issue
tests/test_guard_command_executors_update.py 208 Test has no assertion — only verifies the function does not crash
Files Reviewed (4 files)
  • src/codex_plugin_scanner/guard/runtime/auto_update.py - 2 issues
  • src/codex_plugin_scanner/guard/runtime/command_queue.py - 1 issue
  • tests/test_guard_command_executors_update.py - 1 issue
  • src/codex_plugin_scanner/guard/runtime/command_executors.py - 0 issues

Fix these issues in Kilo Cloud

Previous review (commit 649d0b9)

Status: 4 Issues Found | Recommendation: Address before merge

Overview

Severity Count
CRITICAL 0
WARNING 3
SUGGESTION 1
Issue Details (click to expand)

CRITICAL

File Line Issue

WARNING

File Line Issue
src/codex_plugin_scanner/guard/runtime/auto_update.py 30 json.loads can return None for literal "null", causing state.get(...) to fail
src/codex_plugin_scanner/guard/runtime/auto_update.py 79 finally block calling store.set_kv can mask exceptions from run_guard_update
src/codex_plugin_scanner/guard/runtime/command_queue.py 435 _maybe_auto_update is called without error handling in the empty-poll path

SUGGESTION

File Line Issue
tests/test_guard_command_executors_update.py 208 Test has no assertion — only verifies the function does not crash
Files Reviewed (4 files)
  • src/codex_plugin_scanner/guard/runtime/auto_update.py - 2 issues
  • src/codex_plugin_scanner/guard/runtime/command_queue.py - 1 issue
  • tests/test_guard_command_executors_update.py - 1 issue
  • src/codex_plugin_scanner/guard/runtime/command_executors.py - 0 issues

Fix these issues in Kilo Cloud


Reviewed by step-3.7-flash · Input: 72.7K · Output: 11.9K · Cached: 84K

Comment thread src/codex_plugin_scanner/guard/runtime/auto_update.py Outdated
Comment thread src/codex_plugin_scanner/guard/runtime/auto_update.py
…perations

Add two new command queue operations for remote Guard CLI updates:

1. guard.app.update — executes run_guard_update(dry_run=False) on
   the agent machine. Returns the update payload and exit code. Does
   not require a harness (updates hol-guard itself, not a harness
   adapter).

2. guard.app.updateCheck — calls build_guard_update_status_payload()
   read-only. Returns current_version, latest_version,
   update_available, auto_updatable, and blocked_reason. Used by the
   portal to display version status in the agent list.

Auto-update: _maybe_auto_update() runs during the empty poll path
when no job was leased. Throttled to once per 6 hours via
guard_auto_update_state KV. Only self-applies when
auto_updatable=True, update_available=True, and no blocked_reason.
Source/editable installs are excluded by the existing
auto_updatable flag in build_guard_update_status_payload.

Tests: 9 new tests covering both executors, auto-update throttle,
auto-update exclusion for non-auto-updatable installs, and
auto-update skip when no update is available. All 77 existing
command queue tests still pass.
…rmed state

Address Greptile review feedback:

- P1: Wrap json.loads in try/except for malformed auto-update state.
  A corrupted guard_auto_update_state value no longer crashes the
  empty-poll path — it is treated as empty state.
- P2: Move auto-update logic to auto_update.py (96 lines), reducing
  command_queue.py from 609 to 490 lines. command_queue.py now has
  a thin _maybe_auto_update wrapper that delegates to
  auto_update.maybe_auto_update.

Added test: test_auto_update_handles_malformed_state verifies that
malformed JSON in the state KV does not crash.
…ting

- Restore _REQUEST_TIMEOUT_SECONDS constant that was accidentally
  removed during the auto-update extraction
- Fix import block sorting (auto_update before runner)
- Remove unnecessary quotes from type annotations in auto_update.py
  (from __future__ import annotations is present)
Address Greptile P1: run_guard_update() only refreshes managed harness
installs when store is passed. Previously passed store=None which meant
the update would not trigger the managed install refresh flow.
…-update state

Address Greptile P1: GuardStore does not define get_kv/set_kv.
Use the existing get_sync_payload/set_sync_payload methods that
command_queue.py already uses for its state persistence. Remove the
defensive hasattr checks since these methods are part of the
GuardStore interface. Remove unused json import.
Address Greptile P1: when build_guard_update_status_payload() raises,
the throttle state was not persisted, causing the next poll cycle to
retry immediately. Now saves last_check_at and last_check_error before
returning.
@kantorcodes kantorcodes force-pushed the fix/guard-app-update-command branch from 7191d1e to ab61bca Compare July 5, 2026 00:53
@kantorcodes kantorcodes merged commit e96dd68 into main Jul 5, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant