logs-start
SkillMonitoring & opsStart a VivaDicta log capture. Defaults to the simulator; takes sim, device, or structured to pick a tier.
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 logs-start skill
What this skill tells your AI
The instructions your AI receives, as published by n0an/vivadicta in .agents/skills/logs-start/SKILL.md and read by ahel’s review.
Start a log capture. Stop it with logs-stop, which
resolves the active tier on its own - you never have to name it again.
Argument
$ARGUMENTS selects the tier. Empty means sim.
| Argument | Tier | Reaches extensions? | Cost |
|---|---|---|---|
(empty) or sim | Simulator, live unified log | yes (all sim processes) | none |
device | Device, live stdout | no, main app only | none |
structured | Device, unified log archive | yes | interactive sudo, large archive |
Anything else: say what was passed, list the three, and stop. Do not guess.
When invoked with no argument, start the simulator capture as usual, then close your report with this reminder so the other tiers stay discoverable:
Started the simulator capture (default). Other tiers:
/logs-start devicefor live device stdout (main app only),/logs-start structuredfor the device unified log (the only tier that sees the keyboard and other extensions).
Do not ask which tier to use instead of starting - the default is the default. Only mention the alternatives after the capture is already running.
Choosing a tier
simis the default because it is free and the richest: real unified-log metadata, timestamps, levels, categories, threads.deviceis for hardware-only bugs. Live and cheap, but see the limitation below - it cannot see the keyboard or any other extension.structuredis the only tier that sees extensions on hardware. Reach for it when the keyboard, share, action, or widget target is involved, or for a post-mortem.logarchiveyou want to reopen in Console.app.
sim
mkdir -p logs- Run
./scripts/launch_simulator.shin a background/long-lived shell solog streamkeeps running. It also writeslogs/.sim-capture.pidnaming the streaming process, which is whatlogs-stopreads to end this capture and nothing else. - Report the
logs/sim-YYYYMMDD-HHMMSS.logpath the script prints.
Attaches to the already-booted Simulator; it does not relaunch the app, and it
fails if none is booted. Captures Logger output filtered to
subsystem == "com.antonnovoselov.VivaDicta"; raw print() is not included.
device
./scripts/launch_device.sh --checkfirst - it resolves device and bundle id without launching. Fix whatever it reports before continuing.mkdir -p logs- Run
./scripts/launch_device.shin a background/long-lived shell. It writeslogs/.device-capture.pidnaming thedevicectlprocess, which is whatlogs-stopreads. - Report the
logs/device-YYYYMMDD-HHMMSS.logpath.
Uses xcrun devicectl device process launch --console with
ENABLE_PRINT_LOGS=1. --terminate-existing restarts the app, so in-progress
state is lost.
Limitation: main app only, no extensions
--console pipes the stdout of the single process devicectl launched. Every
extension runs in its own system-spawned process, so devicectl never sees it.
Their output is absent entirely and nothing says so - you get a
complete-looking stream that is silently missing a target.
Measured: a capture during keyboard use carried 213 lines from VivaDicta/ and
0 from VivaDictaKeyboard/, though the keyboard logs from
KeyboardViewController, KeyboardTextProcessor and VivaModeManager. Use
structured for extensions.
Timestamps
Lines carry time, level and call site, because LoggerExtension's print mirror
stamps them itself:
19:09:40.709 [INFO] VivaDicta/AIService.swift:666 Loaded 1 Viva Modes
That is app-side, so it only appears in builds you install. Bare, unstamped lines mean the installed binary predates the print mirror - rebuild to the device rather than changing the capture. Category and thread are still absent; stdout has no room for unified-log metadata.
structured
Starts nothing - it only records where to collect from. logs-stop does the
work.
- Find the device:
xcrun xctrace list devices | grep iPhone | grep -v Simulator | head -1 mkdir -p llmtemp-
date '+%Y-%m-%d %H:%M:%S' > llmtemp/.device-log-start-time echo "<UDID>" > llmtemp/.device-log-udid - Report the start time and UDID, and warn that
logs-stopwill need interactivesudoand will write a large archive.
Why this tier reaches extensions: sudo log collect --device-udid pulls the
device's whole unified log, and extension lines survive the subsystem filter
because LoggerExtension.swift hardcodes one subsystem across all targets:
private nonisolated let kLoggingSubsystem = "com.antonnovoselov.VivaDicta"
That constant is load-bearing. If a target is ever changed to log under its own bundle id, it disappears from these captures silently.
Concurrent captures
sim and device can run at once; logs-stop handles all active tiers, reading
one marker file per tier. Do not start a second capture of the same tier - the
marker is overwritten, so the first stream is orphaned and its file stops
receiving the lines you expect.
The markers are why logs-stop never has to guess. It ends the tier that was
actually started, instead of matching simctl spawn.*log stream against the
machine and catching an unrelated log stream someone else is running.
Manual analysis
ls -lt logs/sim-*.log | head -5
grep -i "error\|fault" logs/sim-*.log
grep "\[AppState\]" logs/sim-*.log
log show logs/vivadicta_device_*.logarchive \
--predicate 'subsystem == "com.antonnovoselov.VivaDicta"'
Related
logs-stopxcodebuild-testingaxe-simulator-control- drive the simulator before capturing
Signals
- GitHub stars
- 112
- Forks
- 10
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
logs-start- Source
- github.com/n0an/vivadicta