Skip to content
Agentmart
Submit a tool

umbraco-deploy

Deployment observation, schema application, and content transfer (watch, status, apply, transfer, queue)

Skill by albanistrefi

IndexedMIT★ 4
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/albanistrefi-umbraco-deploy

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Deployment observation, schema application, and content transfer (watch, status, apply, transfer, queue)

Use cases: devops, writing

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md and code. Checked Oct 26, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/umbraco-deploy

What's inside

Skill name
umbraco-deploy
Description
Deployment observation, schema application, and content transfer (watch, status, apply, transfer, queue)
License
MIT
Metadata
version: 0.5.5
Instructions
276 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# deploy

> **PREREQUISITE:** Read `../umbraco-shared/SKILL.md` for auth, global flags, and security rules.

```bash
umbraco deploy <command> [flags]
```

## Overview

```text
Deployment commands.

Task → command:
  Watch an environment while a deploy lands              deploy watch
  Compare .uda schema artifacts with an environment      deploy status --uda-dir <dir>
  Apply .uda schema ("Update schema")                    deploy apply --uda-dir <dir> --dry-run
  Move content to the next environment, GUIDs intact     deploy transfer --node <id> [--descendants] --dry-run   (Umbraco Deploy required)
  Queue content and transfer it together                 deploy queue add <id>; deploy queue list; deploy transfer --queue --force
```

## Read Commands

| Command | Description |
|---------|-------------|
| `deploy queue list` | List the items queued for transfer |
| `deploy status` | Compare local .uda deploy artifacts against the environment, read-only |
| `deploy watch` | Watch an environment for the effects of a deployment and report phase transitions |

### queue list

```bash
umbraco deploy queue list
```

### status

```bash
umbraco deploy status
```

Reads the Umbraco Deploy artifacts in --uda-dir (the site repo's umbraco/Deploy/Revision) and compares each against the target environment's database via the Management API, reporting in-sync vs drifted per entity. Strictly read-only: a pre-flight check that turns "will this deploy blow up or carry surprises?" into an answerable question — in-sync artifacts are skipped by Deploy's schema pass and are therefore safe; drifted ones are processed.

Comparison is per entity kind (data types, document/media/member types, templates, containers, member groups, relation types) over the fields the artifact carries; environment-only additions like migration markers are ignored. Automate artifacts degrade to status "unknown" where the Automate API is unreachable (Cloud basic auth blocks package APIs on non-live environments) — never a false in-sync — but their step aliases are still read locally, and --flag-step-alias marks automations carrying aliases you know your Deploy version cannot validate (configuration, not encoded knowledge: those landmines change as bugs are fixed).

Exit 7 when drift or missing entities are found (suppress with --exit-zero); parse failures and unreachable comparisons are reported per artifact, never silently dropped. The report is stdout; with an explicit -o json the drift exit is silent (the summary is inside the JSON), so even merged-stream captures parse. Without -o json the drift summary line goes to stderr.

| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--concurrency` | int | 8 | Maximum concurrent environment lookups |
| `--exit-zero` | bool | false | Exit 0 even when drift or missing entities are found |
| `--flag-step-alias` | stringArray | [] | Flag automations whose steps carry this action-alias substring (repeatable; e.g. a control-flow alias your Deploy version fails to validate) |
| `--kind` | stringArray | [] | Only compare these artifact kinds (Udi entity types, e.g. data-type, document-type; repeatable) |
| `--uda-dir` | string | umbraco/Deploy/Revision | Directory holding the .uda artifacts |

### watch

```bash
umbraco deploy watch
```

Observes the target environment for state deltas only a deployment can cause — no pipeline or portal API involved, so it works identically on Umbraco Cloud and on-prem, and it is strictly read-only.

Signals: the newest log entry's ProcessId/MachineName (an app recycle means the deploy landed; the "landed" line says "basis": "process-id"), the management token endpoint probed unauthenticated (503/unreachable = down; 401 = app alive and rejecting the probe — the earliest all-clear, typically ~15s before public pages return), configured health paths on the public host, and Examine index health (deploys can trigger full index rebuilds, during which search is empty — "deploy succeeded" and "the site works" are different questions).

Umbraco 18.2's log viewer refuses every read (HTTP 400, CancelledByLogsSizeValidation) once the log files of the days a read covers exceed 100 MB, which a busy site can reach during the day. A read without a start date covers a day ago too, so the day after a busy log day the newest-entry read is refused while a read from the server's midnight is not: when the default read is refused for size, the watch reads the newest entry from the start of the server's day instead (the day taken from /server/information's baseUtcOffset), and keeps doing so while that works. When that refusal is why the process id is missing (at baseline, or on the poll in question), the watch infers landing from a restart cycle instead: one outage of the management endpoint lasting at least --restart-min-down, then the health paths serving again. The outage is measured from its first to its last failed probe, at least two, so it is a lower bound on the downtime whatever the poll spacing (the 15-10 live restart was down 47s, about 40s of it between failed probes at the 5s interval); the default is 20s, or twice --interval when that is longer, and it must be shorter than --escalation. Since the first and last failed probes can each fall up to one --interval inside the outage, a restart must last --restart-min-down plus up to two poll gaps to be measured: with the default, intervals above about 11s may miss a 47s restart. The "landed" line then says "basis": "restart-cycle" with "processId": "unavailable", the reason and the outage (downSince, downFor, failedProbes). Shorter outages count as blips. Any read of the baseline process after the outage means it was no restart, even an entry from before the outage; an unreadable poll neither disproves nor confirms. Any other failure to read the process id, or an entry without one, waits for a readable process id as before. Residual risk on this basis: a restart that is not a deploy (a platform recycle) and lasts long enough also lands it; a deploy whose restart is too short to measure never lands (timeout, exit 6); and a real restart that leaves the old process's last line newest for one poll never lands on this basis either (timeout, exit 6) and needs a manual check: the watch fails safe, preferring status unknown to verifying an outage the process survived. If the log viewer already refuses at baseline, the watch arms with "landingBasis": "restart-cycle"; any other failure to read the newest log entry at baseline still refuses to arm. With --uda-dir and no baseline process id, schema pass detection is off (log entries from before the deploy cannot be told apart): verified then waits for every tracked artifact to be in sync, so a deploy that leaves one drifted times out (exit 6) instead of exiting 7.

Phases: baseline → restarting → app-alive → serving → landed → deployed → settling → verified | failed | timeout. Everything is baselined before arming — a signal already true on the target is not a signal. Verified requires the environment to stay healthy for a full --settle window after everything first looks good: deployment pipelines can disturb the environment AFTER the app is already serving (observed in production: Umbraco Deploy wiped every Examine index 27 seconds after a single-sample check had passed, leaving search empty for 17 minutes), so a single passing sample is not verification. An interrupted settle (index rebuild, health flap) is emitted as settle-interrupted and the window restarts once the environment recovers. Transitions are emitted with timestamps as they are observed (fast recycles may skip phases); silence between transitions means "still in the current phase", and --heartbeat writes a periodic still-alive line so silence is never ambiguous: text on stderr, and with --json also a "heartbeat" line on stdout ({timestamp, type, currentPhase, elapsed, lastPoll, logs: {read, emitted, status} with --logs, status being reading, unavailable or refused}; lastPoll is when the latest completed poll started). Heartbeats run on their own clock and the log monitor reads beside the probes, so neither waits on a slow request; each poll probes the management endpoint, then the health paths, the newest log entry and the indexes side by side, and every request gives up after --request-timeout (a health path that does not answer in time counts as failing for that poll). Success is never inferred from silence: reaching --timeout without verification exits 6 (status unknown), and sustained downtime or post-landing health failure beyond --escalation exits 5.

deployed is when Umbraco Deploy reports the deployment complete: its schema pass has ended with Work Status "Completed" in the new process's log and, with --uda-dir, every tracked artifact is in sync or has been re-checked after the pass (and is reported as still drifted or missing). It is emitted once, after landed and serving, with the deployment id when Deploy logged one (deploymentId), the timestamp of Deploy's log entry (loggedAt), the work status and, with --uda-dir, the schema counts (confirmed, remaining, unknown); the text line reads "deployed — deployment complete". It is a milestone, not a condition: verified does not wait for it (a deploy without schema changes may log no pass, and the watch can end before Deploy finishes), and it leaves the current phase alone: a settle window already running carries on, neither restarted nor ended, and heartbeats and a timeout still name the phase the watch is in (settling, or settle-interrupted while it waits to recover). A pass that ends with any other work status never emits deployed. It needs Umbraco Deploy's log: without --logs or --uda-dir, or without a baseline process id (its entries could not be told from older ones), it is never emitted and the baseline's "deployed" detail says so ("enabled": false with the reason); while the log viewer is unavailable or refuses reads it waits, since completion is never inferred from silence.

Every --json line has a "type": "phase" for the transitions above. --logs adds the deploy's log entries to the same stream as they are read, with the 'logs tail' poller from the newest entry at baseline: "log" lines (timestamp, category, level, sourceContext, message, exception's first line; e-mail addresses, tokens and secrets masked) for app start/stop (lifecycle), migrations and upgrades (migration), Examine indexer suspend/resume/rebuild (indexer), Umbraco Deploy entries (deploy), --logs-match hits (match) and anything at --logs-level or above (level, default Error); and "log-monitor" lines when the log viewer is unavailable (expected during the restart, or a rejected read) or resumes, when it refuses reads for size (refused: these reads start at the baseline, so it usually lasts the rest of the run; other failures meanwhile leave it refused; it is retried every 5 minutes and as soon as a poll reads the newest entry again, resumed follows if a read succeeds, and heartbeats say "logs: unavailable (size)"), when a burst outran the poller (gap, with the unread window), and once when the watch ends (stopped, with counts of what was read, emitted and excluded). Known chronic noise is dropped before categories apply: delivery-api-disabled (the Delivery API index populator's "not enabled" line), ready-probe-upgrading (the umbraco-ready health check failing with "Level: Upgrading" while migrations run) and automate-workflow-lock-pk (SQL 2627 on PK_umbracoAutomateWorkflowLock); --logs-keep turns one off, --logs-exclude adds more. Log lines never change phases or the exit code, and the monitor stops with the watch.

--uda-dir checks schema tripwires, using the same comparison as 'deploy status'. At baseline every artifact is compared: the drifted and missing-remote ones are what this deploy should change and are tracked; in-sync ones are counted; unknown and error ones (Automate artifacts where the Automate API is unreachable, as on non-live environments behind basic auth) are listed as unverifiable and never counted as in sync or failed. After landing the tracked artifacts are re-checked each poll, with a "schema" line per status change. Umbraco Deploy applies schema in its own pass after the app is serving, logging its start and its end (Work Status "Completed"), so an artifact still at baseline before then is expected; "schema-pass" lines report the pass starting and ending as read from the log (entries of the new process only), and "waiting" once when only the schema is holding verified back. Verified waits until every tracked artifact is in sync, or the pass has ended and a re-check after it has a definitive answer for each (an unreadable one gets three tries, then counts as unknown). If the pass end never shows up, verified never comes and the watch times out (exit 6): success is not inferred from silence. A "schema-summary" line closes the stream with confirmed, unconfirmed (still drifted or missing), unknown and unverifiable artifacts. When the environment is verified but tracked artifacts are still drifted or missing after the pass ended, or the pass ended with another work status than Completed, the watch exits 7, the documented code for drifted or missing entities (Deploy can skip artifacts without failing the pass).

| Flag | Type | Default | Description |
|------|------|---------|-------------|
| `--escalation` | duration | 10m0s | Treat sustained downtime or post-landing health failure longer than this as failed (exit 5) |
| `--health-path` | stringArray | [] | Public path that must return 2xx for the serving/verified phases (repeatable; default /). A redirect to a login page counts as unhealthy: on a basic-auth protected environment (Umbraco Cloud non-live) set basicAuthSharedSecret in the profile |
| `--heartbeat` | duration | 1m0s | Interval for still-alive lines: text on stderr, and with --json also a "heartbeat" NDJSON line on stdout; on their own clock, so they keep coming while a request is slow; 0 disables |
| `--interval` | duration | 5s | Poll interval |
| `--json` | bool | false | Emit phase transitions, heartbeats and the other lines as NDJSON |
| `--logs` | bool | false | Also emit the log entries a deploy produces (type "log"): app start/stop, migrations and upgrades, Examine indexer suspend/resume/rebuild, Umbraco Deploy entries, and anything at --logs-level or above; known noise is excluded (see --logs-keep). They never change phases or the exit code, and stop with the watch |
| `--logs-exclude` | stringArray | [] | Drop entries whose message, source context or exception contains this text, case-insensitive (repeatable), on top of the built-in exclusions |
| `--logs-keep` | stringArray | [] | Turn off a built-in exclusion so its entries are emitted: delivery-api-disabled, ready-probe-upgrading, automate-workflow-lock-pk, or all (repeatable) |
| `--logs-level` | string | Error | Lowest level emitted whatever the category (Verbose, Debug, Information, Warning, Error, Fatal) |
| `--logs-match` | stringArray | [] | Also emit entries whose message, source context or exception contains this text, case-insensitive (repeatable; category "match") |
| `--public-url` | string | — | Public host for health paths when it differs from the management base URL |
| `--request-timeout` | duration | 0s | Give up on any one request after this long; that signal counts as unknown (a health path as failing) for the poll. Must be shorter than --interval and --heartbeat; default half of the shorter of the two, between 250ms and 15s (2.5s with the defaults) |
| `--restart-min-down` | duration | 20s | When the log viewer refuses to read the process id, one outage of the management endpoint must last at least this long to count as the restart that lands the deploy, measured from its first to its last failed probe (at least two), so it is a lower bound on the downtime: a restart must last this plus up to two --interval gaps to be measured. Shorter outages are blips. Default 20s, or twice --interval when that is longer; a value must be longer than --interval (or 0 to count any outage) and shorter than --escalation |
| `--settle` | duration | 1m30s | How long the environment must stay healthy after everything first looks good before verified is emitted; 0 disables (single-sample verification) |
| `--skip-index-verify` | bool | false | Do not require Examine indexes to be healthy for the verified phase |
| `--timeout` | duration | 30m0s | Give up after this long without verification (exit 6, status unknown) |
| `--uda-dir` | string | — | Check schema tripwires: the .uda artifacts here (the site repo's umbraco/Deploy/Revision) that are drifted or missing on the target at baseline are re-checked after landing; verified waits until they are in sync or Umbraco Deploy's schema pass has ended, and exits 7 if any is still drifted or missing then |

## Mutation Commands

> **Safety:** Always use `--dry-run` first. Remove the flag only after verifying the dry-run output.

| Command | Description |
|---------|-------------|
| `deploy apply` | Apply local .uda deploy artifacts to the environment (Deploy's "Update schema" from the CLI) |
| `deploy queue add <id> [<id>…]` | Queue content for transfer (the backoffice's "Queue for transfer") |
| `deploy queue clear` | Empty the transfer queue |
| `deploy queue remove <id-or-udi>` | Remove one item from the transfer queue |
| `deploy transfer --node <id> [--node <id>…] [--descendants] | --queue` | Transfer content to the next environment with Umbraco Deploy (the backoffice's "Transfer now" / "Transfer queue") |

### apply

```bash
umbraco deploy apply
```

Makes the target environment's schema match the Umbraco Deploy artifacts in --uda-dir: the write side of 'deploy status'. Every artifact is first compared exactly as 'deploy status' does; in-sync artifacts are skipped, missing ones are created (with the artifact's GUID, so references keep resolving), drifted ones are updated with a full replacement built from the artifact — the same semantics as Deploy's schema pass.

Writes run in dependency order (Deploy's Ordering dependencies, then kind precedence: languages → folders → data types → templates → member/media/document types → member groups). Content-type references to items that come later in the same plan (allowed children, compositions) are deferred and re-applied in a fix-up pass once the referenced types exist. After every write the entity is re-read and compared again; a write the server accepted but that still drifts is reported as such, never as success.

Supported kinds: language, data-type(+folders), document-type/media-type/member-type(+folders), template, member-group. Relation types and Automate artifacts are read-only in the Management API and are listed as unsupported. Mutating: refuses to run without --dry-run (plan only, no writes; the plan includes the exact request bodies with --bodies) or --force. Every updated entity is backed up first (see --backup-dir).

From albanistrefi/umbraco_CLI, MIT.

More from albanistrefi/umbraco_CLI

Signals

Stars
4
Forks
0
Open issues
0
Last commit (this folder)
Oct 22, 2026 (7 days ago)
Last release
Oct 22, 2026 (7 days ago)

From GitHub (fetched Oct 24, 2026).

Details

Version
0.5.5
License
MIT
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from albanistrefi

Cite this page

umbraco-deploy skill. Agent Mart. https://agentmart.dev/skills/albanistrefi-umbraco-deploy (last updated 2026-10-24)