# gz agent sync control-surfaces

Regenerate agent control surfaces and skill mirrors from canonical governance state.

## Usage

```bash
gz agent sync control-surfaces [--dry-run]
```

## Determinism Contract

For unchanged inputs, sync emits a deterministic updated-path list and stable operator output.

## Fail-Closed Canonical Preflight

Before any mirror propagation, sync validates canonical `.gzkit/skills` integrity.

Blocking preflight failures include:

- missing canonical skill directories (without a legacy bootstrap candidate),
- missing `SKILL.md`,
- missing or invalid `SKILL.md` frontmatter identity fields,
- stale `last_reviewed` values older than policy threshold (90 days),
- invalid/missing deprecation metadata for `deprecated` or `retired` skills.

On failure, sync exits non-zero and prints recovery steps.

## Recovery Behavior (Non-Destructive)

Sync copies canonical files into mirrors but does not auto-delete mirror-only stale content.

When stale mirror-only paths exist, sync:

1. completes successfully,
2. emits a recovery warning with stale paths,
3. prints the manual cleanup protocol.

Related policy in `gz skill audit`:

- stale mirror-only paths are reported as non-blocking warnings
  (`SKA-MIRROR-DIR-UNEXPECTED`) by default,
- `--strict` escalates those warnings to blocking failures.

Manual recovery protocol:

```bash
uv run gz skill audit --json
# remove listed stale mirror-only paths
uv run gz agent sync control-surfaces
uv run gz skill audit
```

## Local vs Repo Config

Claude Code uses two settings files:

| File | Tracked | Contents |
|------|---------|----------|
| `.claude/settings.json` | Yes | Hooks, plugins — shared policy generated by sync |
| `.claude/settings.local.json` | No | Permissions, timeouts — machine-local convenience |

**Separation model:** `settings.json` is generated and deterministic. Local
overrides (allowed commands, domain allowlists, timeouts) go in
`settings.local.json`, which is `.gitignore`-d so each workstation can
customise without polluting shared policy.

**Example file:** `.claude/settings.local.example.json` shows the
permissions-only structure. Copy it to `settings.local.json` and edit.

**Drift detection:** After sync, call `detect_claude_settings_drift()` (from
`gzkit.sync`) to compare the on-disk `settings.json` against the generator
output. Returns a list of human-readable differences (empty = no drift).

## Examples

```bash
# Preview targets only
uv run gz agent sync control-surfaces --dry-run

# Apply sync and view recovery warnings (if any)
uv run gz agent sync control-surfaces
```
