Session log: CLAUDE.md optimization + python3/py fix
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -64,23 +64,19 @@ API_KEY=$(sops -d D:/vault/msp-tools/syncro.sops.yaml | py -c "import sys,yaml;
|
|||||||
- `contact_id` (customer contact)
|
- `contact_id` (customer contact)
|
||||||
- `ticket_type_id` (ticket category)
|
- `ticket_type_id` (ticket category)
|
||||||
|
|
||||||
#### Comments (with optional time entry)
|
#### Comments
|
||||||
|
|
||||||
| Operation | Method | Endpoint | Body |
|
| Operation | Method | Endpoint | Body |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| Add comment | POST | `/tickets/<id>/comment` | `{"subject": "Update", "body": "...", "hidden": false, "do_not_email": false}` |
|
| Add comment | POST | `/tickets/<id>/comment` | `{"subject": "Update", "body": "...", "hidden": false, "do_not_email": false}` |
|
||||||
| Add comment + time | POST | `/tickets/<id>/comment` | Same as above, PLUS: `"product_id": N, "minutes_spent": 60, "bill_time_now": false` |
|
|
||||||
|
|
||||||
**Comment fields:**
|
**Comment fields:**
|
||||||
- `subject` — comment header (e.g., "Update", "Resolution", "Internal Note")
|
- `subject` — comment header (e.g., "Update", "Resolution", "Internal Note")
|
||||||
- `body` — comment text (HTML supported)
|
- `body` — comment text (HTML supported)
|
||||||
- `hidden` — if true, internal-only (customer can't see)
|
- `hidden` — if true, internal-only (customer can't see)
|
||||||
- `do_not_email` — if true, don't email customer about this comment
|
- `do_not_email` — if true, don't email customer about this comment
|
||||||
- `product_id` — labor product ID (see labor products table below). Adds billable time to the ticket.
|
|
||||||
- `minutes_spent` — integer, minutes of work (60 = 1hr minimum in most cases)
|
|
||||||
- `bill_time_now` — if true, immediately creates a charge (equivalent to "Charge now" checkbox in GUI)
|
|
||||||
|
|
||||||
**This is the primary way to log time.** Comment + time in one call mirrors the GUI workflow exactly. Timer entries (`/tickets/{id}/timer_entry`) exist but are rarely used.
|
**WARNING:** The comment endpoint accepts but silently ignores `product_id`, `minutes_spent`, and `bill_time_now` fields — they are not saved. Verified 2026-04-20. Always use the timer_entry endpoint to log time.
|
||||||
|
|
||||||
#### Customers
|
#### Customers
|
||||||
|
|
||||||
@@ -144,17 +140,35 @@ When showing ticket detail, include:
|
|||||||
|
|
||||||
### Billing workflow
|
### Billing workflow
|
||||||
|
|
||||||
|
**ALWAYS ask the user for minutes and labor type before logging any time entry. Never assume a default.**
|
||||||
|
**ALWAYS show a preview of the ticket comment/notes to the user before posting. Wait for confirmation.**
|
||||||
|
|
||||||
When `/syncro bill <number>` is called:
|
When `/syncro bill <number>` is called:
|
||||||
1. Get ticket details
|
1. Get ticket details
|
||||||
2. Ask: "How many minutes + labor type?" (default: 60 min, Labor - Remote Business)
|
2. Ask: "How many minutes should I bill, and what labor type? (remote / onsite / emergency / project / internal)"
|
||||||
3. Add comment with time: `POST /tickets/{id}/comment` with `product_id`, `minutes_spent`, `bill_time_now: false`, and work notes as body
|
3. Draft the comment body and show it to the user for review before posting
|
||||||
4. Then create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}`
|
3. Add comment: `POST /tickets/{id}/comment` with work notes as body (no time fields — they are broken)
|
||||||
5. Update ticket status to "Invoiced"
|
4. Add timer entry: `POST /tickets/{id}/timer_entry` with `start_at`, `end_at`, `billable: true`, `product_id`, `notes`
|
||||||
|
5. Create invoice: `POST /invoices` with `{"ticket_id": N, "customer_id": N, "category": "Standard"}`
|
||||||
|
6. Update ticket status to "Invoiced"
|
||||||
|
|
||||||
**The flow mirrors the GUI: add comment with time attached → Make Invoice.**
|
**Correct two-call pattern for comment + time:**
|
||||||
|
```bash
|
||||||
|
# Step 1: comment (notes only)
|
||||||
|
curl -X POST "${BASE}/tickets/${ID}/comment?api_key=${API_KEY}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{"subject": "Resolution", "body": "...", "hidden": false, "do_not_email": true}'
|
||||||
|
|
||||||
|
# Step 2: timer entry (billable time) — compute start_at as end_at minus minutes
|
||||||
|
NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
START=$(date -u -d "60 minutes ago" +"%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
curl -X POST "${BASE}/tickets/${ID}/timer_entry?api_key=${API_KEY}" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{\"start_at\": \"${START}\", \"end_at\": \"${NOW}\", \"notes\": \"...\", \"billable\": true, \"product_id\": 1190473}"
|
||||||
|
```
|
||||||
|
|
||||||
When `/syncro comment <number> <text> --time 60 --labor remote` is called:
|
When `/syncro comment <number> <text> --time 60 --labor remote` is called:
|
||||||
- Post the comment with time in one API call
|
- Post the comment first, then post a separate timer_entry
|
||||||
- `--labor` maps to product IDs: `remote` → 1190473, `onsite` → 26118, `emergency` → 26184, `project` → 9269129, `internal` → 9269124, `travel` → 26117, `website` → 68055
|
- `--labor` maps to product IDs: `remote` → 1190473, `onsite` → 26118, `emergency` → 26184, `project` → 9269129, `internal` → 9269124, `travel` → 26117, `website` → 68055
|
||||||
|
|
||||||
### Error handling
|
### Error handling
|
||||||
|
|||||||
@@ -257,6 +257,54 @@ Refactored `.claude/CLAUDE.md` to reduce context window pressure. Extracted verb
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Update: 19:48 UTC — Python Fix + CLAUDE.md Continued
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
|
||||||
|
Fixed Windows python3 Store alias errors (exit code 49) burning tokens on every Python call. Also committed previous CLAUDE.md optimization work.
|
||||||
|
|
||||||
|
### Root Cause
|
||||||
|
|
||||||
|
Windows Store app execution aliases for `python.exe` and `python3.exe` were intercepting calls and returning exit 49 instead of running Python. Fix was two-part:
|
||||||
|
1. Code: replace `python3` with `py` (Windows launcher) or `jq` throughout all scripts/docs
|
||||||
|
2. System: Mike disabled the Store aliases in Settings > Apps > Advanced app settings > App execution aliases
|
||||||
|
|
||||||
|
### Files Changed
|
||||||
|
|
||||||
|
**ClaudeTools repo (936ea49):**
|
||||||
|
- `.claude/OLLAMA.md` — reachability check: `python -c` → `jq -r`, one-liner: `python3` → `py`
|
||||||
|
- `.claude/commands/syncro.md` — `python` → `py`
|
||||||
|
- `.claude/scripts/sync.sh` — fallback loop: `python3 python` → `py python3 python`; also updated error message
|
||||||
|
- `.claude/skills/1password/references/op_commands.md` — all `python3` → `py`; JSON one-liners → `jq`
|
||||||
|
- `.claude/skills/1password/references/secret_references.md` — all `python3` → `py`; field list → `jq`
|
||||||
|
- `.claude/skills/1password/scripts/check_setup.sh` — vault list: `python3` → `jq`
|
||||||
|
- `.claude/skills/1password/scripts/env_from_op.sh` — item lists → `jq`; vault/title extraction → `jq`; heredoc: `python3 -` → `py -`
|
||||||
|
- `.claude/skills/1password/scripts/store_secret.sh` — item ID + vault name extraction: `python3` → `jq`
|
||||||
|
- `.claude/skills/remediation-tool/scripts/get-token.sh` — fallback loop: `python3 python py` → `py python python3`
|
||||||
|
- `.claude/DATABASE_FIRST_PROTOCOL.md` — `python -c` → `jq -r`
|
||||||
|
- `.claude/settings.local.json` — added `"Bash(py:*)"` to allowlist
|
||||||
|
|
||||||
|
**Vault repo (4590370):**
|
||||||
|
- `scripts/vault.sh` — fallback loop: `python python3 py` → `py python python3`
|
||||||
|
|
||||||
|
### Python State on DESKTOP-0O8A1RL
|
||||||
|
|
||||||
|
| Command | Status |
|
||||||
|
|---|---|
|
||||||
|
| `python3` | BROKEN — Store alias disabled, now fails cleanly |
|
||||||
|
| `python` | BROKEN — Store alias disabled |
|
||||||
|
| `py` | WORKS — Windows launcher at `C:\Windows\py.exe` |
|
||||||
|
| `jq` | WORKS — `C:\Users\guru\AppData\Local\Microsoft\WinGet\Links\jq.exe` |
|
||||||
|
| Python install | `C:\Program Files\Python314\python.exe` (also Python312 in user AppData) |
|
||||||
|
|
||||||
|
### Memory Saved
|
||||||
|
|
||||||
|
Added `feedback_python_windows.md` to `.claude/memory/`: use `py` not `python3`, prefer `jq` for JSON.
|
||||||
|
|
||||||
|
### No Credentials / No Pending Items from This Update
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Key Infrastructure Reference
|
## Key Infrastructure Reference
|
||||||
|
|
||||||
| Resource | Details |
|
| Resource | Details |
|
||||||
|
|||||||
Reference in New Issue
Block a user