ios-log-diagnose
SkillMonitoring & opsDrive the UniClipboard iOS app in a simulator and read its OSLog yourself to diagnose a mobile-sync bug, instead of asking the user to paste logs. Use when debugging why the iOS sync engine or M5 reducer did something, reproducing an iOS sync / clipboard bug on the simulator, or whenever you'd otherwise ask the user "what do the logs say". All output is Swift OSLog under subsystem `app.uniclipboard` — the Rust core (uc-mobile) emits no logs of its own; the Swift shell logs the reducer's decisions.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the ios-log-diagnose skill
What this skill tells your AI
The instructions your AI receives, as published by uniclipboard/uniclipboard in .agents/skills/ios-log-diagnose/SKILL.md and read by ahel’s review.
Read the UniClipboard iOS app's logs yourself. The mobile-sync decision core lives in Rust (uc-mobile reducer), but it has no logger — the Swift SyncEngine shell logs every reducer decision and outcome to OSLog. So one OSLog stream shows both the native Swift logic and the Rust core's behavior.
iOS app repo: /Users/mark/MyProjects/iOSApp/UniClipboard. The reducer-path log harness lives in UniClipboard/Sync/SyncEngine.swift (commit e94ffd1).
The helper is .agents/skills/ios-log-diagnose/ios-logs.sh — the only thing to invoke. Don't hand-roll simctl/log pipelines unless it can't express what you need (macOS has no timeout; the script wraps log stream in a perl alarm — reproducing that by hand is the usual mistake).
Two channels — pick by what you're after
Log level decides where a line goes. This split is the whole mental model:
debug→ live only, never persisted. The per-tick decision trace:sync preamble: proceed/stop(...),sync route: converged/server-new/push(...), push silent-skip. Seen ONLY by streaming while it happens. Use to watch what the reducer decides each tick.notice/error→ persisted, queryable after the fact. The event trail:sync apply/stage/push/consent-push,sync history: round done, the fivehandle_*transitions, andtick: SyncError .... Use to reconstruct what already happened.
So: streaming a reproduction answers "what is it deciding right now"; show answers "what happened in the last N minutes".
Steps
-
Drive — boot a sim, install the newest build, inject the Rust-core flag ON + an active server, launch:
.agents/skills/ios-log-diagnose/ios-logs.sh drive [SERVER_URL]The engine only ticks with an active server, so
drivealways injects one. A dead URL (the default) still exercises preamble → proceed →getClipboardfails →tick: SyncError→ backoff — enough to see decisions + the error path. For the happy path (route/apply/push/converge), pass aSERVER_URLthat actually returns data (a runninguniclipdmobile-sync server). Completion: the command printsinjected: flag=ON server=...and a launch PID. -
Read — choose the channel:
.agents/skills/ios-log-diagnose/ios-logs.sh stream [SECONDS] [CATEGORY] # live debug, default 15s .agents/skills/ios-log-diagnose/ios-logs.sh show [DURATION] [CATEGORY] # persisted notice/error, default 5mCATEGORY(optional):sync(SyncEngine — reducer + tick; the usual one),network(HTTP client / connect-uri),store(persistence),app,intents. Omit for every category underapp.uniclipboard. Completion: you have thesync(or target) lines for the run you triggered, and can name what the reducer decided / what failed.
Gotchas
- No content, ever. Logs carry states / bools / counts / decision enums plus an 8-char
hashTagprefix — a one-way SHA fingerprint that correlates one clipboard item across pull → stage → apply → push → converge, never the content. - Flag injection is forward-safe.
drivewritesmobileCore.syncClientUsesRustCore = YES. Once the native A/B paths are deleted and Rust is the only path, that key just goes unread — the script keeps working unchanged. - App Group, not the app sandbox. Flag + server live in
defaultssuitegroup.app.uniclipboard.UniClipboard; injecting them needs aterminate+launchsoloadServersre-reads.drivehandles this. - More injection hooks exist.
grep ProcessInfo.processInfo.environmentin the iOS repo forUC_*(e.g.UC_DEVICE_TEXTto seed a device copy,UC_TEST_QR_PAYLOADto add a server via connect-uri) — passed throughSIMCTL_CHILD_<NAME>=valueon launch. - Build first if
drivesays "no built UniClipboard.app":xcodebuild -scheme UniClipboard -sdk iphonesimulator -destination 'generic/platform=iOS Simulator' build CODE_SIGNING_ALLOWED=NO.
Signals
- GitHub stars
- 2k
- Forks
- 76
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
ios-log-diagnose- Source
- github.com/uniclipboard/uniclipboard