-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Description
Summary
Add an optional metadata: Record<string, unknown> field to tasks and subtasks that allows users to store arbitrary key-value pairs. This field would be preserved across all task operations (moves, updates, expansions, etc.), enabling users to track custom identifiers, external references, and workflow-specific data without requiring schema changes.
Motivation
Currently, if users want to associate custom data with tasks (UUIDs, GitHub issue numbers, external system references, custom workflow states, etc.), they have two problematic options:
- Manually edit tasks.json - Works initially, but custom fields are lost when tasks pass through
TaskEntity.toJSON()serialization (e.g., duringgetTaskList()) - Request schema changes - Requires PRs and releases for each new field type
This creates friction for common use cases:
- Linking tasks to GitHub Issues for team coordination
- Tracking stable UUIDs that survive task renumbering/moving
- Storing project-specific workflow metadata (sprint IDs, cost centers, etc.)
- Integrating with external project management tools (Linear, Jira, etc.)
A metadata field solves this by providing a dedicated, schema-stable extension point that Task Master commits to preserving.
Related Issues
- Feature: GitHub Integration #11 (GitHub Integration) - Users want to link tasks to GitHub Issues;
metadataprovides an immediate workaround and future integration point - feat: Task Affected Assets Tracking #1176 (Task Affected Assets Tracking) - Proposes
affectedAssetsfield;metadatacould serve as a generalized version of this pattern - feat: support or Use .md Files with YAML Frontmatter Instead of JSON #707 (YAML Frontmatter) - Seeks better human editability;
metadataallows custom data without format changes - feat: Improve documentation & convert PRD/task files to MDX with front-matter metadata #363 (MDX with front-matter) - Similar extensibility goals;
metadataachieves this within current JSON structure
Proposed Solution
Schema Change
Add an optional metadata field to the Task and Subtask interfaces:
// packages/tm-core/src/common/types/index.ts
export interface Task extends TaskImplementationMetadata {
// ... existing fields ...
/**
* User-defined metadata that survives all task operations.
* Use for external IDs, custom workflow data, integrations, etc.
*/
metadata?: Record<string, unknown>;
}
export interface Subtask extends Omit<Task, 'id' | 'subtasks'> {
// ... existing fields ...
// metadata is inherited from Task
}Implementation Changes
1. Update TaskEntity to preserve metadata
// packages/tm-core/src/modules/tasks/entities/task.entity.ts
export class TaskEntity implements Task {
// Add property
metadata?: Record<string, unknown>;
constructor(data: Task) {
// ... existing assignments ...
this.metadata = data.metadata;
}
toJSON(): Task {
return {
// ... existing fields ...
metadata: this.metadata, // Preserve in serialization
};
}
}2. Preserve in storage operations (already works)
The existing FileStorage methods already use spread operators that preserve extra fields:
// FileStorage.normalizeTaskIds - already preserves via ...task spread
// FileStorage.updateTask - already merges via ...tasks[taskIndex] spreadNo changes needed here, but tests should verify preservation.
3. Preserve in AI-generated task updates
When AI operations (parse-prd, expand, update-task) generate new task data, existing metadata should be merged:
// When updating a task with AI-generated content
const updatedTask = {
...existingTask, // Preserve existing metadata
...aiGeneratedUpdates, // Apply AI updates
metadata: {
...existingTask.metadata, // Keep existing metadata
...aiGeneratedUpdates.metadata, // Allow AI to add metadata
},
};High-Level Workflow
- User manually adds metadata to
tasks.jsonor via future CLI/MCP commands - All task operations (list, update, expand, move) preserve the metadata
- External tools can read/write metadata for integrations
- AI operations merge (not replace) metadata when updating tasks
Key Elements
Task with metadata example
{
"id": "1",
"title": "Implement user authentication",
"description": "Add OAuth2 login flow",
"status": "in-progress",
"priority": "high",
"dependencies": [],
"details": "...",
"testStrategy": "...",
"subtasks": [],
"metadata": {
"uuid": "550e8400-e29b-41d4-a716-446655440000",
"githubIssue": 42,
"githubIssueUrl": "https://github.com/org/repo/issues/42",
"linearId": "ENG-123",
"sprint": "2025-Q1-S3",
"estimatedHours": 8,
"customWorkflowState": "design-review"
}
}CLI enhancements (future, out of initial scope)
# Set metadata via CLI
$ task-master update-task --id=1 --metadata='{"githubIssue": 42}'
# Query tasks by metadata
$ task-master list --filter="metadata.sprint=2025-Q1-S3"MCP tool enhancements (future, out of initial scope)
// update_task tool accepts metadata parameter
update_task({
id: "1",
metadata: { githubIssue: 42 }
})Example Workflow
# User creates a task
$ task-master add-task --prompt "Implement OAuth login"
→ Created task 15: "Implement OAuth login"
# User manually adds metadata to tasks.json
# (or via future CLI command)
{
"id": "15",
"title": "Implement OAuth login",
"metadata": {
"uuid": "a1b2c3d4-...",
"githubIssue": 99
}
}
# Later, task is expanded with subtasks
$ task-master expand --id=15 --num=3
→ Added 3 subtasks to task 15
# Metadata is preserved!
$ task-master show 15 --json | jq '.metadata'
{
"uuid": "a1b2c3d4-...",
"githubIssue": 99
}
# Even if task 15 were renumbered/moved (future feature),
# the UUID allows tracking the same logical taskImplementation Considerations
Backward Compatibility
- The field is optional; existing
tasks.jsonfiles work unchanged - Reading old files:
metadataisundefined, which is valid - Writing: only include
metadatakey if it has content (avoid clutter)
AI Operation Behavior
- parse-prd: New tasks have no metadata (or allow PRD to define it)
- expand: Subtasks can inherit parent's metadata or start empty (configurable?)
- update-task/update-subtask: AI prompts should not overwrite existing metadata unless explicitly instructed
Performance
- No impact; metadata is just another JSON field
- No indexing needed for initial implementation
Validation
- Minimal validation: must be a plain object if present
- No schema enforcement on metadata contents (that's the point)
- Consider max size limit to prevent abuse (e.g., 64KB)
Security
- Metadata is stored in plain text in
tasks.json - Users should not store secrets (same as other task fields)
- Document this in usage guidelines
Out of Scope (Future Considerations)
- CLI commands for metadata (
--metadataflag,--filterby metadata) - MCP tool parameters for reading/writing metadata
- Metadata schema validation (optional user-defined schemas)
- Automatic metadata (auto-generate UUIDs on task creation)
- Metadata inheritance (subtasks inheriting parent metadata)
- GitHub/Linear/Jira sync using metadata as the linking mechanism
- VS Code extension displaying/editing metadata
Testing Requirements
- Unit tests:
TaskEntitypreserves metadata throughtoJSON() - Integration tests: metadata survives full task lifecycle (create, update, expand, list)
- Regression tests: existing tasks without metadata continue to work
Migration
No migration needed - this is purely additive. Existing tasks.json files are compatible.
Checklist for Implementation
- Add
metadata?: Record<string, unknown>toTaskinterface - Add
metadata?: Record<string, unknown>toSubtaskinterface - Update
TaskEntityconstructor to accept metadata - Update
TaskEntity.toJSON()to include metadata - Add unit tests for metadata preservation
- Add integration tests for full lifecycle
- Update documentation with metadata usage examples
- Consider adding to complexity report / task generation prompts (optional)
This issue description was written with assistance from Claude Code.