FocusFlow AI
FocusFlow is AI productivity helper + task tracker MCP
Knowledge workers-engineers, researchers, writers, students, analysts-often struggle with a peculiar paradox: they have ambitious plans, sophisticated tools, and genuine motivation, yet they still drift. A developer sits down to refactor a module, and three hours later realizes they've been scrolling through technical discussions instead of writing code. A researcher begins a literature review and ends up reading tangential papers. A student plans to complete an assignment and procrastinates until the last moment.
Traditional solutions fail in two opposing ways. Time-tracking tools feel like surveillance, adding anxiety rather than focus. Project management platforms (Jira, Linear, Asana) are too coarse-grained-"Write a research paper" becomes "Write a research paper," not the actionable "Finish literature review summary by 2 PM." And neither notices that you've been idle for 45 minutes.
FocusFlow addresses this gap by combining three powerful ideas:
The result is a system that feels like having an accountability buddy-not a boss, not a surveillance system, but a friend who knows when you're drifting and gently nudges you back.
Figure 1: FocusFlow Dashboard showing task management, productivity metrics, and active monitoring.
FocusFlow's architecture revolves around three key principles:
The user-facing interface consists of five main tabs:
This is the sensing layer of FocusFlow:
Watchdog Library
โ
Monitors: /project_path for file events
โ
Filters by task artifact patterns (glob patterns, git commits)
โ
Exposed via MCP Protocol as:
- check_project_status()
- get_file_changes_since(timestamp)
- get_git_commits_for_task(task_id)
โ
Consumed by: Claude Desktop, Agent Core Logic
Key innovation: Instead of tracking time spent, FocusFlow tracks meaningful changes. A new .py file, a git commit, or specific file modifications count as evidence of progress. This defeats procrastination disguised as "I was thinking about it."
Rather than direct API polling, FocusFlow uses Linear's MCP server (if available) or falls back to API:
This bidirectional sync ensures users can manage tasks in Linear (their familiar tool) while FocusFlow monitors completion in real-time.
The decision engine runs on a configurable schedule (default: 30-second checks):
For each active task:
expected_outcome = task.artifact_pattern
actual_artifacts = check_file_system()
if artifact_matches(actual_artifacts, expected_outcome):
# User is on track
log_success()
update_focus_score(+points)
stay_silent() # Non-intrusive!
else:
# User may be distracted
idle_duration = time_since_last_change()
if idle_duration > threshold:
trigger_intervention(level="gentle_nudge")
elif idle_duration > extended_threshold:
trigger_intervention(level="voice_alert")
suggest_help(use_llm=true)
FocusFlow supports three deployment modes:
| Provider | Use Case | Privacy | Speed | Cost |
|---|---|---|---|---|
| OpenAI (GPT-4o) | Production, high complexity | Cloud-based | Fast | Paid |
| Anthropic (Claude) | Production, nuanced reasoning | Cloud-based | Fast | Paid |
| Google (Gemini) | High performance, long context | Cloud-based | Fast | Paid |
| Local (vLLM/Ollama) | Privacy-first, self-hosted | On-device | Slower | Free |
The LLM is used for:
Environment variable switches between providers:
# Cloud-based
export AI_PROVIDER=anthropic
export ANTHROPIC_API_KEY=...
# Local
export AI_PROVIDER=vllm
export VLLM_BASE_URL=http://localhost:8000/v1
Text-to-speech powers the friendly nudges:
Example voice prompt:
"Hey! I noticed you switched to Reddit. I get it-takes
a break sometimes. But you've got 12 more minutes on
'Define core message.' Ready to dive back in?"
The Model Context Protocol implementation is what elevates FocusFlow from a standalone app to an ecosystem participant.
FocusFlow exposes the following tools to any MCP client (Claude Desktop, Cursor, etc.):
{
"tools": [
{
"name": "focusflow.get_current_task",
"description": "Get the task currently being worked on",
"inputSchema": { "type": "object", "properties": {} }
},
{
"name": "focusflow.get_all_tasks",
"description": "List all tasks for the current project",
"inputSchema": { "type": "object", "properties": {} }
},
{
"name": "focusflow.get_productivity_stats",
"description": "Get focus score, distraction count, and today's stats",
"inputSchema": { "type": "object", "properties": {} }
},
{
"name": "focusflow.mark_task_done",
"description": "Mark a task as complete",
"inputSchema": {
"type": "object",
"properties": {
"task_id": { "type": "integer" },
"note": { "type": "string" }
}
}
},
{
"name": "focusflow.add_task",
"description": "Add a new task to the list",
"inputSchema": {
"type": "object",
"properties": {
"title": { "type": "string" },
"description": { "type": "string" },
"estimated_duration": { "type": "string" }
}
}
}
]
}
A user connects FocusFlow to Claude Desktop and has a conversation:
Figure 2: Claude Desktop interacting with FocusFlow via MCP to query tasks and provide assistance.
User: "What am I supposed to be doing right now?"
Claude: [calls focusflow.get_current_task]
Claude: "You're working on 'Design Header Component'
with 15 minutes remaining. The expected output is
a new file at src/components/Header.tsx."
User: "I'm stuck on styling. Can you check my project?"
Claude: [calls focusflow.get_all_tasks +
linear.get_issues (if Linear MCP available)]
Claude: "I see you have a design ticket in Linear with
Figma specs linked. Your last commit was 'WIP: header
structure' 10 minutes ago. Let me help you move forward.
Here's a styled component template based on your project's
existing pattern..."
This is the key differentiator: FocusFlow isn't isolated. It's woven into your AI agent's context, providing real-time focus state and project status alongside code suggestions and task management.
Unlike traditional productivity tools that assume "idle = distracted," FocusFlow uses multiple signals:
Signal 1: File System Events
Signal 2: Content Analysis (Optional)
node_modules, .git, common temp directories.Signal 3: Idle Duration
Signal 4: Project Context
When distraction is detected:
Level 1 (5 min idle): Silent dashboard log
Level 2 (15 min idle): Gentle notification
Level 3 (30+ min idle): Friendly voice nudge + suggestions
Key principle: Users can always ignore nudges. FocusFlow never forces action-it only reminds and suggests. The power remains with the builder.
User's Project Files
โ (Watchdog monitors)
โ
FocusFlow (SQLite database local)
โ
vLLM (running on localhost:8000)
โ
All project data stays on user's machine
What leaves the device: Only voice synthesis requests (text prompts โ audio) if ElevenLabs is enabled. No project content, file names, or task descriptions.
User's Project Files
โ
FocusFlow (SQLite local + cloud sync optional)
โ
Claude/GPT-4o/Gemini APIs (for task decomposition, suggestions)
โ
User decides: log task data or just prompts?
Privacy controls:
# Local-first setup
export LAUNCH_MODE=local
export AI_PROVIDER=vllm
export VLLM_BASE_URL=http://localhost:8000/v1
export VLLM_MODEL=ibm-granite/granite-3.0-8b-instruct
export ELEVEN_API_KEY=... # voice is optional, cloud-only
# Cloud-enhanced setup
export LAUNCH_MODE=demo
export AI_PROVIDER=anthropic
export ANTHROPIC_API_KEY=...
We chose Gradio 5 not just for rapid prototyping, but for its new MCP-native capabilities. Gradio has evolved from a simple ML demo tool into a robust framework for building AI-powered applications.
For FocusFlow, Gradio handles the complex state management required for a multi-tabbed interface-switching between the "Monitor" view (which needs real-time updates) and the "Dashboard" (which aggregates historical data) without page reloads. We leverage gr.Timer components to create a heartbeat for the application, triggering the agent's decision loop every 30 seconds.
# The heartbeat of FocusFlow
monitor_timer = gr.Timer(value=30, active=True)
monitor_timer.tick(fn=agent_decision_loop, outputs=[status_display, voice_alert])
At its core, FocusFlow is an MCP Server. This means it doesn't just "have an API"-it adheres to the Model Context Protocol standard, making it instantly compatible with any MCP client.
We use the mcp Python SDK to expose our internal logic as tools. This inversion of control is powerful: instead of building a custom plugin for Claude, we build a standard MCP server that Claude (and others) can discover and use.
@server.call_tool
def get_current_task(arguments: dict) -> str:
# This tool becomes available to Claude instantly
task = db.tasks.filter(status="active").first()
return json.dumps(task.to_dict())
To detect "work," we couldn't rely on simple CPU usage or window titles-too noisy. Instead, we implemented a file system observer using watchdog. This allows FocusFlow to listen for intent.
The system filters out noise (like __pycache__ updates or node_modules churn) and focuses on "meaningful" events: a file save, a git commit, or a new directory creation. This event stream provides the ground truth for the "Focus Score."
One of the biggest challenges was supporting both privacy-first local users and power users who want GPT-4o. We solved this with a FocusAgent abstraction layer.
This class handles the nuances of different provider APIs (OpenAI, Anthropic, Gemini, vLLM) so the rest of the app doesn't care who is generating the tokens. It also manages the "context window budget," deciding when to send full file summaries versus just task metadata based on the user's privacy settings.
We use ElevenLabs not just for text-to-speech, but for emotional feedback. The system selects different voice IDs and stability settings based on the intervention level. A gentle nudge uses a calm, stable voice; a critical alert might use a more dynamic, urgent tone. This "emotional UI" makes the AI feel more present.
FocusFlow needs to run in two very different environments:
We implemented a TaskManager that seamlessly switches between sqlite3 and Python list structures based on the LAUNCH_MODE environment variable. This ensures the demo is always clean for new visitors while local users never lose data.
class TaskManager:
def __init__(self, use_memory=False):
# Seamlessly switch strategies
self.storage = [] if use_memory else SQLiteStorage("focusflow.db")
git clone https://github.com/Rebell-Leader/FocusFlowpip install -r requirements.txtcp .env.example .env && edit .envvllm serve ... in another terminalpython app.pyhttp://localhost:5000The Monitor tab allows simulating distraction:
FocusFlow is designed to run on:
Deployment to HuggingFace Spaces:
git push hf-hub main # triggers automatic deployment
The most important design decision: FocusFlow stays silent unless there's evidence of procrastination. Users trust it more because it doesn't spam.
Building FocusFlow as an MCP server from day one makes it:
Offering local vLLM from the start:
Duolingo's success comes from personality. A simple notification with a friendly tone beats a beautifully designed but corporate message.
"30 minutes focused" is less useful than "completed 3 micro-tasks." Measure what matters.
FocusFlow demonstrates how modern AI architecture-MCP, local LLMs, voice interfaces, and agentic reasoning-can solve a deeply human problem: staying focused on what matters.
By combining friendly nudges with real project artifact monitoring, offering privacy-first deployment, and embedding itself in the AI agent ecosystem, FocusFlow isn't just another productivity tool. It's a privacy-aware, extensible, AI-native companion for builders who want to reclaim their focus without surveillance or micromanagement.
The code is open-source, the MCP server is production-ready, and the privacy guarantees are real. For anyone struggling with distraction, FocusFlow offers a path forward-one friendly nudge at a time.
Try FocusFlow: https://huggingface.co/spaces/MCP-1st-Birthday/FocusFlowAI
FocusFlow is AI productivity helper + task tracker MCP