daily-activity-log
Skill4 starsChanged 7 months agoMITView on GitHub
Scan work repos (git), calendar events, PG/engineering emails, and Teams chats (SSP + customer) to build a structured daily activity log in customer-engagements. Writes activity-log.md per project as the source of truth for CRM sync and engagement tracking. Triggers include: 'daily activity', 'activity log', 'log my work', 'what did I do', 'sync activity', 'daily sync', 'update activity log', or any request to capture the day's SE work into customer-engagements.
- Installs packages
In this repository11 other files it gives its agents.
- architectureSkill
- azure-answerSkill
- capture-meetingSkill
- connectSkill
- copilot-babysitterSkill
- crm-activity-syncSkill
- customer-repoSkill
- followupsSkill
- meeting-prepSkill
- msx-crmSkill
- sso-watcherSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
77 rules. About 0 are common, 50 are distinctive, and 27 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈50
Distinctive · estimate
This author's own choices. Worth a look.
27
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 25
Default to POSIX commands.
- Distinctive: line 29
Evidence-based only: Every logged activity must trace to a concrete artifact: a git commit, a calendar event, or a sent email.
- Distinctive: line 30
Aggregate per day: All evidence for a single customer + project + date is merged into one daily entry.
- Distinctive: line 32
Idempotent: If the log already contains an entry for the target date + project, skip it.
- Distinctive: line 33
Preserve source language: Commit messages, email subjects, and meeting titles stay in their original language.
- Distinctive: line 73
Before running, verify all dependencies are present.
- Distinctive: line 86
Check if each required skill is installed:
- Distinctive: line 116
Run the installer (idempotent — safe to re-run):
- Distinctive: line 126
Verify the required skills are now installed.
- Very specific: line 139
If CRM sync is desired, the helper script must exist at $HOME/.copilot/skills/msx-crm/crm-tools/run-tool.mjs.
- Distinctive: line 151
If missing and CRM sync is desired, clone the SE Kanban Tracker repo:
- Very specific: line 167
Check m_m365_status. If not signed in → call m_m365_sign_in.
- Distinctive: line 229
Not every project has a repo — some are meeting-only engagements.
- Very specific: line 261
Only scan chats for SSPs in config.core_ssps.
- Very specific: line 307
If domains is empty or missing, the customer is skipped during chat discovery.
- Very specific: line 312
Call m365_list_chats(limit: 50, expand: "members") to get recent chats with member info.
- Very specific: line 313
Important: Use m365_list_chats with expand: "members", NOT m365_search_chats.
- Distinctive: line 314
Search only matches topic names and will miss unnamed chats or chats where the topic doesn't contain the customer name.
- Very specific: line 319
If match → cache the chat entry in that customer's crm-mapping.json under customer_chat_ids[].
- Very specific: line 324
Pagination: If the user has many chats, page through using skipToken from the response.
- Very specific: line 328
Run discovery at the start of EVERY daily run (not just when customer_chat_ids is empty).
- Distinctive: line 335
If auto-discovery misses a chat (e.g., member uses a personal email, domain is unusual), the user can manually note the chat ID and …
- Distinctive: line 345
If today is Sunday → yesterday was Saturday (weekend) → use Thursday.
- Distinctive: line 366
If missing → prompt: "Run /crm-activity-sync setup first to configure your profile and customer mappings."
- Distinctive: line 371
If missing → this customer has no CRM mapping yet.
- Very specific: line 425
Commit message prefixes (everything before the first colon: design:, poc:, feat:, fix:, docs:, test:).
- Distinctive: line 467
If both match the same project → confirmed.
- Distinctive: line 468
If domain matches one customer but subject matches another → flag ambiguity, ask user.
- Distinctive: line 469
If no match → skip (not a customer event).
- Distinctive: line 506
Exclude everything else: No internal team emails, no SSP coordination, no HR/admin.
- Very specific: line 523
Find chat ID: Use m365_create_chat_by_email(email: "<ssp-email>") to get the 1:1 chat ID.
- Very specific: line 549
Use the SSP → customer mapping from config.core_ssps[].customers[].
- Very specific: line 550
If the SSP covers multiple customers (rare), match by scanning message content against each project's subject_keywords.
- Distinctive: line 552
If ambiguous → assign to the SSP's primary customer.
- Very specific: line 561
If a project has a group_chat_ids[] array, scan those too.
- Distinctive: line 569
Only scan chats with SSPs mapped to active customers.
- Distinctive: line 602
Only include Relevant messages in the log.
- Very specific: line 606
Check if the chat's members[] domains match a specific project's subject_keywords from the message content.
- Distinctive: line 608
If the customer has only one project → assign directly.
- Very specific: line 609
If multiple projects exist → scan message content against each project's subject_keywords to find the best match.
- Very specific: line 611
If ambiguous → in interactive mode, ask the user.
- Distinctive: line 620
Run auto-discovery (see Config section above) before scanning.
- Distinctive: line 634
If the same customer chat already contributed to a calendar event match (e.g., a scheduled Teams meeting that shows up in both calendar and …
- Very specific: line 664
Exclude already-scanned chats: Remove chats that were already processed by steps 2d (SSP chats) or 2e (registered customer chats).
- Distinctive: line 676
If zero messages on the target date → skip.
- Distinctive: line 701
If the answer to (a) is NO → skip.
- Distinctive: line 702
If the answer to (a) is YES but (b) is ambiguous → in interactive mode, ask the user.
- Very specific: line 709
Add the evidence to the appropriate { customer, project } evidence bucket
- Distinctive: line 729
Only customer-related chats get full message extraction.
- Very specific: line 739
When a chat is auto-discovered via content-based classification, cache it in crm-mapping.json under customer_chat_ids[]:
- Distinctive: line 762
Before any text-based evidence (Teams messages, email bodies, meeting chat) is included in the activity log, apply semantic relevance …
- Distinctive: line 779
Read the message content and ask: "Does this message contribute to understanding what work was done on the project?"
- Distinctive: line 782
If YES → Relevant. Include it.
- Distinctive: line 783
If NO → Off-topic. Drop it silently.
- Distinctive: line 784
If MIXED (e.g., starts with a joke then pivots to a technical question) →
- Distinctive: line 929
Don't double-count overlapping time: If a meeting runs 10:00-11:00 and commits span 09:00-14:00, the meeting time is already within the …
- Distinctive: line 931
Use the larger of: commit span vs sum of meetings.
- Distinctive: line 933
But: if meetings and commits overlap, don't add meetings separately — they're part of the same work block.
- Distinctive: line 956
Write a concise 2–4 sentence summary combining all evidence:
- Very specific: line 980
Before writing, check if activity-log.md already has an entry for this date:
- Distinctive: line 986
If found → skip this entry.
- Very specific: line 988
Override: If the user explicitly says "re-log" or "update", replace the existing entry for that date (find the ## <date> header, delete …
- Very specific: line 1060
Create file if missing: If activity-log.md doesn't exist, create it with the header:
- Very specific: line 1067
Separator: Add --- between date entries for readability.
- Distinctive: line 1069
Commit to git: After writing:
- Distinctive: line 1123
Preserve technical specifics: Don't genericize. "Yafim compiled DPDK with MANA driver" is better than "discussed compilation progress".
- Distinctive: line 1129
Language: Write summaries in English even if the conversation was in Hebrew.
- Distinctive: line 1146
Only write for sources with relevant content: No file for a source that had zero relevant messages after classification.
- Distinctive: line 1150
Idempotent: If the file already exists for that date+source, skip it.
- Distinctive: line 1163
After processing all target dates and all customer/projects, present a summary:
- Distinctive: line 1190
When running as a scheduled automation (e.g., daily at 07:30):
- Distinctive: line 1192
Run for yesterday (or last workday).
- Distinctive: line 1196
No user interaction — fully automated.
- Very specific: line 1239
When this skill is installed by a new Clawpilot user, the following setup happens automatically on first run (when …
- Distinctive: line 1250
Ask user to confirm which are customers
- Very specific: line 1251
Create customer-engagements/ folder structure
- Very specific: line 1254
Test with m_m365_status. Sign in if needed.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
/daily-activity-log — Daily Activity Log Builder
Scan multiple data sources — work repos (git history), M365 calendar,
PG/engineering emails, and Teams chats (both SSP and direct customer) — to build
a structured daily activity summary per customer project. Writes activity-log.md in each project's
customer-engagements folder, making customer-engagements the single source of
truth for downstream consumers like /crm-activity-sync.
Platform Compatibility
This skill runs on macOS, Linux, and Windows. Detect the OS first and pick the matching shell syntax. See _shared/PLATFORM.md (skills repo root) for the full translation table. Quick reference:
| Action | macOS / Linux (bash) | Windows (PowerShell) |
| List dir | ls $HOME/customer-engagements/ | Get-ChildItem $HOME/customer-engagements/ |
| Find node | which node | Get-Command node |
| Run git in repo | cd $HOME/repo && git log ... | Set-Location $HOME/repo; git log ... |
| Home dir | ~ or $HOME | $HOME |
Default to POSIX commands; use PowerShell on Windows native (not WSL/Git Bash).
Core Principles
- Evidence-based only. Every logged activity must trace to a concrete artifact: a git commit, a calendar event, or a sent email. Never infer or fabricate work.
- Aggregate per day. All evidence for a single customer + project + date is merged into one daily entry. A day of design commits + a meeting + an engineering email → one entry with sections, not three separate entries.
- Append, never overwrite. New daily entries are prepended (most recent first) to
activity-log.md. Existing entries are never modified or removed. - Idempotent. If the log already contains an entry for the target date + project, skip it. Report: "Activity for {customer}/{project} on {date} already logged."
- Preserve source language. Commit messages, email subjects, and meeting titles stay in their original language.
- Graceful degradation. Each data source can fail independently. If git is available but calendar isn't, log what you have. Note missing sources.
- Classify, don't just list. Each daily entry gets a Task Category classification based on the evidence. The category must match one of the 20 CRM
msp_taskcategoryvalues. The skill auto-classifies using signal keywords, but the user can override to any category during interactive mode or via thedefault_activity_typeincrm-mapping.json. - Relevance-only content. Every piece of text-based evidence (Teams messages, email body, meeting notes) must pass a semantic relevance check before being logged. You (the LLM executing this skill) read each message and judge whether it is project-related or off-topic. This is NOT a keyword filter — it is your semantic understanding of context. Personal chat, jokes, politics, social conversation, weekend plans, food, sports, and any off-topic messages are silently excluded — even if they appear in a customer or SSP chat. Only project-related business and technical content is logged. See "Relevance Classification" section below.
CRM Task Categories (all 20)
These are the valid msp_taskcategory values in MSX. The skill can assign any of them:
| Category | Value | Auto-classify signals |
| Architecture Design Session | 861980004 | "architecture", "design", "topology", "solution review", design commits |
| PoC/Pilot | 861980005 | "poc", "pilot", "testing", "lab", "hands-on", poc commits |
| Workshop | 861980001 | "workshop", "deep-dive", "training", "enablement", multi-hour events |
| Customer Engagement | 861980000 | General customer meetings, sync calls, status updates |
| Briefing | 861980008 | "briefing", "ideation", "brainstorm", "explore", "concept" |
| Blocker Escalation | 861980006 | Engineering escalation emails, PG coordination on blockers |
| Demo | 861980002 | "demo", "demonstration", "showcase", "show and tell" |
| Internal | 861980012 | Internal-only meetings with project keyword match, no customer |
| ACE | 606820000 | "ace", "azure consumption" |
| Call Back Requested | 861980010 | "callback", "call back" |
| Consumption Plan | 861980007 | "consumption", "commit", "macc" |
| Cross Segment | 606820001 | "cross segment", "cross-segment" |
| Cross Workload | 606820002 | "cross workload", "cross-workload" |
| External (Co-creation of Value) | 861980013 | "co-creation", "hackathon", "joint development" |
| Negotiate Pricing | 861980003 | "pricing", "negotiate", "commercial", "deal terms" |
| New Partner Request | 861980011 | "partner", "isv", "si request" |
| Post Sales | 606820003 | "post sales", "post-sales", "go-live support" |
| RFP/RFI | 861980009 | "rfp", "rfi", "request for proposal" |
| Tech Support | 606820004 | "support", "incident", "troubleshoot" |
| Technical Close/Win Plan | 606820005 | "close plan", "win plan", "technical close" |
The top 8 are the most common for SE daily work. The remaining 12 are available for
specialized activities. If the auto-classifier can't determine the category, it falls
back to the project's default_activity_type in crm-mapping.json.
- Detect unknown customers. When a calendar event has external attendees whose domain doesn't match any existing
crm-mapping.jsoncustomer, flag it. In interactive mode: ask whether it's a core customer, temp engagement, or not customer work. In automated mode: log the activity anyway (customer-engagements folder is source of truth if it exists) and send a Teams alert asking for classification.
Prerequisite Auto-Install
Before running, verify all dependencies are present. Install anything missing automatically.
Required Sibling Skills
This skill requires sibling skills from the same repository
(https://github.com/roie9876/clawpilot-skills):
| Skill | Purpose | Required? |
/crm-activity-sync | Downstream — reads activity-log.md and pushes to CRM. Also owns the shared config.json and setup flow | ✅ For config + CRM sync |
/customer-repo | Scaffolds customer-engagements/ folder structure per customer | ✅ For initial setup |
/msx-crm | CRM query tools (run-tool.mjs) for milestone and opportunity lookups | ⚠️ Only if CRM sync is desired |
Check if each required skill is installed:
# macOS / Linux
for skill in crm-activity-sync customer-repo msx-crm; do
[ -f "$HOME/.copilot/skills/$skill/SKILL.md" ] && echo "✅ $skill" || echo "❌ $skill MISSING"
done# Windows
foreach ($skill in @('crm-activity-sync','customer-repo','msx-crm')) {
if (Test-Path "$HOME\.copilot\skills\$skill\SKILL.md") { "✅ $skill" } else { "❌ $skill MISSING" }
}If ANY required skill is missing, install all skills from the repository:
- Clone the repo (skip if already cloned):
# macOS / Linux [ -d "$HOME/customer-skills/.git" ] || git clone https://github.com/roie9876/clawpilot-skills.git "$HOME/customer-skills"# Windows if (-not (Test-Path "$HOME\customer-skills\.git")) { git clone https://github.com/roie9876/clawpilot-skills.git "$HOME\customer-skills" } - Run the installer (idempotent — safe to re-run):
# macOS / Linux bash "$HOME/customer-skills/scripts/install.sh"# Windows pwsh "$HOME\customer-skills\scripts\install.ps1" - Verify the required skills are now installed. If still missing, stop and report the error.
Required Tools
| Tool | Check (POSIX) | Check (Windows) | Install (macOS) | Install (Windows) |
| git | git --version | Get-Command git | Pre-installed | winget install Git.Git |
| Node.js | node --version | Get-Command node | brew install node | winget install OpenJS.NodeJS |
Node.js is only strictly required if CRM sync is desired. Install any missing tools before proceeding.
CRM Tool Script (run-tool.mjs) — Optional
If CRM sync is desired, the helper script must exist at $HOME/.copilot/skills/msx-crm/crm-tools/run-tool.mjs.
# macOS / Linux
[ -f "$HOME/.copilot/skills/msx-crm/crm-tools/run-tool.mjs" ] && echo "✅ CRM tools found" || echo "⚠️ CRM tools not found (CRM sync will be unavailable)"# Windows
if (Test-Path "$HOME\.copilot\skills\msx-crm\crm-tools\run-tool.mjs") { "✅ CRM tools found" } else { "⚠️ CRM tools not found" }If missing and CRM sync is desired, clone the SE Kanban Tracker repo:
# macOS / Linux
git clone https://github.com/roie9876/crm-tools.git "$HOME/.copilot/skills/msx-crm/crm-tools"
cd "$HOME/.copilot/skills/msx-crm/crm-tools"# Windows
git clone https://github.com/roie9876/crm-tools.git "$HOME\.copilot\skills\msx-crm\crm-tools"
Set-Location "$HOME\.copilot\skills\msx-crm\crm-tools"; npm installM365 Sign-In
Check m_m365_status. If not signed in → call m_m365_sign_in.
Additional Checks
| Prerequisite | Required? | How to check |
customer-engagements/ folder | ✅ | $HOME/customer-engagements/ exists with ≥1 customer |
| Config file | ✅ | $HOME/.copilot/crm-activity-sync/config.json — shared with crm-activity-sync |
Note: This skill shares its config with /crm-activity-sync. If setup hasn't
been run yet, it will trigger the setup flow (see crm-activity-sync Step 1).
Commands
| Command | Purpose |
/daily-activity-log | Log yesterday's activities (default) |
/daily-activity-log today | Log today's activities (so far) |
/daily-activity-log <date> | Log activities for a specific date (ISO: 2026-04-21) |
/daily-activity-log week | Log the current work week (Sun–Thu) |
/daily-activity-log range <start> <end> | Log a date range |
/daily-activity-log add-repo <customer>/<project> <path> | Register a work repo for a project |
/daily-activity-log remove-repo <customer>/<project> <path> | Unregister a work repo |
/daily-activity-log repos | List all registered work repo mappings |
/daily-activity-log add-domain <customer> <domain> | Register an email domain for a customer (e.g., checkpoint checkpoint.com) |
/daily-activity-log domains | List all customer domain mappings |
/daily-activity-log discover-chats | Scan recent Teams chats to auto-discover customer conversations |
/daily-activity-log customer-chats | List all cached customer chat IDs |
File Locations
| File | Purpose |
~/.copilot/crm-activity-sync/config.json | Shared config (user profile, preferences, repo mappings) |
~/customer-engagements/{customer}/projects/{project}/activity-log.md | Per-project daily activity log (output) |
~/customer-engagements/{customer}/crm-mapping.json | Per-customer project-to-CRM mapping (shared with crm-activity-sync) |
Config: Work Repo Registration
Work repos are stored in crm-mapping.json under each project:
{
"projects": {
"sase": {
"display_name": "SASE",
"work_repos": [
{
"path": "/Users/robenhai/SASE",
"label": "SASE Design & POC",
"added": "2026-04-23"
}
],
"subject_keywords": ["sase", "checkpoint", "aks", "dpdk", "srv6"]
}
}
}Registration rules:
- A repo is registered to exactly one project. If a repo serves multiple projects (rare), ask the user which project it belongs to.
- Repos are registered manually via
/daily-activity-log add-repoor during setup. - Not every project has a repo — some are meeting-only engagements.
- The path must be an absolute path to a directory containing
.git/. - Validate on registration:
[ -d "<path>/.git" ]. If not a git repo → reject.
Config: SSP Chat Mapping
SSP-to-customer mapping comes from config.core_ssps[] in
~/.copilot/crm-activity-sync/config.json. Each SSP entry lists which customers
they cover. The 1:1 chat ID is resolved at runtime via
m365_create_chat_by_email(email) and can optionally be cached in
crm-mapping.json for performance:
{
"ssp_chat_ids": {
"kobishitrit@microsoft.com": "19:80cb6140-...@unq.gbl.spaces"
},
"projects": {
"sase": {
"group_chat_ids": [
{
"id": "19:5fda07cb...@thread.v2",
"topic": "HSASE-AZURE-GlobalNetworkBrain",
"added": "2026-04-23"
}
]
}
}
}SSP chat scanning rules:
- Only scan chats for SSPs in
config.core_ssps. Never scan random chats. - Cache resolved chat IDs in
crm-mapping.jsonunderssp_chat_idsto avoid repeated lookups. - Group chats are optional — register via
/daily-activity-log add-group-chat. - The
group_chat_idsarray is per-project incrm-mapping.json.
New commands for SSP chat management:
| Command | Purpose |
/daily-activity-log add-group-chat <customer>/<project> <chat-id> <topic> | Register a group chat for scanning |
/daily-activity-log remove-group-chat <customer>/<project> <chat-id> | Unregister a group chat |
Config: Customer Domains & Chat Discovery
Customer email domains are stored in crm-mapping.json per customer under a
top-level domains array. This is the primary mechanism for matching Teams chats
to customers:
{
"domains": ["checkpoint.com"],
"customer_chat_ids": [
{
"id": "19:abc123...@unq.gbl.spaces",
"type": "oneOnOne",
"topic": "John Smith (CheckPoint)",
"members": ["john.smith@checkpoint.com"],
"discovered": "2026-04-24"
},
{
"id": "19:def456...@thread.v2",
"type": "group",
"topic": "SASE Architecture Review",
"members": ["john.smith@checkpoint.com", "kobishitrit@microsoft.com"],
"discovered": "2026-04-24"
}
],
"projects": { ... }
}Domain registration rules:
- Each customer can have one or more domains (e.g.,
["checkpoint.com", "checkpoint.co.il"]). - Domains are matched against the email part after
@in Teams chat member addresses. - Register via
/daily-activity-log add-domain <customer> <domain>or auto-discover. - If
domainsis empty or missing, the customer is skipped during chat discovery.
Customer chat discovery flow (/daily-activity-log discover-chats):
- Collect all known
customer_domains → customermappings from allcrm-mapping.jsonfiles. - Call
m365_list_chats(limit: 50, expand: "members")to get recent chats with member info. Important: Usem365_list_chatswithexpand: "members", NOTm365_search_chats. Search only matches topic names and will miss unnamed chats or chats where the topic doesn't contain the customer name. Member-based scanning catches everything. - For each chat, check if any member's email domain matches a known customer domain. This catches: 1:1 chats with customer contacts, named group chats, AND unnamed group chats — as long as the customer member's email domain is registered.
- If match → cache the chat entry in that customer's
crm-mapping.jsonundercustomer_chat_ids[]. For unnamed chats, generate a descriptive topic like "(unnamed) member1, member2". - Skip chats that are already cached (match by
id). - Report: "Discovered N new customer chats: {customer} — {topic/member}."
Pagination: If the user has many chats, page through using skipToken from the
response. Scan at least 100 chats (2 pages of 50) to ensure good coverage.
Auto-discovery during daily runs:
- Run discovery at the start of EVERY daily run (not just when
customer_chat_idsis empty). New customer chats may appear at any time. - Discovery only runs once per skill invocation (not per date in range mode).
- Cache results immediately so subsequent dates in the same run benefit.
- Scan at least 50 recent chats per run. This is fast (single API call).
Manual fallback:
- If auto-discovery misses a chat (e.g., member uses a personal email, domain is
unusual), the user can manually note the chat ID and register it. But unlike SSP
chats and group chats, there is no separate manual-add command — just edit
crm-mapping.jsondirectly or let discovery handle it.
Step 0: Determine Target Date(s)
Default: Yesterday, adjusted for Israeli work week.
- If today is Sunday → yesterday was Saturday (weekend) → use Thursday.
- Otherwise → use yesterday (including Friday and Saturday — work can happen on non-standard days; the skill logs whatever evidence it finds).
Note: The old logic skipped Friday and Saturday entirely. This was wrong — SEs sometimes work on non-standard days (CritSits, deadlines, travel). The skill should always check yesterday. If no evidence is found, it reports "No activity detected" which is harmless. Missing real work is not.
Explicit date: The user can provide a specific date or range.
Week mode: Sunday through Thursday of the current week up to yesterday.
Set target_dates[] — an array of dates to process. Process each date
independently, in chronological order.
Step 1: Load Config and Mappings
- Read
~/.copilot/crm-activity-sync/config.json.- If missing → prompt: "Run /crm-activity-sync setup first to configure your profile and customer mappings."
- Stop.
- For each customer in
~/customer-engagements/:- Read
~/customer-engagements/{customer}/crm-mapping.json. - If missing → this customer has no CRM mapping yet. Still process it (activity log is useful even without CRM), but warn: "No CRM mapping for {customer}. Activities will be logged but won't sync to CRM."
- Read
- Build a lookup table:
repo_path → { customer, project }— maps each registered repo to its project.keyword → { customer, project }— maps subject keywords to projects.customer_domains → { customer }— maps email domains to customers (fromcrm-mapping.jsondomains[]field, falling back tostakeholders.md).ssp_email → { customer[], chat_id }— maps SSPs to their customers and cached chat IDs.customer_chat_ids → { customer, chat_id, members[] }— maps cached customer Teams chats to their customer (fromcrm-mapping.jsoncustomer_chat_ids[]).all_customer_names → [...]— list of all known customer display names, slugs, and account names for content-based matching.all_project_keywords → { keyword: { customer, project } }— flattened keyword map across all customers/projects for content-based matching.
Step 2: Collect Evidence
For each target date, collect from all sources in parallel.
Source types:
- 2a. Work Repo Git History (registered repos)
- 2b. Calendar Events (M365)
- 2c. Sent Emails (PG/Engineering + Customer)
- 2d. SSP Teams Chat (registered SSP chats)
- 2e. Customer Teams Chat (registered customer chats)
- 2f. Relevance Classification (filter for all text sources)
- 2g. Content-Based Chat Discovery (unmapped chats — LLM-driven) ⚠️ MANDATORY — see gate below
⚠️ Step 2g is NON-OPTIONAL. Steps 2a–2e only scan pre-registered sources. Step 2g is the only mechanism that discovers NEW customer chats (ad-hoc meetings, EXT support cases, CritSit chats, 1:1s about customer work). Skipping it causes silent data loss — entire customer interactions will be missing from the daily log. A mandatory gate before Step 3 enforces this.
2a. Work Repo Git History
For each registered work repo:
cd <repo-path> && git --no-pager log \
--format="%h %aI %s" \
--since="<target-date>T00:00:00" \
--until="<target-date+1>T00:00:00" \
--author="$(git config user.email)" \
2>/dev/nullImportant: The %aI format gives ISO 8601 author date — needed for duration
calculation (time span from first to last commit).
Important: Filter by --author to only count the user's own commits, not
collaborators. Use git config user.email from the repo, or fall back to the
email in config.
Extract from commits:
- Total commit count.
- Commit message prefixes (everything before the first colon:
design:,poc:,feat:,fix:,docs:,test:). - Dominant prefix = most frequent → drives activity type classification.
- Summarize what changed: group by prefix, list the distinct topics.
Prefix-to-task-category mapping:
| Git prefix | CRM Task Category |
design, arch, proposal | Architecture Design Session |
poc, feat, experiment, spike, test | PoC/Pilot |
workshop, lab, enable | Workshop |
demo, showcase | Demo |
docs, readme, changelog | Architecture Design Session (documentation supports design) |
fix, hotfix, patch | PoC/Pilot (bug fixing during POC) |
escalation, blocker | Blocker Escalation |
support, incident | Tech Support |
| No prefix / unknown | Use project's default_activity_type from crm-mapping.json |
If a repo has zero commits on the target date → skip it, no entry for this source.
2b. Calendar Events
m365_list_events(startDate: "<target-date>T00:00:00Z", endDate: "<target-date>T23:59:59Z", limit: 50)Filter criteria:
- ❌ Exclude all-day events.
- ❌ Exclude cancelled events.
- ❌ Exclude recurring 1:1s with manager (match
config.user.manager.email). - ❌ Exclude events with zero external attendees AND no project keyword match in subject.
- ✅ Include events where ≥1 attendee has an external (customer) email domain.
- ✅ Include events where the subject matches a project keyword, even if all-internal.
For each qualifying event, extract:
- Subject, start time, end time, duration.
- Attendee list (names, classify as internal/external/engineering).
- Whether external attendees are customer or Microsoft Engineering (PG).
Map to customer/project:
- Match external attendee domains against
customer_domainslookup. - Match subject against
keywordlookup. - If both match the same project → confirmed.
- If domain matches one customer but subject matches another → flag ambiguity, ask user.
- If no match → skip (not a customer event).
Classify meeting category:
- Meeting + "workshop" / "deep-dive" / "hands-on" / "training" → Workshop
- Meeting + "architecture" / "design" / "topology" / "solution review" → Architecture Design Session
- Meeting + "poc" / "pilot" / "testing" / "lab" → PoC/Pilot
- Meeting + "demo" / "showcase" / "demonstration" → Demo
- Meeting + "ideation" / "brainstorm" / "explore" / "concept" → Briefing
- Meeting + "rfp" / "rfi" / "request for proposal" → RFP/RFI
- Meeting + "pricing" / "negotiate" / "commercial" / "deal" → Negotiate Pricing
- Meeting + "close plan" / "win plan" / "technical close" → Technical Close/Win Plan
- Meeting + "partner" / "isv" / "si" → New Partner Request
- Meeting + "consumption" / "commit" / "macc" → Consumption Plan
- Meeting + "support" / "incident" / "troubleshoot" → Tech Support
- Meeting + "post sales" / "go-live" → Post Sales
- Meeting with Microsoft PG/Engineering (no customer) + blocker context → Blocker Escalation
- Meeting with Microsoft PG/Engineering (no customer) + project keyword → Architecture Design Session or PoC/Pilot (internal engineering work)
- Internal-only meeting matching project keyword → Internal
- Customer meeting (generic, no keyword match) → Customer Engagement
2c. Sent Emails (PG/Engineering + Customer Architecture)
m365_list_emails(folder: "sent", startDate: "<target-date>", endDate: "<target-date+1>", limit: 50)Include only emails matching these criteria:
- Product Group / Engineering emails:
- Recipient domain is
@microsoft.comAND - Recipient is NOT in your direct team (config.user known team members) AND
- Subject matches a project keyword from any
crm-mapping.json
- Recipient domain is
- Customer technical emails:
- Recipient domain matches a known customer domain AND
- This is a project-related thread (subject matches keyword)
Exclude everything else. No internal team emails, no SSP coordination, no HR/admin.
For each qualifying email, extract:
- Subject, recipients (names + emails), date.
- Classify: "Engineering Coordination" or "Customer Communication".
- Map to customer/project via subject keywords and recipient domains.
If zero qualifying emails on the target date → skip, no entry for this source.
2d. SSP Teams Chat (Ad-hoc Calls & Technical Discussion)
Ad-hoc Teams calls between SE and SSP are a major activity source that doesn't appear on the calendar. These are captured by scanning 1:1 and relevant group chats with known SSPs.
For each SSP in config.core_ssps:
- Find chat ID. Use
m365_create_chat_by_email(email: "<ssp-email>")to get the 1:1 chat ID. Cache this — the chat ID is stable. - Pull messages for target date:
Filter to messages wherem365_list_chat_messages(chatId: "<chat-id>", limit: 50)createdDateTimefalls within the target date (in user's timezone). Paginate withskipTokenif needed to cover the full day. - Detect ad-hoc calls. Messages with
content: "<systemEventMessage/>"andtype: "unknownFutureValue"are Teams call events (call started/ended). Count pairs of consecutive systemEventMessages as one call. Each pair typically has timestamps ~seconds apart (start + end). - Extract technical context. From the non-system text messages on the same date,
apply the Relevance Classification (see Step 2f). For each message:
- First apply the quick scheduling filter: messages that are purely coordination like "זמין?", "פנוי?", "available?", "בפגישה", "שניה", "ok", "👍", single emoji, or messages shorter than 10 characters → classify as Scheduling, drop.
- For all remaining messages, apply semantic relevance check: read the content and classify as Relevant (technical/business/project) or Off-topic (personal, jokes, politics, social). Only include Relevant messages.
- Preserve original language (Hebrew, English, mixed).
- Map to customer/project:
- Use the SSP → customer mapping from
config.core_ssps[].customers[]. - If the SSP covers multiple customers (rare), match by scanning message content
against each project's
subject_keywords. - If ambiguous → assign to the SSP's primary customer. Flag in the log.
- Use the SSP → customer mapping from
- Summarize topics. Group the technical messages into topics:
- Extract the key nouns/concepts discussed (e.g., "SRv6", "NAT GW", "SSD", "ephemeral storage", "LB usage").
- Note if any messages reference forwarded emails, documents, or PG contacts.
- Count: number of ad-hoc calls, number of substantive messages.
Also scan relevant group chats registered in crm-mapping.json:
- If a project has a
group_chat_ids[]array, scan those too. - Apply the same date filter and technical content extraction.
- Group chats with SSP + PG engineers are especially valuable (e.g., HSASE-AZURE-*).
If zero calls AND zero technical messages on the target date → skip, no entry for this source.
Important filtering rules:
- Only scan chats with SSPs mapped to active customers. Don't scan random chats.
- Messages from the SSP AND from the SE (you) both count as evidence.
- A day with calls but no text messages → still log as "ad-hoc call(s)" with no topic detail. The call itself is evidence of customer engagement.
- A day with technical text messages but no calls → still log. SSP text coordination is also customer work (e.g., answering SSP questions about the design async).
2e. Customer Teams Chat (Direct Customer Communication)
Direct Teams conversations with customer contacts — 1:1 chats and group chats that include external customer members. Unlike SSP chats (2d) which are between internal Microsoft people, these are conversations directly with the customer.
For each customer that has customer_chat_ids[] in crm-mapping.json:
- Iterate cached chats. For each entry in
customer_chat_ids[]: - Pull messages for target date:
Filter to messages wherem365_list_chat_messages(chatId: "<chat-id>", limit: 50)createdDateTimefalls within the target date (in user's timezone). Paginate withskipTokenif needed to cover the full day. - Detect calls. Same logic as SSP chats: messages with
content: "<systemEventMessage/>"andtype: "unknownFutureValue"are Teams call events. Count pairs as one call. - Extract content. From the non-system text messages on the same date,
apply the Relevance Classification (see Step 2f). Same process as SSP chats:
- Quick scheduling filter first (short/emoji/coordination → drop).
- Then semantic relevance check on remaining messages: read each one and classify as Relevant (project work) or Off-topic (personal/social).
- Only include Relevant messages in the log.
- Preserve original language.
- Map to project:
- Check if the chat's
members[]domains match a specific project'ssubject_keywordsfrom the message content. - If the customer has only one project → assign directly.
- If multiple projects exist → scan message content against each project's
subject_keywordsto find the best match. - If ambiguous → in interactive mode, ask the user. In automated mode, assign
to the customer's default project (first in
crm-mapping.json).
- Check if the chat's
- Summarize. Group messages into topics:
- Extract key discussion points.
- Note document shares, links, images.
- Count: calls, substantive messages, and which members participated.
If a customer has domains but no customer_chat_ids:
- Run auto-discovery (see Config section above) before scanning.
- Cache results and proceed with scanning.
If zero calls AND zero substantive messages on the target date → skip, no entry for this source.
Important filtering rules:
- Scan chats cached in
customer_chat_ids[]here. Unmapped chats are handled by Step 2g (content-based discovery) — do NOT skip them entirely. - Both your messages and customer messages count as evidence.
- A day with only a Teams call to the customer (no text) → still log as "customer call" — the call itself is engagement evidence.
- A day with only text messages (no call) → still log. Async customer communication is also work.
- If the same customer chat already contributed to a calendar event match (e.g., a scheduled Teams meeting that shows up in both calendar and chat), the calendar event takes precedence for that time block. But additional text messages outside the meeting window still count as separate evidence.
- Group chats with mixed internal + customer members: classify as customer chat (not SSP chat), since the customer is directly participating.
2g. Content-Based Chat Discovery (Unmapped Chats)
This is the most important discovery mechanism. Steps 2d and 2e only scan
chats that are pre-registered in crm-mapping.json. But customer work often
happens in chats that were never registered: ad-hoc support cases (EXT tickets),
1:1 with colleagues helping on customer issues, meeting chats from one-off calls,
new group chats created mid-engagement.
The LLM (you) can read message content and understand which customer it relates to. This step uses semantic analysis — not domain matching — to discover customer-relevant chats that other steps missed.
Discovery Flow
- Get recently active chats.
Filter to chats that had activity on any of them365_list_chats(limit: 50, expand: ["members", "lastMessagePreview"])target_dates[]. UselastUpdatedDateTimeas the initial filter (it's fast — no message reads yet). - Exclude already-scanned chats. Remove chats that were already processed
by steps 2d (SSP chats) or 2e (registered customer chats). These are identified
by chat ID matching against
ssp_chat_idsandcustomer_chat_idsin allcrm-mapping.jsonfiles. Also exclude 1:1 chats with the user's manager (config.user.manager.email) — these are not customer work. - Quick triage each remaining chat. For each unscanned chat with target-date
activity, read up to 20 messages from the target date:
Filter messages to the target date (bym365_list_chat_messages(chatId: "<id>", limit: 20)createdDateTimein user's timezone). If zero messages on the target date → skip. LLM semantic classification. For each chat with messages on the target date, you (the LLM) read the messages and answer these questions:
a. Is this customer-related work? Look for:
- Customer names, project names, product names matching known customers
- Azure resource references (resource groups, subscriptions, VNets, PE) that match customer environments
- Technical discussion tied to a known engagement (architecture, debugging, deployment, CritSit)
- Support case context (EXT tickets, ICM incidents, CritSit)
- Colleague names known to work on specific customer accounts (from
crm-mapping.jsonSSP lists, stakeholders) - Chat topic keywords ("כלל ביטוח", "checkpoint", "sase", etc.)
b. Which customer and project? Match against:
all_customer_names— customer display names, slugs, account namesall_project_keywords— subject keywords from all projects- Member names cross-referenced with known stakeholders/SSPs
- Azure resource naming patterns (e.g.,
rg-ai-clal-dev→ Clal Insurance)
c. What type of activity? Classify using the same CRM Task Category signals as Step 3b.
If the answer to (a) is NO → skip. Not customer work. If the answer to (a) is YES but (b) is ambiguous → in interactive mode, ask the user. In automated mode, log to the best-guess customer and flag "auto-classified — verify customer mapping."
- Process matched chats. For each chat classified as customer-related:
- Apply the same evidence extraction as Step 2e (calls, messages, topics, relevance classification from Step 2f)
- Add the evidence to the appropriate
{ customer, project }evidence bucket - Auto-cache the chat in that customer's
crm-mapping.jsonundercustomer_chat_ids[]with"source": "content-based"so future runs find it via Step 2e directly (faster, no re-classification needed)
What This Catches That Domain-Based Discovery Misses
| Scenario | Why domain-based fails | Content-based catches it |
| EXT support case (e.g., "EXT | 2604230050000351") | Members are MSFT + support vendor (LTI Mindtree, Teknowledge). No customer domain. | Messages reference customer name, Azure resources, and project context |
| 1:1 with internal colleague helping on customer issue | Both members are @microsoft.com | Messages contain customer resource groups, deployment errors, and project-specific terms |
| Meeting chat from ad-hoc customer call | Meeting wasn't in registered chats. Members may all be internal if customer joined via phone | Chat topic or messages reference customer by name |
| CritSit / ICM chat | Created by support, members are all internal + support vendor | ICM details, customer subscription IDs, resource names in messages |
| Cross-team collaboration | Engineers from other teams helping. No customer member present | Discussion clearly about customer architecture, deployment, blockers |
Performance Considerations
- This step runs AFTER steps 2a-2e. It only scans chats not already covered.
- Quick exit: Most chats are internal (team standup, org-wide, social). The LLM can classify these in seconds by reading the topic + first few messages. Only customer-related chats get full message extraction.
- Caching eliminates re-work. Once a chat is auto-cached in
crm-mapping.json, future runs process it via Step 2e without needing LLM classification again. - Limit: Scan at most 50 unmapped chats per run. This is enough for daily discovery. For backfill runs, page through more chats if needed.
- Parallel with other steps: This step can run in parallel with Steps 2a-2e since it targets different chats.
Auto-Cache Format
When a chat is auto-discovered via content-based classification, cache it in
crm-mapping.json under customer_chat_ids[]:
{
"id": "19:34791f8863eb455c860321ab3a702e08@thread.v2",
"type": "group",
"topic": "EXT | 2604230050000351",
"members": ["Ido Katz", "Scott Vickers", "Jayant Kumar"],
"discovered": "2026-04-25",
"source": "content-based",
"matched_by": "Messages reference Clal Insurance Azure resources (rg-ai-clal-dev-swe) and AI Foundry PE debugging"
}The source: "content-based" and matched_by fields distinguish auto-discovered
chats from domain-matched ones. This helps the user audit and correct
misclassifications if needed.
Step 2f: Relevance Classification (applies to ALL text sources)
Before any text-based evidence (Teams messages, email bodies, meeting chat) is included in the activity log, apply semantic relevance classification. This is not a keyword filter — it is an LLM judgment call made by you (the agent executing this skill) when you read each piece of content.
Classification Rules
For each message, email, or text excerpt, classify as one of:
| Classification | Action | Examples |
| Relevant | Include in activity log | Architecture discussion, requirements, design decisions, technical questions, pricing, timelines, deliverables, PG coordination, blocker discussion, status updates, action items, document sharing (technical), meeting scheduling about project topics |
| Off-topic | Silently exclude | Jokes, politics, sports, weekend plans, food, personal life, social chit-chat, memes, emoji-only reactions, holiday wishes, birthday messages, general small talk |
| Scheduling | Exclude (already filtered) | "זמין?", "available?", "ok", "👍", "שניה", "בפגישה", single emoji, <10 chars |
How to Classify
Read the message content and ask: "Does this message contribute to understanding what work was done on the project?"
- If YES → Relevant. Include it.
- If NO → Off-topic. Drop it silently. Do not mention it in the log.
- If MIXED (e.g., starts with a joke then pivots to a technical question) → Relevant. Include the technical part, summarize without the off-topic portion.
Where This Applies
| Source | What gets classified | Notes |
| SSP Teams chat (2d) | Each non-system message | Replaces the old "scheduling chatter" blocklist with full semantic check |
| Customer Teams chat (2e) | Each non-system message | Same semantic check |
| Sent emails (2c) | Email subject + body preview | Already filtered by keyword + domain; relevance check is a second pass |
| Calendar events (2b) | Meeting subject | Already filtered by attendees + keywords; generally all relevant |
| Git commits (2a) | N/A — commits in registered repos are always relevant | No filter needed |
| Group chats | Each non-system message | Same semantic check |
Counting Rules After Classification
- Only relevant messages count toward the
substantive messagestotal in the Sources line (e.g., "customer-chat (1 call, 5 messages)" — those 5 are post-filter). - Calls always count regardless of message content — a Teams call to a customer is work evidence even if the surrounding text is social.
- Duration estimation uses only relevant message count (5 min per relevant exchange, not per raw message).
Edge Cases
| Case | Behavior |
| All messages in a chat on target date are off-topic | No entry from this source. The chat had no project-relevant activity. |
| Chat has a call + only off-topic text messages | Log the call. Skip the messages. Entry says "1 call, no substantive messages." |
| Message is in Hebrew/mixed language | Classify based on meaning, regardless of language. Technical Hebrew = relevant. |
| Message references a shared document | Relevant — document sharing is work activity, even if the text is brief ("check this doc"). |
| Ambiguous message (could be social or work) | When in doubt, include it. Better to over-log slightly than miss real work. |
⛔ Pre-Synthesis Gate (MANDATORY before Step 3)
DO NOT proceed to Step 3 until ALL evidence sources have been executed. This gate exists because Step 2g (content-based chat discovery) is the most commonly skipped step — it's the heaviest and runs last — but it catches customer interactions that NO other step can find.
Confirm each source was executed (not just "no results" — actually ran):
| # | Source | Executed? |
| 2a | Git repos scanned | ☐ |
| 2b | Calendar events scanned | ☐ |
| 2c | Sent emails scanned | ☐ |
| 2d | SSP chats scanned | ☐ |
| 2e | Customer chats scanned | ☐ |
| 2f | Relevance classification applied | ☐ |
| 2g | Content-based chat discovery (unmapped chats) | ☐ |
If 2g was not executed → STOP and run it now before continuing.
A "no results" from 2g is fine (it means no unmapped chats had customer content). But "not executed" is a skill violation — it guarantees silent data loss.
Step 3: Aggregate and Classify
For each { customer, project, target_date } combination that has at least one
piece of evidence:
3a. Merge Evidence
Combine all evidence into a single daily entry:
evidence = {
repo_commits: [...], // from 2a
calendar_events: [...], // from 2b
sent_emails: [...], // from 2c
ssp_chat: { // from 2d
calls: N, // count of ad-hoc Teams calls
topics: [...], // extracted technical topics
messages: [...], // substantive messages (filtered)
ssp_name: "...", // SSP name
chat_sources: [...] // which chats contributed (1:1, group names)
},
customer_chat: { // from 2e
calls: N, // count of direct customer Teams calls
topics: [...], // extracted discussion topics
messages: [...], // substantive messages (filtered)
members: [...], // customer member names who participated
chat_sources: [...] // which chats contributed (1:1, group w/ customer)
}
}3b. Determine Task Category
Match evidence against the auto-classify signals from the CRM Task Categories table above. Use the dominant signal with this priority:
| Priority | Signal | Category |
| 1 | Workshop event (>2 hours, multiple attendees, "workshop" keyword) | Workshop |
| 2 | Customer meeting with "design"/"architecture" keyword | Architecture Design Session |
| 3 | Customer meeting with "poc"/"pilot" keyword | PoC/Pilot |
| 4 | Engineering escalation email (PG coordination on blocker) | Blocker Escalation |
| 5 | SSP chat with "design"/"architecture" topics + calls | Architecture Design Session |
| 5b | Customer chat with "design"/"architecture" topics + calls | Architecture Design Session |
| 6 | SSP chat with "poc"/"pilot"/"testing" topics + calls | PoC/Pilot |
| 6b | Customer chat with "poc"/"pilot"/"testing" topics + calls | PoC/Pilot |
| 7 | "demo"/"showcase" keyword in meeting or commits | Demo |
| 8 | "rfp"/"rfi" keyword | RFP/RFI |
| 9 | "pricing"/"negotiate"/"commercial" keyword | Negotiate Pricing |
| 10 | "partner"/"isv" keyword | New Partner Request |
| 11 | Repo commits dominant prefix → match prefix to category (see 2a table) | Varies |
| 12 | Internal-only meeting matching project keyword (no customer attendees) | Internal |
| 13 | SSP chat (calls or technical messages, no other keyword match) | Customer Engagement |
| 13b | Customer chat (calls or technical messages, no other keyword match) | Customer Engagement |
| 14 | Customer meeting (generic, no keyword match) | Customer Engagement |
| 15 | Engineering emails only (no meeting, no repo) | Architecture Design Session |
| 16 | Project's default_activity_type from crm-mapping.json | Fallback |
If multiple categories are equally strong (e.g., 10 design commits + a POC meeting),
use the project's default_activity_type as tiebreaker.
The **Type:** line in activity-log.md must use the exact CRM label (e.g.,
"Architecture Design Session", not "Design") so /crm-activity-sync can map it
directly to the msp_taskcategory value without ambiguity.
3c. Estimate Duration
Calculate the total duration in minutes for the day's activity. This is written
to activity-log.md and consumed by /crm-activity-sync to populate
actualdurationminutes on the CRM task.
Duration estimation rules by source:
| Source | How to estimate | Example |
| Calendar meeting | Exact: end - start from event | 60 min meeting → 60 min |
| Ad-hoc Teams call | From systemEventMessage timestamp pairs: end_ts - start_ts. If only one pair detected, minimum 10 min | Two calls, 8 min + 15 min → 23 min |
| SSP text discussion (no call) | Estimate 5 min per substantive message exchange (back-and-forth) | 4 messages exchanged → 20 min |
| Customer chat call | Same as ad-hoc Teams call: systemEventMessage timestamp pairs. Minimum 10 min per call | 1 customer call, 22 min → 22 min |
| Customer chat text (no call) | Estimate 5 min per substantive message exchange (same as SSP) | 6 messages exchanged → 30 min |
| Git commits | Time span from first to last commit of the day: last_commit_time - first_commit_time. Minimum 30 min if only 1 commit. If spread > 6 hours, cap at 6 hours (assumes breaks) | First commit 09:15, last 14:30 → 315 min (5h15m) |
| Sent email (PG/customer) | 15 min per qualifying email (composing a technical email) | 2 PG emails → 30 min |
Aggregation rules:
- Don't double-count overlapping time. If a meeting runs 10:00-11:00 and commits span 09:00-14:00, the meeting time is already within the commit span. Use the larger of: commit span vs sum of meetings.
- Formula:
total_duration = max(commit_time_span, sum_of_meetings) + ssp_call_duration + ssp_text_time + customer_call_duration + customer_text_time + email_time - But: if meetings and commits overlap, don't add meetings separately — they're part of the same work block. Only add meetings that fall outside the commit time span.
- Minimum: 15 min (even a single email counts as some work).
- Maximum: 480 min (8 hours) per day per project. If calculated duration exceeds this, cap at 480 and note "Duration capped at 8h" in the log.
- Round to nearest 15 min for CRM (e.g., 47 min → 45 min, 53 min → 60 min).
Write to activity-log.md:
The **Duration:** line goes after **Sources:**:
**Type:** Architecture Design Session
**Sources:** repo (3 commits), ssp-chat (4 calls, 8 messages), email (1 PG thread)
**Duration:** 285 min (4h 45m) — repo span 3h, 4 calls 45m, 1 email 15mThe breakdown after the total is informational — helps the user understand and override if needed.
3d. Generate Summary
Write a concise 2–4 sentence summary combining all evidence:
Template:
{Activity-type-verb} for {project-display-name} — {main topics from repo commits and/or meetings}.
{If SSP calls: "{N} ad-hoc call(s) with SSP ({name}). Topics: {topic1}, {topic2}."}
{If customer chat: "{N} call(s) + {M} messages with {customer-contact}. Topics: {topic1}, {topic2}."}
{If engineering emails: "Coordinated with {PG-team} on {topic}."}
{If meetings: "{N} meeting(s) with {customer/internal/PG}."}
{Commit count if repo work: "{N} commits."}Example with SSP calls + customer chat:
Design work for SASE — SRv6 feasibility analysis, NAT GW topology,
ephemeral storage assessment. 4 ad-hoc calls with SSP (Kobi Shitrit).
1 call + 3 messages with customer (John Smith). Coordinated with
Azure Networking PG (Brian Lehr) on SRv6 support. 1 email to PG. 3 commits.Step 4: Idempotency Check
Before writing, check if activity-log.md already has an entry for this date:
grep -c "^## <target-date>" ~/customer-engagements/{customer}/projects/{project}/activity-log.mdIf found → skip this entry. Report: "Activity for {customer}/{project} on {date} already logged."
Override: If the user explicitly says "re-log" or "update", replace the existing
entry for that date (find the ## <date> header, delete everything until the next
## header or --- separator, insert the new entry).
Step 5: Write activity-log.md
File Format
# Activity Log — {Customer Display Name} / {Project Display Name}
## 2026-04-23
**Type:** PoC/Pilot
**Sources:** repo (3 commits), ssp-chat (4 calls, 8 messages), customer-chat (1 call, 3 messages), email (1 PG thread)
**Duration:** 315 min (5h 15m) — repo span 3h, 4 SSP calls 45m, 1 customer call 15m, 1 email 15m
### Repo Work
- 3 commits in ~/SASE: secrets management design (area 12), SKU families recommendation
- Prefix breakdown: design (2), docs (1)
### SSP Coordination
- 4 ad-hoc calls with Kobi Shitrit (SSP)
- Topics discussed:
- SRv6 feasibility in Azure — official position is it won't happen, need to communicate to CheckPoint
- NAT GW topology — 2 per tenant (1 mgmt + 1 egress)
- Ephemeral SSD — 30GB sufficient, no extra SSD needed
- Load Balancer role — clarification on what it's used for (not E-W, not N-S, not egress)
- Also: coordinated PG outreach to Brian Lehr re SRv6
### Customer Communication
- 1 Teams call with John Smith (john.smith@checkpoint.com), 15 min
- 3 messages exchanged — topics: deployment timeline confirmation, SRv6
alternative approach feedback, shared updated architecture diagram
- Chat: "John Smith (CheckPoint)" (1:1)
### Engineering Coordination
- Email to blehr@microsoft.com (Azure Networking PG): SRv6 requirements for SASE
### Summary
Design work for SASE — SRv6 feasibility analysis, NAT GW topology,
ephemeral storage assessment, LB role clarification. 4 ad-hoc calls with SSP
(Kobi Shitrit). 1 call + 3 messages with customer (John Smith). Coordinated
with Azure Networking PG on SRv6 support. 3 commits.
---
## 2026-04-21
**Type:** Architecture Design Session
**Sources:** repo (21 commits)
**Duration:** 480 min (8h) — repo span 09:15-17:45 (capped at 8h)
### Repo Work
- 21 commits in ~/SASE: PoP topology, traffic flow diagrams (6 scenarios),
HA/failover, service functions, VPP/DPDK design, inter-PoP connectivity,
addressing, control plane proposals
- Prefix breakdown: design (18), docs (3)
### Summary
Full design sprint for SASE — 10 architecture areas with draw.io diagrams.
Covered PoP topology (4-subnet model), 6 traffic flow scenarios, HA/failover
model (4 failure domains), service function chain model, VPP/DPDK and SRv6
fabric design. 21 commits.
---Writing Rules
- Create file if missing. If
activity-log.mddoesn't exist, create it with the header:# Activity Log — {Customer Display Name} / {Project Display Name} - Prepend new entries. Insert after the
# Activity Logheader line, before any existing##date entry. Most recent date first. - Separator. Add
---between date entries for readability. - Commit to git. After writing:
cd ~/customer-engagements/{customer} git add projects/{project}/activity-log.md git commit -m "activity-log: {date} — {activity-type} ({sources summary})"
Step 5b: Write communications/ (detailed chat & email records)
In addition to the summary in activity-log.md, write the full relevant content
of text-based sources to the communications/ folder. This preserves the actual
messages for reference, search, and audit — while activity-log.md has the summary.
File naming convention
One file per source per date:
communications/{date}-{source-type}.mdExamples:
communications/2026-04-23-customer-chat.mdcommunications/2026-04-23-ssp-chat.mdcommunications/2026-04-23-email-pg.md
File format for chat records
# {Source Type} Summary — {Month Day, Year}
**Chat:** {chat topic or "(unnamed) member list"}
**Participants:** {external member name (email)}, {other members}
**Messages:** {N} relevant ({M} filtered as off-topic) | **Duration:** ~{X} min
---
## Key Topics
### 1. {Topic Title}
{2-4 sentence summary of what was discussed, decided, or raised. Include who
said what when it matters. Capture technical specifics — architecture choices,
numbers, product names, blockers — not just "they discussed networking".}
### 2. {Topic Title}
{Summary...}
## Action Items
- [ ] {Who} to {do what} (re: {topic context})Summary writing rules:
- Summarize, don't copy-paste. Group related messages into topics. Write a coherent narrative of what was discussed, not a message-by-message transcript.
- Preserve technical specifics. Don't genericize. "Yafim compiled DPDK with MANA driver" is better than "discussed compilation progress".
- Extract action items. Any commitment, request, or next step mentioned in the conversation becomes a checkbox item.
- Include who. Name the person who raised a point, made a decision, or took an action — this matters for follow-up.
- Language. Write summaries in English even if the conversation was in Hebrew. Preserve technical terms and proper nouns in their original form.
File format for email records
# Email Coordination — {Month Day, Year}
---
### {HH:MM} — To: {recipients}
**Subject:** {subject}
{email preview/body excerpt — relevant portions only}Writing rules for communications/
- Only write for sources with relevant content. No file for a source that had zero relevant messages after classification.
- Only include messages classified as Relevant in Step 2f. Off-topic messages are silently excluded. Note the filtered count in the header.
- Idempotent. If the file already exists for that date+source, skip it. If re-logging, replace it.
- Commit together with the activity-log.md entry:
cd ~/customer-engagements/{customer} git add projects/{project}/activity-log.md projects/{project}/communications/ git commit -m "activity-log: {date} — {activity-type} ({sources summary})"
Step 6: Report
After processing all target dates and all customer/projects, present a summary:
📋 Daily Activity Log — April 22, 2026
Logged:
✅ CheckPoint / SASE — Design (21 repo commits)
✅ Clal Insurance / AI Search — Meeting Call (1 meeting, 14:00-15:30)
Auto-discovered chats:
🔍 Clal Insurance — "EXT | 2604230050000351" (content-based: AI Foundry PE debugging)
🔍 Clal Insurance — 1:1 with Orel Yitzhakian (content-based: Bastion deployment for rg-ai-clal-dev-swe)
Skipped (already logged):
⏭️ CheckPoint / SASE — April 21 already in activity-log.md
No activity detected:
⚪ Sapiens / Digital-AI — no commits, no meetings, no emails
No CRM mapping (logged but won't sync):
⚠️ Sapiens — run /crm-activity-sync setup to add CRM mappingAutomation
When running as a scheduled automation (e.g., daily at 07:30):
- Run for yesterday (or last workday).
- Auto-discover customers by scanning
~/customer-engagements/*/crm-mapping.json— process every customer that has acrm-mapping.jsonwithcustomer_typeset. No hardcoded customer list. - Skip already-logged dates.
- Send a Teams summary only if new entries were created.
- No user interaction — fully automated.
Automation prompt:
Run /daily-activity-log for yesterday.
Auto-discover all customers by scanning ~/customer-engagements/*/crm-mapping.json —
process every customer that has a crm-mapping.json with customer_type set.
Skip already-logged dates.
If new entries were created, send a brief Teams summary.
If errors occur, include them in the summary.Edge Cases
| Case | Behavior |
| Repo has commits but project has no crm-mapping.json | Log anyway — activity-log.md is useful even without CRM |
| Calendar returns no events | Fine — log repo work only |
| M365 not signed in | Skip calendar + email + Teams chat. Log repo work only. Warn in report. |
| Multiple repos for one project | Merge all commits into one entry. List each repo path in the "Repo Work" section. |
| Repo has commits by someone else (pair programming) | --author filter ensures only user's commits are counted. If zero → skip. |
| Weekend date | Log anyway — SEs sometimes work on non-standard days (CritSits, deadlines). If no evidence found, report "No activity detected." |
| Empty day (no evidence from any source) | No entry created. Report as "No activity detected." |
| Very large commit count (>50) | Summarize at topic level, don't list individual commits. Show count only. |
| Commit message has no prefix | Use project's default_activity_type. In the entry, list as "general" prefix. |
Customer chat found but no domains configured | Skip domain-based discovery for that customer, but content-based discovery (2g) may still find chats. |
| Chat has both customer + SSP members | Classify as customer chat (2e), not SSP chat (2d). Customer participation takes precedence. |
| Customer chat call overlaps with calendar meeting | Calendar event takes precedence for that time slot. Don't double-count the same meeting from both sources. |
| Multiple customer chats match the same customer | Merge evidence from all chats into one entry per customer/project/date. |
| Chat member domain doesn't match any customer | Don't skip — Step 2g (content-based) may still match it by reading messages. |
| Unmapped chat references customer by name in content | Step 2g classifies it, extracts evidence, and auto-caches for future runs. |
| Unmapped chat references Azure resources (RG, VNet, subscription) matching a customer | Step 2g matches resource naming patterns to customer environments. |
| EXT / CritSit / ICM support case chat | Step 2g reads messages, matches customer by context, and logs as Tech Support or Blocker Escalation. |
| 1:1 with colleague about customer work | Step 2g reads messages, detects customer-related content, and attributes to the correct customer. |
| Content-based match is ambiguous (could be 2 customers) | Interactive: ask user. Automated: best-guess + flag "auto-classified — verify." |
| Content-based discovers a completely new customer | Flag as "Unknown customer" in report. Do NOT auto-create customer-engagements folder. Ask user in interactive mode. |
New User Adoption Guide
When this skill is installed by a new Clawpilot user, the following setup happens
automatically on first run (when ~/.copilot/crm-activity-sync/config.json is
missing). This skill shares its config with /crm-activity-sync.
First-Run Checklist
Prompt: "Run /crm-activity-sync it sets up yourfirst
profile, customers, and CRM mappings that this skill depends on."
Guide user through customer discovery:
- Scan recent calendar for external attendee domains
- Ask user to confirm which are customers
- Create
customer-engagements/folder structure
Needed for calendar + email + Teams chat scanning.
Test with m_m365_status. Sign in if needed.
For each customer project with a local
git repo, register via /daily-activity-log add-repo.
For customer-specific Teams groups
with SSPs, register via /daily-activity-log add-group-chat.
What Gets Personalized
| Item | Where stored | Notes |
| Git author email | Auto-detected from git config user.email per repo | No config needed |
| Customer folders | ~/customer-engagements/ | Created during /crm-activity-sync setup |
| Work repos | crm-mapping.json per customer | Registered manually |
| SSP chat IDs | crm-mapping.json per customer | Resolved via m365_create_chat_by_email |
| Group chat IDs | crm-mapping.json per project | Registered manually |
| Customer domains | crm-mapping.json per customer domains[] | Registered via add-domain or auto-discovered from calendar |
| Customer chat IDs | crm-mapping.json per customer customer_chat_ids[] | Auto-discovered via discover-chats or during daily runs |
| Subject keywords | crm-mapping.json per project | Set during setup, editable |
| Manager email (for filtering) | config.json | Auto-discovered via M365 Graph |
| Work week days | config.json | Israel: Sun-Thu, configurable |
Sharing This Skill
To share with another SE:
- Give them the
SKILL.mdfiles for both/daily-activity-logand/crm-activity-sync - They install in their Clawpilot (
~/.copilot/m-skills/) - On first run, the setup flow personalizes everything for their identity, customers, and no manual editing of SKILL.md neededrepos
- Examples in this file use "RBH" / "CheckPoint" / " these are illustrativeKobi" only, not hardcoded logic
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

