Browse Source

chore: sync Scout skills 2026-09-14

main
Daniel Kucinski 4 weeks ago
parent
commit
e7f044e525
  1. 113
      teams-export/SKILL.md

113
teams-export/SKILL.md

@ -205,6 +205,111 @@ Conventions:
- Timestamps in America/Los_Angeles, 24-hour. - Timestamps in America/Los_Angeles, 24-hour.
- Separate root messages with a horizontal rule (`---`). - Separate root messages with a horizontal rule (`---`).
### Auto-nominate new sources (opt-in, read-only)
Off by default. The caller enables it (`nominate: true`); ad-hoc `/teams-export`
runs should leave it off so they stay fast. The nightly archive automation
turns it on.
Purpose: `sources.yaml` is an allowlist, so its failure mode is **silent
omission** — a new important thread archives nothing and the user never finds
out. This pass closes that gap by surfacing candidates for a one-line opt-in.
**This pass NEVER edits `sources.yaml`.** It only reports.
Run it *after* the export pass, so a failed export never costs the user their
nominations (and vice versa).
**Steps:**
1. Build the set of known identifiers from `sources.yaml`: every `chat_id` and
`channel_id` from all three sections — **including entries with
`enabled: false`**. A deliberately-retired source must never come back as a
nomination.
2. **Resolve `oneOnOne` entries that have no cached `chat_id`.** Several entries
are identified only by `email`, so they have no ID to match against and will
be falsely nominated as "new" unless handled. For every 1:1 candidate, get
the other participant's email — call `workiq_list_chats` with
`expand: "members"`, or `workiq_get_chat` on the candidate — and treat the
chat as known if that email matches an `email` in `sources.yaml`
(case-insensitive). When you resolve one this way, report its `chat_id` in
the run summary under the existing "newly resolved 1:1 chat_id" item, so the
user can cache it and remove the ambiguity permanently.
3. Read the optional top-level `ignore:` list (entries with `chat_id` or
`channel_id`). Treat everything in it as known. A missing or empty `ignore:`
is normal — don't error.
4. Call `workiq_list_chats` ordered by most recent activity, paging with
`skipToken` until you reach chats whose last activity predates the run
window. Don't page further back than the window. Filter on
`lastUpdatedDateTime` first — this is what removes the long tail of dormant
chats before you spend any calls counting messages.
5. For each chat not in the known set, count messages inside the run window.
Nominate only if **≥5 messages** land in the window — this is what keeps the
single-reply meeting chats out. Skip any chat whose in-window messages are
all system/bot events (joins, leaves, call records, recording notices) with
no human authorship.
6. Load the state file (below) and apply the repeat rules.
7. Report survivors in the run summary.
**State file:** `D:\Repos\Obsidian\00 - Chats\.nominations.json`
The one file this skill may write outside the monthly export folders. Shape:
```json
{
"19:meeting_abc...@thread.v2": {
"topic": "Patch Plan V-Team Sync",
"first_seen": "2026-09-14",
"last_reported": "2026-09-14",
"times_reported": 1
}
}
```
**Repeat rules** — these exist so the pass never becomes nagging:
- Report a candidate the first time it's seen.
- Re-report only if it's still unlisted, still active, and ≥7 days since
`last_reported`.
- After `times_reported` reaches **3**, stop reporting it permanently. Keep the
record so it isn't re-nominated from scratch later.
- Prune records for chats that have since been added to `sources.yaml` or
`ignore:`, so re-adding a source later starts the count fresh.
If the state file is missing or unparseable, treat it as empty and rewrite it —
never let a bad state file abort the run.
**Report shape** — give the user something they can paste, and say *why* it
was nominated:
```
Nominated (not in sources.yaml):
• "Patch Plan V-Team Sync" — 23 msgs since 09-07, 4 participants (1st time seen)
- alias: patch-plan-vteam
type: group
chat_id: "19:meeting_abc...@thread.v2"
topic: Patch Plan V-Team Sync
• "Lee/Daniel Chat" — 8 msgs since 09-07 (reported 2x, will stop after 1 more)
- alias: lee-daniel
type: group
chat_id: "19:...@thread.v2"
To silence one permanently, add its chat_id under `ignore:` in sources.yaml.
```
Suggest a kebab-case `alias` derived from the topic or participant names, and
check it doesn't collide with an existing alias — aliases are filenames and must
stay unique.
**Topics are not unique.** Distinct chats routinely share a topic (Daniel's
tenant currently has two separate `Patch Plan V-Team Sync` meeting chats with
different `chat_id`s). Never assume topic identifies a chat. Always key state,
dedup, and known-set matching on `chat_id` / `channel_id`. When two candidates
in the same report share a topic, disambiguate the suggested aliases with a date
or sequence suffix (e.g. `patch-plan-vteam-2026-09`) and say plainly in the
report that these are two different chats, so the user doesn't assume it's a
duplicate and opt in only one.
### Run summary ### Run summary
After every run, print a short summary to the user: After every run, print a short summary to the user:
@ -214,11 +319,15 @@ After every run, print a short summary to the user:
- Any errors - Any errors
- **Any newly resolved 1:1 `chat_id` values** (so the user can paste them into - **Any newly resolved 1:1 `chat_id` values** (so the user can paste them into
`sources.yaml` to skip the lookup next time) `sources.yaml` to skip the lookup next time)
- **Nominations**, if the nominate pass ran and produced any (see above)
### Guardrails ### Guardrails
- Never write outside `D:\Repos\Obsidian\00 - Chats\`. - Never write outside `D:\Repos\Obsidian\00 - Chats\`. The only non-export file
- Never edit `sources.yaml`. this skill may write is `00 - Chats\.nominations.json` (nominate-pass state).
- **Never edit `sources.yaml`** — not to add a nominated source, not to prune a
dead one, not to update `ignore:`. Report and let the user decide. This is the
boundary that keeps the allowlist trustworthy.
- Respect MIP sensitivity labels — if a source surfaces classified content, - Respect MIP sensitivity labels — if a source surfaces classified content,
note it in the run summary so the user knows the output file inherits that note it in the run summary so the user knows the output file inherits that
sensitivity. sensitivity.

Loading…
Cancel
Save