-
-
Notifications
You must be signed in to change notification settings - Fork 27
Debugging Guide
Pass -cotabby-debug as a launch argument in Xcode:
- Product > Scheme > Edit Scheme > Run > Arguments
- Add
-cotabby-debugto "Arguments Passed On Launch"
This enables CotabbyDebugOptions.isEnabled, which turns on:
- On-disk JSONL log sinks (see below) in addition to the always-on Console.app stream
- Detailed service-level logging (prompt input, raw model output, normalized output)
- Verbose focus-tracking diagnostics
Debug logging is gated so that user content never appears in production logs.
With -cotabby-debug enabled, Cotabby writes structured JSON-per-line logs that are designed to be filtered with jq:
-
~/Library/Logs/Cotabby/cotabby.jsonl— main event stream. All metadata (request IDs, engine names, token counts, latencies, error reasons) is flattened as top-level fields. -
~/Library/Logs/Cotabby/llm-io.jsonl— full LLM prompts and completions, one record per generation. Sharesrequest_idwith the main log so a single suggestion can be joined across files. -
~/Desktop/cotabby-ax-dump.txt— most recent Chrome AX tree snapshot. Overwritten on each Chrome focus change. - Rotated previous logs:
*.jsonl.1(one-step rotation at ~10 MB).
Correlation IDs. Every prediction gets a request_id like req_a3f9k2lq, stamped on every log line that touches that request. To pull the complete history of one suggestion:
jq 'select(.request_id == "req_a3f9k2lq")' ~/Library/Logs/Cotabby/cotabby.jsonl
jq 'select(.request_id == "req_a3f9k2lq")' ~/Library/Logs/Cotabby/llm-io.jsonlUseful recipes:
# Recent errors across the app
jq 'select(.level == "error")' ~/Library/Logs/Cotabby/cotabby.jsonl
# Llama generations slower than 500 ms
jq 'select(.engine == "llama" and .latency_ms > 500)' ~/Library/Logs/Cotabby/llm-io.jsonl
# Coordinator state transitions
jq 'select(.category == "suggestion" and .stage != null)' ~/Library/Logs/Cotabby/cotabby.jsonl
# Runtime model load/decode events
jq 'select(.category == "runtime")' ~/Library/Logs/Cotabby/cotabby.jsonlSymptom to category map (jump straight to the right filter):
- Ghost text didn't appear:
suggestion+focus - Wrong text inserted: look up the request in
llm-io.jsonl, then walksuggestionfor acceptance - Model won't load / decode fails:
runtime+models - Permission dialog loop:
app(permission state transitions) - Chrome-specific weirdness: start with
~/Desktop/cotabby-ax-dump.txt, thenfocus - Wrong backend chosen:
suggestionrouter selection log (engine,fallback_engine)
Console.app fallback (when -cotabby-debug wasn't set):
log show --predicate 'subsystem == "com.cotabby.app"' --last 10m
log stream --predicate 'subsystem == "com.cotabby.app"' --level debugWork through this decision tree:
1. Check the menu bar. Open Cotabby's menu - does the status say anything useful?
2. Is Cotabby disabled?
- Globally turned off? Check the "Enable Globally" toggle.
- App-disabled? The focused app may be in the disabled list. Check Settings > Disabled Apps.
- Terminal? Cotabby automatically blocks terminal emulators (
TerminalAppDetector). - Secure field? Cotabby refuses to operate on password fields.
- Missing permissions? Input Monitoring and Accessibility must both be granted.
All these checks live in SuggestionAvailabilityEvaluator.disabledReason().
3. Is the field recognized?
- Check
FocusSnapshot.capability- is it.supported? - If
.unsupportedor.blocked, the AX tree isn't exposing a usable text field. See App Compatibility Notes.
4. Is generation running?
- With
-cotabby-debug, check Xcode console for prompt/generation output. - If the model isn't loaded, check
LlamaRuntimeManagerbootstrap state in the menu bar.
5. Is the result being suppressed?
-
SuggestionTextNormalizerstrips empty or prefix-echoing output. -
SuggestionSessionReconcilerinvalidates sessions when editor content diverges from the expected state.
Check the caret geometry quality:
| Quality | Meaning | Accuracy |
|---|---|---|
.exact |
App provides precise BoundsForRange
|
Pixel-accurate |
.derived |
Computed from child frame geometry | Usually close |
.estimated |
Fallback from field frame | Approximate |
If .estimated, the host app doesn't expose precise caret bounds via Accessibility. Check AXTextGeometryResolver and GhostSuggestionLayout.
Two systems prevent this:
-
SuggestionTextNormalizerstrips leading text that echoes the prefix. -
SuggestionSessionReconcilerinvalidates sessions when the editor text has changed since generation started.
Check both if you see stale or repeated output.
-
Empty output: Check
-cotabby-debugconsole for the raw model response. The normalizer may be stripping everything. If the model returns thinking tokens (e.g.,<think>) the prompt should suppress them (seeLlamaPromptRenderer). -
Crashes: Check for
ggml_abortin the crash log - this usually means an oversized prompt exceeded the context window. Verify model file integrity withModelFileValidator.
Chrome and Electron apps recycle Accessibility node identifiers (CFHash values) between polls. This makes elementIdentifier unreliable for tracking which field is focused.
Cotabby works around this using processIdentifier + focusChangeSequence instead. If you're debugging focus identity issues in these apps, check:
-
SuggestionSessionReconciler- session continuity logic -
ContextBuffer- context accumulation across polls
-
Restart the app.
PermissionManagerchecks are cached at startup. - Check signing. When running from Xcode, your development team must be configured for entitlements to activate. If the app isn't properly signed, macOS may silently deny Accessibility access.
- Check System Settings. Verify Cotabby appears in Privacy & Security > Accessibility and Privacy & Security > Input Monitoring with checkmarks.