Skip to content

Add optional completion tracking tools for idempotent session-start checks#14

Open
partymola wants to merge 2 commits into
jen6:mainfrom
partymola:feature/completion-tracking
Open

Add optional completion tracking tools for idempotent session-start checks#14
partymola wants to merge 2 commits into
jen6:mainfrom
partymola:feature/completion-tracking

Conversation

@partymola

Copy link
Copy Markdown

Summary

This PR adds two optional MCP tools and a SQLite-backed local store that let agents track which completed TickTick tasks they have already processed — without reading or writing growing log files at session start.

This feature is entirely opt-in. Nothing in the existing codebase changes behaviour. If you never call the new tools, nothing happens. No database file is created unless the tools are actually called.


Problem

Agents often need to react to newly completed tasks (e.g. log outcomes, trigger follow-up work). The naive approach is to read a completion log file at the start of each session and diff it against the current API response. This has two problems:

  1. The log file grows indefinitely, bloating the context window over time.
  2. There is no clean way to know which completions a given agent has already seen — without keeping state somewhere.

Solution

Two new tools backed by a local SQLite database (<dotenv-dir>/completion_tracking.db):

ticktick_get_unprocessed_completions(project_id, days=30)

  • Fetches completed tasks for a project in the given time window via the TickTick API
  • Filters out any task IDs already recorded in the local DB
  • Returns only the delta — tasks the caller has not yet processed

ticktick_mark_completion_processed(task_id, project_id, title?, completed_time?, notes?)

  • Records a task as processed in the local DB
  • Subsequent calls to ticktick_get_unprocessed_completions will skip it
  • Stores optional metadata (title, completion timestamp, notes) for a human-readable audit trail
  • Returns {"status": "already_processed"} idempotently if called twice for the same task

DB schema

CREATE TABLE completion_tracking (
    task_id        TEXT PRIMARY KEY,
    project_id     TEXT NOT NULL,
    title          TEXT,
    completed_time TEXT,
    processed_at   TEXT NOT NULL,
    notes          TEXT
)

DB is stored alongside the .env file in --dotenv-dir (defaults to ~/.config/ticktick-mcp/completion_tracking.db).


Usage pattern

Could be called at the beginning of each conversation to check for new completions:

tasks = ticktick_get_unprocessed_completions(project_id="your_project_id_here", days=30)
for task in tasks:
    # read task["content"], log outcomes, take action ...
    ticktick_mark_completion_processed(
        task_id=task["id"],
        project_id=task["projectId"],
        title=task["title"],
        completed_time=task["completedTime"],
        notes="handled",
    )

Also included

  • filter_tools.py bug fix: get_completed() was called with from_date=/to_date= keyword arguments, but the underlying ticktick-py API uses start=/end=. This fix is required for ticktick_get_unprocessed_completions to work correctly.
  • Tests: 14 tests covering all DB functions (init_db, is_processed, mark_processed, get_processed_ids_for_project) and the ticktick_mark_completion_processed MCP tool, including idempotency and isolation via temp DB paths.

What this does NOT change

  • No existing tools are modified (other than the filter_tools.py bugfix)
  • No existing configuration is affected
  • No DB is created unless the new tools are called
  • The feature is purely additive

Adds two new MCP tools backed by a local SQLite store to solve the
problem of agents re-processing already-handled completed tasks on
every session start.

ticktick_get_unprocessed_completions(project_id, days=30)
  - Fetches completed tasks in the given window via the TickTick API
  - Filters out task IDs already in the local DB
  - Returns only the delta (new completions not yet seen)

ticktick_mark_completion_processed(task_id, project_id, ...)
  - Records a task as processed in the SQLite store
  - Subsequent calls to get_unprocessed_completions will skip it
  - Stores optional title, completion timestamp, and notes for audit

DB location: --dotenv-dir / completion_tracking.db (alongside .env)
Schema: completion_tracking(task_id PK, project_id, title,
        completed_time, processed_at, notes)

Also fixes filter_tools.py: get_completed() API takes start=/end=
not from_date=/to_date=.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant