Skip to main content
Glama

sync_daily_note

Sync completed tasks from Obsidian daily notes to Coach AI's database using markdown checkboxes, enabling bidirectional task management for productivity workflows.

Instructions

Sync completed tasks from Obsidian daily note to database.

NEW TOOL - Bidirectional sync: Reads markdown checkboxes (- [x]) from your daily note and automatically marks matching todos as complete in the database. Uses fuzzy matching to handle partial text matches.

This enables an Obsidian-first workflow: work in your daily note, check off tasks there, then sync back to Coach AI's database.

Args: date_str: Optional date in YYYY-MM-DD format (defaults to today)

Returns: Summary of tasks synced and any warnings about unmatched checkboxes

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
date_strNo

Implementation Reference

  • The core implementation of the sync_daily_note logic which interacts with the Obsidian vault and the database to update task statuses.
    async def sync_daily_note(date_str: str = None) -> str:
        """Sync completed tasks from Obsidian daily note to database.
    
        NEW TOOL - Bidirectional sync:
        Reads markdown checkboxes from daily note and marks matching
        todos as complete in the database.
    
        Args:
            date_str: Optional date in YYYY-MM-DD format (defaults to today)
    
        Returns:
            Summary of synced tasks
        """
        vault = get_vault()
        if not vault:
            return "āŒ Obsidian vault not configured."
    
        if date_str:
            try:
                target_date = datetime.strptime(date_str, "%Y-%m-%d").date()
            except ValueError:
                return f"āŒ Invalid date format: {date_str}"
        else:
            target_date = date.today()
    
        db = await get_db()
    
        sync_result = await _sync_completed_tasks(vault, target_date, db)
    
        result = f"šŸ“ Synced daily note for {target_date.strftime('%Y-%m-%d')}\n\n"
    
        if sync_result["completed_count"] > 0:
            result += f"āœ… Marked {sync_result['completed_count']} tasks complete:\n"
            for task in sync_result["completed_tasks"]:
                result += f"   - {task}\n"
        else:
            result += "No new completed tasks found.\n"
    
        if sync_result["warnings"]:
            result += f"\nāš ļø  {len(sync_result['warnings'])} checkboxes couldn't be matched to todos\n"
    
        return result
  • MCP tool registration for sync_daily_note which delegates execution to the daily_notes module.
    @mcp.tool()
    async def sync_daily_note(date_str: str = None) -> str:
        """Sync completed tasks from Obsidian daily note to database.
    
        NEW TOOL - Bidirectional sync:
        Reads markdown checkboxes (- [x]) from your daily note and automatically
        marks matching todos as complete in the database. Uses fuzzy matching to
        handle partial text matches.
    
        This enables an Obsidian-first workflow: work in your daily note, check
        off tasks there, then sync back to Coach AI's database.
    
        Args:
            date_str: Optional date in YYYY-MM-DD format (defaults to today)
    
        Returns:
            Summary of tasks synced and any warnings about unmatched checkboxes
        """
        return await daily_notes.sync_daily_note(date_str)
  • Internal helper _sync_completed_tasks that performs the actual database operations and fuzzy matching for the sync.
    async def _sync_completed_tasks(
        vault: ObsidianVault, target_date: date, db: aiosqlite.Connection
    ) -> dict:
        """Internal helper to sync completed tasks from daily note.
    
        Returns:
            Dict with completed_count, completed_tasks list, and warnings
        """
        note_data = vault.read_daily_note(datetime.combine(target_date, datetime.min.time()))
    
        if not note_data:
            return {"completed_count": 0, "completed_tasks": [], "warnings": []}
    
        completed_checkboxes = [
            task for task in note_data.get("tasks", []) if task.get("completed")
        ]
    
        if not completed_checkboxes:
            return {"completed_count": 0, "completed_tasks": [], "warnings": []}
    
        # Get all active todos from database
        cursor = await db.execute(
            "SELECT id, title FROM todos WHERE status = 'active'"
        )
        active_todos = {row["id"]: row["title"] for row in await cursor.fetchall()}
    
        completed_tasks = []
        warnings = []
    
        for checkbox in completed_checkboxes:
            checkbox_text = checkbox["text"]
    
            # Try to match checkbox to a todo
            matched_id = _fuzzy_match_task(checkbox_text, active_todos)
    
            if matched_id:
                # Mark as complete
                await db.execute(
                    "UPDATE todos SET status = 'completed', completed_at = ? WHERE id = ?",
                    (datetime.now().isoformat(), matched_id),
                )
                completed_tasks.append(active_todos[matched_id])
            else:
                warnings.append(checkbox_text)
    
        await db.commit()
    
        return {
            "completed_count": len(completed_tasks),
            "completed_tasks": completed_tasks,
            "warnings": warnings,
        }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/94aharris/coach-ai'

If you have feedback or need assistance with the MCP directory API, please join our Discord server