Interactive post-onboarding tour that adapts to whatever data exists (calendar, Granola, or none). Use right after onboarding, or when the user says 'show me around', 'how do I start'. Also use proactively when the vault is < 7 days old. Not for the initial setup itself; use `setup`.
Installs into .claude/skills of the current project.
Are you the author of Getting Started?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/davekilleen-getting-started-dex)
---
name: getting-started
description: "Interactive post-onboarding tour that adapts to whatever data exists (calendar, Granola, or none). Use right after onboarding, or when the user says 'show me around', 'how do I start'. Also use proactively when the vault is < 7 days old. Not for the initial setup itself; use `setup`."
---
<!-- Generated from `.claude/skills/getting-started/SKILL.md` by `scripts/generate-agents-skills.py`. Do not edit. -->
## Purpose
Transform the post-onboarding experience from "blank chat window" to guided value delivery. Adaptive based on what data sources are available (calendar, Granola, or neither).
## When to Run
- Automatically suggested at session start if vault < 7 days old
- User types `/getting-started`
- After onboarding completion (Step 11)
- User says they're not sure what to do next
## Entry Point
### Step 1: Verify Onboarding
Call `check_onboarding_complete()` from onboarding-mcp to verify vault status.
The first-week reveal already ran during onboarding. Do not repeat the first-week statistics or present them as a new discovery, even if an older completion marker suggests analysis was deferred. `/getting-started` is now the deeper tour.
### Step 2: Environment Check
Check what data sources are available:
- Calendar: Try calling calendar MCP (if fails, not available)
- Granola: Call `granola_check_available()` from granola-mcp
Based on results, route to appropriate flow.
---
## Flow A: Has Calendar + Granola
**The Deeper History Flow**
### Historical Data Discovery
```
đ **Welcome back, [Name]!**
You have already seen this week's calendar snapshot, so I won't repeat it. Let's look at the deeper meeting history you can turn into useful context.
**Calendar:** â Connected
**Granola:** â Connected
I'll check how much Granola history is available before suggesting what to process.
```
Then execute:
1. Analyze Granola data extent using helper function (6 months by default)
2. If more data exists, ask if they want to see full extent
3. Present the historical summary
```
đ **Your Granola history:**
**Granola data (last 6 months):**
⢠[N] meetings captured
⢠Going back [days_back] days (to [oldest_date])
⢠[M] unique people detected ([I] internal, [E] external)
⢠[K] external companies identified
```
**If `has_more_data` is True, ask:**
```
đĄ **I see there are meetings beyond 6 months.**
Want me to check how much more history you have?
This will take a few more seconds.
â Yes - show me the full extent
â No - 6 months is plenty
```
**If user says "Yes", refetch with `extended=True` and update:**
```
đ **Updated - Full data extent:**
⢠[N_total] meetings captured (found [N_new] older meetings)
⢠Going back [total_days] days (to [oldest_date])
⢠[M_total] unique people detected
⢠[K_total] external companies identified
---
Here's what I can create from your Granola history:
**đ People & Company Pages** (Recommended: All history)
â Builds context for relationships
â Low overhead - just reference pages
â Helps you see interaction history
**đ Meeting Notes** (Recommended: Last 30 days)
â Searchable record of discussions
â ď¸ Medium overhead - lots of reading material
â Good for finding past decisions
**â Action Items / Todos** (Recommended: Last 7 days)
â Actionable recent tasks
â ď¸ Can be overwhelming if too many
â ď¸ Old todos often outdated or already done
**What would you like me to do?**
1ď¸âŁ Smart default (Recommended)
⢠People/companies: All [days_back] days
⢠Meeting notes: Last 30 days (~[est_30d] meetings)
⢠Todos: Last 7 days (~[est_7d] meetings)
2ď¸âŁ Recent only (Conservative)
⢠Everything: Last 7 days only
3ď¸âŁ Full history (Comprehensive)
⢠Everything: All [days_back] days
4ď¸âŁ Custom (You choose)
⢠Pick different time ranges for each type
5ď¸âŁ Just going forward
⢠Start fresh from today
6ď¸âŁ Skip for now
```
### User Chooses Processing Strategy
Use prompt_user tool. If prompt_user is not available, prompt in CLI with the same numbered options and capture the selection:
```json
{
"questions": [{
"id": "granola_strategy",
"prompt": "How would you like to process your Granola data?",
"allow_multiple": false,
"options": [
{"id": "smart", "label": "1ď¸âŁ Smart default - People/companies (all) + Notes (30d) + Todos (7d)"},
{"id": "recent", "label": "2ď¸âŁ Recent only - Everything from last 7 days"},
{"id": "full", "label": "3ď¸âŁ Full history - Everything from all available data"},
{"id": "custom", "label": "4ď¸âŁ Custom - I'll choose time ranges for each type"},
{"id": "forward", "label": "5ď¸âŁ Just going forward - Start fresh from today"},
{"id": "skip", "label": "6ď¸âŁ Skip for now"}
]
}]
}
```
### Custom Mode Flow
If user selects "custom", ask for granular preferences:
```json
{
"title": "Choose time ranges for historical data",
"questions": [
{
"id": "people_range",
"prompt": "People & Company Pages: How far back?",
"allow_multiple": false,
"options": [
{"id": "7d", "label": "Last 7 days"},
{"id": "30d", "label": "Last 30 days"},
{"id": "90d", "label": "Last 90 days"},
{"id": "all", "label": "All [days_back] days (recommended)"},
{"id": "none", "label": "Skip - don't create"}
]
},
{
"id": "notes_range",
"prompt": "Meeting Notes: How far back?",
"allow_multiple": false,
"options": [
{"id": "7d", "label": "Last 7 days"},
{"id": "30d", "label": "Last 30 days (recommended)"},
{"id": "90d", "label": "Last 90 days"},
{"id": "all", "label": "All [days_back] days"},
{"id": "none", "label": "Skip - don't create"}
]
},
{
"id": "todos_range",
"prompt": "Action Items / Todos: How far back?",
"allow_multiple": false,
"options": [
{"id": "7d", "label": "Last 7 days (recommended)"},
{"id": "30d", "label": "Last 30 days"},
{"id": "90d", "label": "Last 90 days"},
{"id": "all", "label": "All [days_back] days"},
{"id": "none", "label": "Skip - don't create"}
]
}
]
}
```
Map responses to days:
- "7d" â 7
- "30d" â 30
- "90d" â 90
- "all" â [days_back from extent analysis]
- "none" â 0 (skip)
### Process Based on Selection
**Map strategy to time ranges:**
```python
def map_strategy_to_ranges(strategy: str, extent: dict) -> dict:
"""Convert user strategy choice to specific time ranges"""
if strategy == "smart":
return {
'people_days': extent['days_back'], # All history
'notes_days': min(30, extent['days_back']), # Last 30 days or all if less
'todos_days': min(7, extent['days_back']) # Last 7 days or all if less
}
elif strategy == "recent":
return {
'people_days': 7,
'notes_days': 7,
'todos_days': 7
}
elif strategy == "full":
return {
'people_days': extent['days_back'],
'notes_days': extent['days_back'],
'todos_days': extent['days_back']
}
elif strategy == "forward":
return {
'people_days': 0,
'notes_days': 0,
'todos_days': 0
}
elif strategy == "skip":
return None
# For "custom", ranges come from separate prompt_user responses (or CLI fallback)
```
**Show confirmation before processing:**
```
**Here's what I'll do:**
đ People/Company Pages: Last [people_days] days
â ~[est_people] people pages, ~[est_companies] company pages
đ Meeting Notes: Last [notes_days] days
â ~[est_notes] meeting notes
â Todos: Last [todos_days] days
â Estimated [est_todos] action items
**This will take about 2-3 minutes. Ready?**
```
**Processing phases:**
1. **Fetch meetings by maximum range needed:**
```python
max_days = max(people_days, notes_days, todos_days)
all_meetings = granola_get_recent_meetings(days_back=max_days, limit=1000)
```
2. **Phase 1: People & Companies (if people_days > 0):**
```python
# Filter meetings for people processing
people_meetings = [m for m in all_meetings
if days_ago(m['date']) <= people_days]
# For each unique person:
# - Extract from all meetings in range
# - Create person page with meeting history
# - Route to Internal/ or External/
# - Create/update company pages for external domains
# Use /process-meetings --people-only --days-back={people_days} logic
```
3. **Phase 2: Meeting Notes (if notes_days > 0):**
```python
# Filter meetings for note creation
notes_meetings = [m for m in all_meetings
if days_ago(m['date']) <= notes_days]
# For each meeting:
# - Create detailed meeting note
# - Extract key points and decisions
# - Link to person/company pages
# - BUT don't extract todos yet
# Use /process-meetings --no-todos --days-back={notes_days} logic
```
4. **Phase 3: Todos (if todos_days > 0):**
```python
# Filter meetings for todo extraction
todo_meetings = [m for m in all_meetings
if days_ago(m['date']) <= todos_days]
# For meetings that have notes:
# - Extract action items
# - Create tasks in 03-Tasks/Tasks.md
# - Add task IDs to meeting notes
# For meetings in todo range but not notes range:
# - Still extract todos but note they came from unprocessed meetings
```
5. **Show completion summary:**
```
## Processing Complete â
**People & Companies:**
⢠Created [X] person pages ([I] internal, [E] external)
⢠Created [Y] company pages
⢠Processed [P] days of history
**Meeting Notes:**
⢠Created [N] detailed meeting notes
⢠From last [notes_days] days
**Action Items:**
⢠Extracted [T] todos
⢠From last [todos_days] days
⢠Added to 03-Tasks/Tasks.md
**Your vault now has:**
⢠Rich context from [people_days] days of meetings
⢠Searchable notes from [notes_days] days
⢠Actionable todos from [todos_days] days
Want to explore what was created?
```
**If "skip" selected:**
- Show: "No problem! You can always run `/process-meetings` later when you're ready."
- Move to completion flow
**If "forward" selected:**
- Show: "Got it - starting fresh from today. I won't backfill historical data."
- Update a marker file to remember this choice
- Future meetings will be processed normally
---
## Flow B: Has Calendar OR Granola (Not Both)
**The "Let Me Help You Complete The Picture" Flow**
### If Only Calendar:
```
đ **Welcome back, [Name]!**
You already saw this week's calendar snapshot during onboarding, so I won't repeat those numbers. I can now show you how to use that context for daily planning, meeting prep, and relationship notes.
**But I notice Granola isn't connected** - that's how I process meeting transcripts into action items and insights.
Want help with:
1. Connecting Granola â run `/granola-setup` to add your Granola API key (needs a Granola Business plan) for automatic meeting intelligence
2. Connecting another meeting tool
3. Or tell me what other tools you use - I'll build integrations
What sounds useful?
```
### If Only Granola:
**Same discovery flow as Flow A, but calendar-less:**
```
đ **Welcome back, [Name]!**
I can see Granola is connected. Let me check what's available...
[Analyze Granola data extent - 6 months by default]
đ **Granola data (last 6 months):**
⢠[N] meetings captured
⢠Going back [days_back] days (to [oldest_date])
⢠[M] unique people detected ([I] internal, [E] external)
⢠[K] external companies identified
```
**If `has_more_data` is True:**
```
đĄ **I see there are meetings beyond 6 months.**
Want me to check how much more history you have?
â Yes - show me the full extent
â No - 6 months is plenty
```
**Then continue:**
```
---
Here's what I can create from your Granola history:
**đ People & Company Pages** (Recommended: All history)
â Builds context for relationships
â Low overhead - just reference pages
**đ Meeting Notes** (Recommended: Last 30 days)
â Searchable record of discussions
â ď¸ Medium overhead
**â Action Items / Todos** (Recommended: Last 7 days)
â Actionable recent tasks
â ď¸ Can be overwhelming if too many
**What would you like me to do?**
1ď¸âŁ Smart default - People/companies (all) + Notes (30d) + Todos (7d)
2ď¸âŁ Recent only - Everything from last 7 days
3ď¸âŁ Full history - Everything from all available data
4ď¸âŁ Custom - I'll choose time ranges for each type
5ď¸âŁ Just going forward - Start fresh from today
6ď¸âŁ Skip for now
**I also notice your calendar isn't connected.** After processing, want to:
⢠Connect Google Calendar (even if work is restricted)
⢠Connect Apple Calendar
⢠Or skip - I can work with just Granola
```
Use the same prompt_user and processing logic as Flow A (or CLI fallback).
---
## Flow C: Neither Calendar Nor Granola
**The "Let's Connect Your Tools" Flow**
```
đ **Welcome back, [Name]!**
Your workspace is set up, but you don't have calendar or meeting tools connected yet.
**Let's get you integrated with the tools you actually use.**
What tools do you use most? Examples:
⢠Notion, Linear, Jira
⢠Slack, Discord
⢠GitHub, GitLab
⢠Your company's internal tools
⢠Newsletters, RSS feeds
**Give me names or URLs** (URLs are better - just the root domain like "notion.so" or "linear.app")
Once you tell me, I'll:
1. Check for API documentation
2. Analyze what's possible
3. Generate working MCP code
4. Get you integrated in ~2 minutes
What's your most important tool?
```
### Tool Integration Flow
When user provides tool name/URL:
**Step 1: Find API docs**
```python
if url_provided:
# Fetch directly
base_url = normalize_url(user_input)
doc_content = web_fetch(base_url)
else:
# Search for docs
search_patterns = [
f"{tool_name} API documentation",
f"{tool_name} developer docs",
f"{tool_name} API reference"
]
# Try WebSearch or direct fetch of common patterns
doc_url = find_api_docs(tool_name)
doc_content = web_fetch(doc_url)
```
**Step 2: Analyze capabilities**
```
"Hold on - reading [Tool]'s API documentation..."
[Analyze doc_content for:]
- Authentication methods
- Available endpoints
- Common operations
- Rate limits
"Got it! I just read [Tool]'s API. Here's what we can build:
**Possible integrations:**
⢠[Capability 1] - [Dex use case]
⢠[Capability 2] - [Dex use case]
⢠[Capability 3] - [Dex use case]
Based on your role ([role]), I'd focus on [specific capabilities].
Ready to build this? Takes about 2 minutes."
```
**Step 3: Generate MCP**
Follow `/create-mcp` skill flow:
1. Design tools based on API analysis
2. Generate server code
3. Configure authentication
4. Test connection
5. Update documentation
**Step 4: The Magic Moment**
```
"Your [Tool] integration is live! â
Test it right now:
'[Natural language query about that tool]'
See? Real data, not AI guessing. That's what MCP does."
```
**Step 5: Offer More**
```
"Want to connect another tool? Or explore what else Dex can do?"
[If yes, repeat]
[If no, show quick reference guide]
```
---
## Additional Pathways (Available in Any Flow)
### Google Workspace Setup
If user wants to connect Gmail/Calendar:
```
"Let's connect your Google account.
This works even if your work account has restrictions - we can use your personal Google if needed.
**What we'll set up:**
⢠Calendar sync (see meetings in Dex)
⢠Gmail access (summarize newsletters, find emails)
⢠Optional: Create daily digest
I'll guide you through OAuth step-by-step.
Ready?"
```
Then:
1. Guide through OAuth flow for Google Calendar MCP
2. Add Gmail MCP if they want
3. Offer to set up newsletter digest
### Information Diet Setup
If user mentions newsletters, RSS, or content consumption:
```
"Want me to create a daily digest for you?
I can pull from:
⢠Newsletters (via Gmail)
⢠YouTube channels you follow
⢠RSS feeds from blogs
⢠Specific websites you check regularly
Each morning, you'd get:
⢠Summaries of new content
⢠Key points extracted
⢠Novel insights highlighted
⢠All in one place
What sources matter most to you?"
```
Then build appropriate scrapers/integrations.
### Smithery.ai Discovery
Anytime during tool discussion:
```
"By the way - there are 100+ pre-built MCP servers at **Smithery.ai**
Browse there for:
⢠GitHub, Linear, Jira
⢠Notion, Airtable, Sheets
⢠Slack, Discord, Email
⢠Databases, monitoring tools
⢠And way more...
Find something interesting? Just paste the URL here and I'll integrate it.
Or we can build custom if you don't find what you need."
```
---
## Setting Expectations
Throughout ANY flow, include:
```
"**Fair warning:** I can't promise everything will work perfectly.
Company restrictions, API limitations, weird auth flows -
lots can go wrong in the real world.
**But here's what's cool:** Even when it doesn't work, you learn:
⢠How to use Claude to debug APIs
⢠How to build integrations yourself
⢠How MCP servers work
⢠How to read API documentation
It's educational even when it fails.
Still want to try?"
```
---
## Cursor UX Tip (If Running in Cursor)
After a few file edits, offer:
```
"**Quick Cursor tip:**
You're seeing 'Accept' prompts for each change I make. That's Cursor asking permission.
**Useful at first** - you see what's happening
**Annoying later** - slows things down
If you want to auto-accept:
1. Settings (Cmd+,)
2. Search "always allow tool use"
3. Enable it
Your choice - some prefer control, others prefer speed."
```
Only show if:
- Detected running in Cursor (check environment)
- After 3-4 accept prompts shown
---
## Integration Discovery (Contextual)
**Trigger:** Run this check if the vault is < 7 days old AND few or no integrations are connected.
### When to Check
After completing the main pathway flow (A, B, or C) but before showing the completion message:
1. Read `System/integrations/config.yaml` (if it exists)
2. Count how many integrations have `enabled: true` (exclude `slack` since it's a default)
3. If connected integrations <= 1 AND vault age < 7 days, run the concierge
### How to Run
Execute the integration concierge â it scans the vault for signals (mentions, links, email domains) of tools the user already works with and ranks them:
```bash
Use the harness's MCP integration flow if available; otherwise continue without optional integrations.
```
Parse the JSON output for the high_value and moderate_value tiers. Each entry includes `shortName`, `reason` (a ready-to-use plain-English signal â "installed on your Mac", "3 mentions in your notes", "already set up as a connector but not switched on yet"), `value`, `setupTime`, and `setup` (the setup skill to run). Prefer `reason` verbatim â it already names the strongest evidence (an installed app or configured connector outranks a passing mention).
### Presenting Recommendations
**Only surface high_value items** (keep it light â this isn't onboarding, it's a nudge).
For each high_value integration found:
```
By the way â **[shortName]** ([reason]).
Connecting it would give you: [value proposition]
Setup takes [setupTime]. Want to connect it now?
```
**If multiple high_value items:**
```
I also spotted signals for **[shortName2]** and **[shortName3]** in your notes.
Want to connect any of these? Or run `/integrate-mcp` anytime later.
```
**Rules:**
- Maximum 2 integration suggestions (don't overwhelm)
- Only mention high_value items (score >= 5) â skip moderate and available
- If the user says yes, run the setup skill (its `setup` field, e.g. `/trello-setup`) inline, then return to the getting-started completion
- If the user says no/skip/later, move on without pressure
- Don't show this section if the user already went through integration setup during onboarding Step 10 â check the `.onboarding-complete` marker for an `integrations_offered` flag and skip if present
---
## Completion & Next Steps
After any pathway completes:
```
"**You're set up!**
**Daily workflow:**
⢠Run `/daily-plan` each morning
⢠Use `/meeting-prep [person]` before meetings
⢠Tell me about meetings - I'll extract action items
**Discovery:**
⢠`/dex-level-up` - Find features you haven't tried
⢠`/integrate-mcp` - Add more tools anytime
⢠`/dex-doctor` - Anytime checkup: finds what's wrong, fixes what it can on its own, guides you through the rest: https://heydex.ai/help/updating-troubleshooting.html#health-dex-doctor
⢠`/feedback` - Something misbehaving? Just say so in your own words â Dex writes the bug report for you and tells you when it's fixed. What a report can and can't contain: https://heydex.ai/help/feedback.html
⢠Smithery.ai - Browse MCP marketplace
**Come back anytime:**
⢠`/getting-started` - Run this tour again
⢠Just ask in natural language - I'll figure out what you need
What would you like to work on first?"
```
Update marker file:
```python
marker_data['phase2_completed'] = True
marker_data['phase2_completed_at'] = datetime.now().isoformat()
marker_data['pathways_completed'] = selected_pathways
```
---
## Usage Log Integration
Before showing suggestions, check `System/usage_log.md`:
```python
usage = read_usage_log()
tried_features = [f for f, checked in usage.items() if checked]
# Adaptive suggestions based on what they've used
if len(tried_features) < 3:
# New user - basics
suggest = ["daily-plan", "meeting-prep"]
elif "meeting-prep" not in tried_features and has_calendar:
# Have meetings but haven't prepped
suggest = ["meeting-prep"]
elif "process-meetings" not in tried_features and has_granola:
# Have Granola but haven't processed
suggest = ["process-meetings"]
else:
# Power user - advanced features
suggest = get_advanced_features(usage, role)
```
Don't show features they've already tried - focus on gaps.
---
## Escape Hatches
At EVERY major decision point:
- "This is a lot - want to pause and come back later?"
- "No pressure - you can always run `/getting-started` again"
- "Want to explore on your own first? That's cool"
After full tour:
- "Remember - invoke `/dex-level-up` to discover more"
- "Or `/integrate-mcp` to add tools as you need them"
- "The system grows with you"
---
## Success Metric
The moment they think: **"How did it know to do that?"**
Different magic for different situations:
- **With data:** Analyzed calendar/Granola intelligently, offered smart actions
- **Without data:** Built working integration in 2 minutes from just a name
- **Either way:** They see value immediately and know where to go next
---
## Helper: Analyze Granola Data Extent
Before presenting choices, discover how much Granola data is available:
```python
def analyze_granola_extent(user_email_domain: str, extended: bool = False) -> dict:
"""
Discover how much Granola data is available
Args:
user_email_domain: User's company email domain for internal/external classification
extended: If True, fetch up to 2 years. If False, fetch 6 months (default)
Returns:
Dictionary with extent analysis or None if no data
"""
from datetime import datetime
# Default to 6 months for speed, optionally extend to 2 years
days_to_fetch = 365 * 2 if extended else 180
result = granola_get_recent_meetings(days_back=days_to_fetch, limit=1000)
if not result.get('success') or not result.get('meetings'):
return {
'meetings_count': 0,
'days_back': 0,
'has_data': False
}
meetings = result['meetings']
# Find oldest and newest dates
dates = [m['date'] for m in meetings if m.get('date')]
if not dates:
return {'meetings_count': 0, 'days_back': 0, 'has_data': False}
oldest = min(dates)
newest = max(dates)
# Calculate days back
oldest_dt = datetime.fromisoformat(oldest)
newest_dt = datetime.fromisoformat(newest)
days_back = (newest_dt - oldest_dt).days + 1 # +1 to include both days
# Extract unique people and companies
people = set()
internal_people = set()
external_people = set()
companies = set()
# Normalize user domain for comparison
user_domains = [d.strip().lower() for d in user_email_domain.split(',')]
for meeting in meetings:
for participant in meeting.get('participants', []):
name = participant.get('name')
email = participant.get('email')
if name:
people.add(name)
if email:
domain = email.split('@')[1].lower() if '@' in email else None
# Classify as internal or external
if domain and any(d in domain or domain in d for d in user_domains):
internal_people.add(name)
else:
external_people.add(name)
if domain:
companies.add(domain)
else:
# No email provided - default to external
external_people.add(name)
# Calculate meetings in different time ranges for estimation
now = datetime.now()
meetings_7d = sum(1 for m in meetings if m.get('date') and
(now - datetime.fromisoformat(m['date'])).days <= 7)
meetings_30d = sum(1 for m in meetings if m.get('date') and
(now - datetime.fromisoformat(m['date'])).days <= 30)
meetings_90d = sum(1 for m in meetings if m.get('date') and
(now - datetime.fromisoformat(m['date'])).days <= 90)
# Check if there might be more data beyond what we fetched
has_more = False
if not extended and len(meetings) >= 900: # Close to limit, likely more data
has_more = True
# Check if oldest meeting is exactly at the boundary (suggests more data)
if not extended and days_back >= 175: # Close to 180 days
has_more = True
return {
'has_data': True,
'meetings_count': len(meetings),
'days_back': days_back,
'oldest_date': oldest,
'newest_date': newest,
'unique_people': len(people),
'internal_people': len(internal_people),
'external_people': len(external_people),
'unique_companies': len(companies),
'people_sample': list(people)[:10],
'companies_list': list(companies),
'meetings_7d': meetings_7d,
'meetings_30d': meetings_30d,
'meetings_90d': meetings_90d,
'has_more_data': has_more,
'fetched_range_days': days_to_fetch
}
```
**Usage in Flow A:**
```python
# After detecting Granola is available
user_profile = read_user_profile()
email_domain = user_profile.get('email_domain', '')
# Fetch initial 6 months
extent = analyze_granola_extent(email_domain)
if not extent['has_data']:
# Handle no data case
pass
else:
# Check if there's more data beyond 6 months
if extent['has_more_data']:
# Ask if they want to fetch more
response = prompt_user({
"questions": [{
"id": "fetch_more",
"prompt": f"I found {extent['meetings_count']} meetings going back {extent['days_back']} days. There appears to be more data beyond that. Want me to check how much more?",
"allow_multiple": false,
"options": [
{"id": "yes", "label": "Yes - show me the full extent"},
{"id": "no", "label": "No - 6 months is enough"}
]
}]
})
if response['fetch_more'] == 'yes':
# Fetch extended range (2 years)
extent = analyze_granola_extent(email_domain, extended=True)
# Show discovery summary and choice framework
pass
```
---
## Track Usage (Silent)
Call the `mark_feature_used` tool on the `dex-analytics` MCP server with `getting-started`. This ticks the feature's box in `System/usage_log.md`, which is what `/dex-level-up` reads to recommend features that have not been tried. It writes locally and sends nothing, so it runs whether or not analytics is enabled.
**Analytics (Silent):**
Call `track_event` with event_name `getting_started_completed` and properties:
- calendar_connected
- granola_connected
- artifacts_created
This only fires if the user has opted into analytics. No action needed if it returns "analytics_disabled".