$npx -y skills add deepklarity/harness-kit --skill hk-local-logsInspect and debug errors via logs across the harness-kit monorepo. Reads the right log file based on the error layer — backend, frontend, celery, odin CLI, or odin task execution. Use this skill whenever someone mentions a 500 error, a stack trace, a crash, 'check the logs', 'wha
| 1 | # /hk-local-logs — Log Inspector & Error Debugger |
| 2 | |
| 3 | Read the right log for the right problem, from the right place. No more guessing which of 5 log locations to check. |
| 4 | |
| 5 | ## Quick Reference |
| 6 | |
| 7 | | Symptom | Log to check | Command | |
| 8 | |---------|-------------|---------| |
| 9 | | 500 error, API broken | Backend | `/hk-local-logs backend` | |
| 10 | | UI not loading, build error | Frontend | `/hk-local-logs frontend` | |
| 11 | | Task not executing, queue stuck | Celery | `/hk-local-logs celery` | |
| 12 | | `odin plan`/`odin exec` failed | Odin | `/hk-local-logs odin` | |
| 13 | | Specific task execution trace | Task | `/hk-local-logs task <id>` | |
| 14 | | Migration error on startup | Backend | `/hk-local-logs backend --search migrate` | |
| 15 | | Don't know where the error is | Auto | `/hk-local-logs` (no args) | |
| 16 | |
| 17 | ## Arguments |
| 18 | |
| 19 | Parse `$ARGUMENTS` to extract: |
| 20 | - **layer** (optional): `backend`, `frontend`, `celery`, `odin`, or `task` |
| 21 | - **id** (required for `task`): task ID or prefix |
| 22 | - **--lines N** (optional, default 50): how many lines from the end to show |
| 23 | - **--search <pattern>** (optional): grep for a pattern in the log |
| 24 | |
| 25 | If no layer is specified, run **auto-detect mode** — check all logs for recent errors. |
| 26 | |
| 27 | ## Log Locations |
| 28 | |
| 29 | All paths are relative to `REPO_ROOT` (use `git rev-parse --show-toplevel`). |
| 30 | |
| 31 | | Layer | File | Format | Notes | |
| 32 | |-------|------|--------|-------| |
| 33 | | **backend** | `.dev-logs/backend.log` | Plain text | Django runserver stdout/stderr | |
| 34 | | **frontend** | `.dev-logs/frontend.log` | Plain text | Vite dev server output | |
| 35 | | **celery** | `.dev-logs/celery.log` | Plain text | Celery worker + beat | |
| 36 | | **backend-app** | `taskit/taskit-backend/logs/taskit.log` | Structured plain text | App-level logging, `[timestamp] LEVEL [file:line] - msg` | |
| 37 | | **backend-detail** | `taskit/taskit-backend/logs/taskit_detail.log` | Plain text | Full tracebacks (check here for exception details) | |
| 38 | | **odin-runs** | `.odin/logs/run_*.jsonl` (in working dir) | JSON lines | Structured orchestration log | |
| 39 | | **odin-app** | `.odin/logs/odin.log` (in working dir) | Plain text | Odin CLI logging | |
| 40 | | **odin-detail** | `.odin/logs/odin_detail.log` (in working dir) | Plain text | Full tracebacks from odin (`odin logs debug`) | |
| 41 | | **task-output** | `.odin/logs/task_<id>.out` (in working dir) | Plain text | Raw agent stdout for a task (`odin logs <id> -f`) | |
| 42 | |
| 43 | ## Execution |
| 44 | |
| 45 | ### Step 1: Resolve paths |
| 46 | |
| 47 | ```bash |
| 48 | REPO_ROOT=$(git rev-parse --show-toplevel) |
| 49 | ``` |
| 50 | |
| 51 | Odin logs live in the **working directory** where odin was run, not the repo root. The standard working dir is `$REPO_ROOT/odin/temp_test_dir/`. Check both. |
| 52 | |
| 53 | ### Step 2: Read the log |
| 54 | |
| 55 | Based on the layer argument: |
| 56 | |
| 57 | #### `backend` (or auto-detect first choice for 500 errors) |
| 58 | |
| 59 | Check two locations — `.dev-logs/backend.log` has startup/crash output, `taskit-backend/logs/taskit_detail.log` has full tracebacks: |
| 60 | |
| 61 | ```bash |
| 62 | # Recent backend output (startup errors, migration failures) |
| 63 | tail -n $LINES "$REPO_ROOT/.dev-logs/backend.log" |
| 64 | |
| 65 | # Full tracebacks from app logging (the real errors) |
| 66 | tail -n $LINES "$REPO_ROOT/taskit/taskit-backend/logs/taskit_detail.log" |
| 67 | ``` |
| 68 | |
| 69 | **When debugging 500s**: The `taskit_detail.log` has full exception tracebacks. The `.dev-logs/backend.log` has Django's console error output. Check both — the detail log is usually more informative. |
| 70 | |
| 71 | Also check if the migration is current: |
| 72 | ```bash |
| 73 | cd "$REPO_ROOT/taskit/taskit-backend" && python manage.py showmigrations tasks 2>&1 | grep '\[ \]' |
| 74 | ``` |
| 75 | If unapplied migrations exist, that's likely the cause. |
| 76 | |
| 77 | #### `frontend` |
| 78 | |
| 79 | ```bash |
| 80 | tail -n $LINES "$REPO_ROOT/.dev-logs/frontend.log" |
| 81 | ``` |
| 82 | |
| 83 | Look for: TypeScript errors, Vite build failures, module resolution errors. |
| 84 | |
| 85 | #### `celery` |
| 86 | |
| 87 | ```bash |
| 88 | tail -n $LINES "$REPO_ROOT/.dev-logs/celery.log" |
| 89 | ``` |
| 90 | |
| 91 | Look for: `Task exception`, `WorkerLostError`, broker connection failures. |
| 92 | |
| 93 | #### `odin` |
| 94 | |
| 95 | Check the most recent structured run log: |
| 96 | |
| 97 | ```bash |
| 98 | # Find latest run log |
| 99 | ODIN_WD="$REPO_ROOT/odin/temp_test_dir" |
| 100 | LATEST=$(ls -t "$ODIN_WD/.odin/logs/run_"*.jsonl 2>/dev/null | head -1) |
| 101 | |
| 102 | # Show structured entries (formatted) |
| 103 | if [ -n "$LATEST" ]; then |
| 104 | tail -n $LINES "$LATEST" | python3 -c " |
| 105 | import sys, json |
| 106 | for line in sys.stdin: |
| 107 | try: |
| 108 | e = json.loads(line.strip()) |
| 109 | ts = e.get('timestamp','')[:19] |
| 110 | action = e.get('action','') |
| 111 | tid = (e.get('task_id','') or '')[:8] |
| 112 | agent |