# Self Update

> Check for and apply KiroCrew updates. Use when user says "update yourself", "check for updates", "are you up to date", "keep yourself updated", or "auto-update".

- Skill: `kirodotdev/self-update` (Agent Skill)
- Install (CLI): `npx skillmds@latest add kirodotdev/self-update`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kirodotdev/self-update/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: kirodotdev (https://skillmd.com/u/kirodotdev)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kirodotdev/self-update

---


# Self-Update

## Overview

Check for available KiroCrew updates, apply them, and optionally set up automatic update checking via cron.

`kirocrew update` behaves differently on three install layouts, and which one the
user is on decides everything below:

- **git checkout** — fetch, then `reset --hard` to the upstream tip. Only a
  fast-forwardable checkout is updated; a DIVERGED checkout (local commits both
  ahead and behind) is refused, because the reset would discard them.
- **wheel / cli.sh** — fetch the release feed, compare versions, re-run the
  installer.
- **externally managed (desktop app, Docker)** — prints guidance and returns
  without updating. The desktop app updates itself over its own OTA channel.

There is no separate "check" subcommand.

A policy-defined update provider, when one is configured, owns updating this host:
it runs before any layout dispatch, the built-in mechanism never runs, and there is
no fallback — `kirocrew update` exits 1 on provider failure. Report the provider's
failure; do not try to route around it.

## Core Concepts

### Checking for Updates

Non-destructive — safe to run anytime. Report the installed version:

```bash
kirocrew --version
```

Then compare it against **that layout's own source of truth**: upstream for a git
checkout, the release feed for a wheel install, the app's own updater for desktop.
Comparing against the public repository's tags is right only for a git install.

### Applying Updates

To apply an available update:

```bash
kirocrew update
```

The gateway must be restarted afterward for the new version to take effect.

Two more verbs:

```bash
kirocrew update approve   # approve a pending in-app update armed from the dashboard
kirocrew update --force   # git installs only
```

`--force` is the destructive one: on a diverged git checkout it lets the hard reset
**discard local commits**, recoverable only from `git reflog`. Never run it without
saying that first.

### Automatic Update Checking

If the user asks for automatic updates, create a cron job that checks periodically and notifies.

**Scheduling rules:**
1. **Pick a random weekday and business hour** — don't hardcode Monday 9am. Suggest something like "I'll check on Wednesdays around 2pm" and let the user approve or adjust.
2. **Add a random minute** (0-59) to the cron expression to avoid a thundering herd of all KiroCrew instances checking simultaneously.
3. **Use the user's local timezone** — get it from their Slack profile via `read_slack_profile`. The `cron_add` tool accepts a `timezone` parameter. Never schedule in UTC unless the user is actually in UTC.
4. **For auto-apply mode**, some users prefer updates outside business hours (e.g. "update overnight"). Ask the user's preference.

**Determining the user's timezone:**

Check the system timezone first (fastest). If it's UTC, it may be an unconfigured cloud desktop rather than the user's actual timezone — verify with a second source.

```bash
# System timezone (fast, local)
cat /etc/timezone  # or: timedatectl show -p Timezone --value
```

Resolution order:
1. **System timezone is non-UTC** — use it (reliably reflects user's locale)
2. **System timezone is UTC** — could be correct or could be an unconfigured server. Check Slack profile via `read_slack_profile(user="<user_id>")` for the user's configured timezone, or ask the user to confirm
3. **If `read_slack_profile` unavailable** — ask the user directly

**Example — notify-only cron:**

```python
cron_add(
    name="kirocrew-update-check",
    cron_expr="37 14 * * 3",  # Wednesday at 2:37pm (random minute)
    timezone="America/Los_Angeles",  # from user's Slack profile
    command="kirocrew --version",
    message="Report the installed KiroCrew version and check whether a newer one is available",
)
```

A notify-only cron must NOT run `kirocrew update` (that applies the update). Use
`kirocrew --version` to report the installed version, and have the LLM-mode job
compare it against the public repo and tell the user if an update is available.
Present the schedule to the user for confirmation, always including the timezone: "I'll check for updates on Wednesdays around 2:37pm Pacific (America/Los_Angeles). Sound good?"

For fully automatic updates (apply + restart), first check the layout: only a git
or wheel install has a self-update path to automate. On a desktop install point the
user at the app's own OTA updater instead of a cron, and on Docker there is no
self-update at all. Where a cron does fit, use an LLM-mode one so it can follow the
gateway-restart skill for a safe restart:

```python
cron_add(
    name="kirocrew-auto-update",
    cron_expr="42 2 * * 4",  # Thursday at 2:42am (off-hours, random minute)
    timezone="America/Los_Angeles",
    message="Apply a KiroCrew update by scheduling it server-side, then follow the gateway-restart skill to restart the gateway. If already up to date, report briefly.",
)
```

An explicit `kirocrew update` is the supported way a source install updates; a
boot-time automatic apply is not part of the update architecture, so do not
reintroduce one by cron on a layout that has no self-update engine.

### Limitations

- BOTH `kirocrew restart` AND `kirocrew update` are blocked when run directly from an agent session, by the self-protection argv floor (it reads the command's argv, so mentioning the words in a path or a grep pattern is not blocked, and there is no opt-out).
- A policy-defined update provider, where configured, owns updating the host and there is no fallback: `kirocrew update` exits 1 if it fails. Report that failure rather than working around it.
- Because the agent shell cannot run them, an update must be applied either by the user manually, or scheduled server-side (a cron job runs outside the shell-tool filter). After an update, restart via the gateway-restart skill.
- After an update + restart, the resuming session runs the new code.

## Usage

### User asks "am I up to date?" or "check for updates"

1. Run `kirocrew --version` to show the current version
2. Compare it against that layout's own source of truth (upstream for a git checkout, the release feed for a wheel install, the app's updater for desktop)
3. Report findings
4. If an update is available, offer to apply it and offer to set up automatic updates

### User asks "update yourself"

1. Check the current version first
2. If an update is available, apply it (the agent shell cannot run `kirocrew update` directly — schedule it server-side via cron, or ask the user to run it)
3. Inform the user that a gateway restart is needed for the new version to take effect
4. Offer to schedule the restart via a cron (per the gateway-restart skill) or ask the user to run it manually

### User asks "keep yourself updated" or "auto-update"

1. Look up the user's timezone from their Slack profile (`read_slack_profile`)
2. Pick a random weekday and business-hour time; present for approval
3. Create a recurring cron with the user's timezone
4. Offer two modes:
   - **Notify only** — check and report during business hours, user applies manually
   - **Auto-apply** — apply and restart automatically (suggest off-hours for this mode)

