mcpbeat

State Management

microsoft/state-management

How to manage workflow state and tasks.md files

3k tokens
context cost
the whole folder, loaded on every use
1
files
instructions only
0
copies elsewhere
how many repositories repackaged it
17
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/microsoft/upgrade-agent-plugins --skill state-management

The instruction itself

26 sections, as written by the author

State Management Guide

Instructions for managing workflow state files.

> This skill covers 8 sections. Read all before starting work.

>

> | # | Section | Key Content |

> |---|---------|-------------|

> | 1 | State Files Overview | File purposes, ownership, including task.md |

> | 2 | tasks.md | Template, recent activity format |

> | 3 | Scenario Instructions | Location, preferences format |

> | 4 | State Operations | get_state, start_task, complete_task, break_down_task |

> | 5 | Tool-Driven Navigation | Use availableTasks from tool responses |

> | 6 | File Consistency & Reconciliation | Critical — source of truth hierarchy, drift detection, reconciliation protocol |

> | 7 | Progress Bar Calculation | Counting rules, update timing |

> | 8 | Context Recovery | Cold-start / post-compaction re-sync steps, recall-intent table |

State Files Overview

| File | Purpose | Updated By |

|------|---------|------------|

| tasks.md | Human-readable progress view | Tools (structure) + LLM (activity) |

| scenario-instructions.md | Scenario spec and preferences | LLM + User |

| tasks/{taskId}/task.md | Per-task description enriched with research — everything needed to execute the task | LLM (enriched during execution) |

tasks.md

Location: {RepoRoot}/.github/upgrades/{scenarioId}/tasks.md

Updated by:

  • Tools: Structure, task hierarchy, statistics
  • LLM: Recent activity section

Template

# Migration Progress

**Progress**: 0/{totalTasks} tasks complete <progress value="0" max="100"></progress> 0%
**Status**: In Progress - Task {currentTaskId}
**Started**: {startDate}
**Last Updated**: {lastUpdate}

## Task Hierarchy
{generated from state.json}

**Legend**: ✅ Complete | 🔄 In Progress | 🔲 Pending | ⚠️ Blocked | ❌ Failed

## Current Focus
🔄 **{taskId}**: {taskName}
[Details](tasks/{taskId}/task.md) | [Changes](tasks/{taskId}/progress-details.md)

## Recent Activity
{LLM appends single line per event with timestamp}

## Statistics
- Total Tasks: {totalTasks}
- Completed: {completedTasks} ({percentage}%)
- Files Modified: {filesModified}
- Projects Updated: {projectsUpdated}/{projectsTotal}

Updating Recent Activity

After each significant event, append to Recent Activity:

- {timestamp}: {brief description of what happened}

Examples:

  • 2024-01-15 10:30: Completed 02.01-common-lib - updated 5 packages
  • 2024-01-15 10:45: Started 02.02-utils-lib
  • 2024-01-15 11:00: Broke down 03-shared-libraries into 3 subtasks

Scenario Instructions

Location: {RepoRoot}/.github/upgrades/{scenarioId}/scenario-instructions.md

This file is ALWAYS IN CONTEXT when a workflow is active.

Contains:

  • Strategy approach
  • User preferences (flat key-value list)
  • Key decisions made during the workflow
  • Custom per-task instructions

Reading User Preferences

Check the Preferences and Custom Instructions sections before executing any task:

## Preferences
- **Pace**: {Standard | Fast | Methodical}
- {other scenario-specific preferences}

## Custom Instructions
<!-- Task-specific overrides: "For {taskId}: {instruction}" -->

State Operations

Getting Current State

get_state(path)

Returns:

  • inProgressTask: Currently active task (if any)
  • availableTasks: Tasks ready to execute (no blockers)
  • blockedTasks: Tasks waiting on dependencies
  • completedTasks: Finished tasks
  • progress: Completion statistics
  • staleTaskWarnings: Tasks stuck in 🔄 from a previous session (see Stale Task Warnings)

Starting a Task

start_task(taskId)

Returns:

  • task: Task details (id, name, complexity, projects)
  • folderCreated: Path to task folder (created JIT)
  • needsBreakdown: Whether task should be broken down
  • userInstructions: Content from existing task.md (if pre-created)
  • staleTaskWarnings: Tasks stuck in 🔄 from a previous session (see Stale Task Warnings)

Updates:

  • tasks.md: Task shown as 🔄 In Progress
  • Creates tasks/{taskId}/ folder if doesn't exist

Completing a Task

complete_task(taskId, filesModified)

Returns:

  • completed: Task that was completed
  • availableTasks: Next tasks ready to execute
  • blockedTasks: Tasks still waiting on dependencies
  • progress: Updated completion statistics

Updates:

  • tasks.md: Task shown as ✅ Complete, statistics and progress bar updated

Failing a Task

complete_task(taskId, filesModified, failed=true, errorMessage="...")

Returns:

  • availableTasks, blockedTasks: For navigation
  • error: Error message

Updates:

  • tasks.md: Task shown as ❌ Failed

Breaking Down a Task

break_down_task(parentTaskId, subtasks)

Declarative: provide the complete desired subtask list. Calling again reconciles automatically.

Returns:

  • subtasksCreated: List of created subtasks
  • subtasksRemoved: List of removed subtask IDs (if any existing children were not in the new list)
  • availableTasks: First subtask(s) ready to execute
  • blockedTasks: Subtasks waiting on siblings

Updates:

  • tasks.md: Shows subtasks in hierarchy
  • Creates tasks/{subtaskId}/ folders (empty, ready for task.md)
  • Removes non-completed children not in the new list (entries + task folders)
  • Preserves completed subtasks and existing subtasks with matching IDs (keeps their state)

Tool-Driven Navigation

Key Principle: Every state-changing tool returns availableTasks - use this to determine the next task to execute.

After each tool call:
- If availableTasks is not empty → pick next task from list
- If availableTasks is empty and blockedTasks exist → report blockers
- If availableTasks is empty and no blockedTasks → workflow complete

DO NOT parse tasks.md to determine next task - use tool responses.

Stale Task Warnings

get_state and start_task may return a staleTaskWarnings array — tasks that are marked 🔄 In Progress but appear to be left over from a prior session.

Each warning contains:

  • TaskId: The stale task's ID
  • Description: What the task is
  • Instruction: Specific action to take

Handle stale warnings before starting new work:

  • Follow the Instruction in each warning
  • Assess the task's state — check its task folder for evidence of completed work (e.g., progress-details.md, code changes)
  • Call complete_task(taskId) to finalize it, or complete_task(taskId, failed=true) to abandon it

Stale warnings indicate state inconsistency. Do not ignore them.

*Continue reading — Sections 6-7 cover file consistency, drift detection, and progress bar calculation.*

Best Practices

  • Call get_state(path) at start of each interaction to know current state
  • Use tools for all state changes - never edit state files directly
  • Keep tasks.md readable - users view this for status
  • Log decisions in scenario-instructions.md Decisions section
  • Update progress after every change to maintain visibility

File Consistency & Reconciliation

Source of Truth Hierarchy

When files conflict, this is the priority order:

  • plan.md — authoritative for what tasks exist and their scope
  • tasks.md — derived view, can always be regenerated from plan.md + completion state
  • tasks/{taskId}/task.md — elaboration only, doesn't define the task list
  • Tool state (scenario properties taskStates) — authoritative for task states recorded by start_task/complete_task

Detecting Drift

get_state(path) returns fileTimestamps for plan.md, tasks.md, and scenario-instructions.md.

At the start of each conversation turn:

  • Call get_state(path)
  • Compare fileTimestamps against what you last saw
  • If plan.md is newer → re-read it, check if tasks were added/removed/reordered
  • If tasks.md is newer → user probably intended to edit the plan; re-read and treat as plan change
  • If scenario-instructions.md is newer → re-read for updated preferences

Reconciliation Protocol

When plan.md changed (tasks added, removed, or reordered):

  • Re-read plan.md
  • Regenerate tasks.md to match (preserve completion statuses for unchanged tasks)
  • If a removed task had a folder with work in it → warn user before deleting reference

When tasks.md was edited directly:

  • Re-read tasks.md to understand user intent
  • Propagate changes back to plan.md if task list changed
  • Regenerate tasks.md cleanly (it's a derived view)

When user says "I edited X":

  • Re-read the file they mention
  • Diff against your last known state
  • Propagate changes to dependent files
  • Confirm changes with user before proceeding

What NOT to Reconcile

  • progress-details.md files — append-only history, never needs reconciliation
  • task.md elaborations — these refine scope, they don't define the task list
  • Scenario properties — managed by tools, not user-editable

*Continue reading — Section 7 covers progress bar counting rules.*

Progress Bar Calculation

The Progress line in tasks.md tracks completion across all tasks and subtasks:

**Progress**: {completed}/{total} tasks complete <progress value="{percent}" max="100"></progress> {percent}%

Counting rules:

  • Count every task and subtask equally (flat count)
  • When a parent is broken down, count only its subtasks, not the parent itself
  • A task counts as "completed" only when status is ✅
  • total = all leaf tasks + unbroken parents
  • percent = floor(completed / total * 100)

Update this line after every complete_task() or break_down_task() call, using the progress statistics from the tool response.

Context Recovery

Use these steps when starting a new session, or after context compaction (you can't reliably

recall the active scenario, current stage, or recent tasks).

Detecting Context Compression

Context compression can happen mid-session without warning. Signs it occurred:

  • You remember *that* you loaded a skill but can't recall its *specific instructions* (only vague concepts)
  • You can't recall what happened in the last few tasks or what tools returned
  • You feel uncertain about the current state or recent decisions

Standard Recovery Steps

  • Call get_state(path) — re-establish current scenario, task progress, available/blocked tasks.
  • Re-read scenario-instructions.md — your persistent memory (user preferences, decisions,

custom instructions, flow mode).

  • If a task is in-progress, read tasks/{taskId}/task.md — working memory for that task.
  • For recent context, read progress-details.md of the last 1-2 completed tasks — what

actually changed, build results, issues resolved.

  • Re-load all skills for the current task — do not assume they are still in context. The cost

of reloading is seconds; the cost of executing without them is wrong decomposition, missed

tools, and failed migrations.

Recall Intents

| User intent | Source | Example phrases |

|---|---|---|

| Recent activity | progress-details.md of completed tasks | "what happened?", "recap", "catch me up" |

| Task-specific history | tasks/{taskId}/task.md + progress-details.md | "what happened with task X?" |

| Overall status | get_state(path) + tasks.md | "status", "where are we?" |

How to use it

Copy the folder

Take microsoft/state-management from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.