Skip to content

Latest commit

 

History

History
258 lines (187 loc) · 7.58 KB

File metadata and controls

258 lines (187 loc) · 7.58 KB

yatl Specification

Version: 0.1.0

Overview

A minimal, file-based task tracking system designed for use with git repositories. Tasks are stored as individual markdown files with YAML frontmatter, enabling both human editing and programmatic access.

Directory Structure

.tasks/
  config.yaml              # Optional: project-level configuration
  .gitattributes           # Git merge strategy configuration
  open/                    # Ready to work on
    a1b2c3d4.md
  in-progress/             # Currently being worked on
    c3d4e5f6.md
  blocked/                 # Waiting on dependencies
    e5f6g7h8.md
  closed/                  # Completed successfully
    f7g8h9i0.md
  cancelled/               # Will not be done
    h9i0j1k2.md

Status is determined by directory location, not stored in the file. Tasks move between directories when their status changes. This makes find .tasks/open -name '*.md' a trivial way to list active work.

File Naming Convention

{id}.md

Where {id} is an 8-character Crockford base32 identifier like a1b2c3d4.

IDs are generated from random bytes to ensure uniqueness even with concurrent task creation.

Examples:

  • a1b2c3d4.md
  • c3d4e5f6.md

Task File Format

---
yatl_version: 1
title: Fix login bug with special characters
id: a1b2c3d4
created: 2025-11-25T10:30:45Z
updated: 2025-11-25T14:22:00Z
author: brian
priority: high
tags:
  - bug
  - auth
blocked_by: []
---

Users cannot log in when their password contains special characters like `&` or `<`.

## Reproduction

1. Create account with password `test&pass`
2. Log out
3. Attempt to log in
4. Observe 500 error

## Acceptance Criteria

- [ ] Special characters in passwords work correctly
- [ ] Add test coverage for edge cases

---
# Log: 2025-11-25T11:00:00Z brian

Found the root cause - password is being interpolated into SQL without proper escaping in the legacy auth path.

---
# Log: 2025-11-25T14:22:00Z brian

Fixed in commit abc1234. Need to add tests before closing.

Field Definitions

Required Fields

Field Type Description
yatl_version integer Task format version (current: 1). Used for migrations.
title string Human-readable title
id string Unique 8-character Crockford base32 identifier
created ISO 8601 Creation timestamp in UTC
updated ISO 8601 Last modification timestamp

Note: Status is NOT stored in the file. It is derived from the directory the file is in.

Optional Fields

Field Type Default Description
author string - Creator's identifier
priority enum medium One of: low, medium, high, critical
tags list [] Freeform labels
blocked_by list [] Task IDs that must close before this can proceed
blocks list [] Task IDs that this task blocks (reverse of blocked_by)
parent string - Parent task ID (for hierarchies)
children list [] Child task IDs (for hierarchies)

Status Transitions

Status is determined by which directory the task file is in:

     ┌──────────────────────────────────────┐
     │                                      │
     v                                      │
   open ──────> in-progress ──────> closed  │
     │              │                       │
     │              v                       │
     └────────> blocked ────────────────────┘
     │
     └──────────────────────────> cancelled
  • open/: Ready to be worked on
  • in-progress/: Currently being worked on
  • blocked/: Cannot proceed until dependencies resolve
  • closed/: Completed successfully
  • cancelled/: Will not be done

Automatic Status Changes

When you add a blocker to a task (yatl block A B), task A is automatically moved to blocked/.

When a blocking task is closed, all tasks it was blocking are checked - if they have no remaining blockers, they are automatically moved back to open/.

Log Section

The log section follows the YAML frontmatter and main description. Each log entry begins with a horizontal rule and H1 header:

---
# Log: {ISO-8601-timestamp} {author}

{message content}

Each log entry:

  • Starts with --- followed by # Log: {ISO-8601-timestamp} {author}
  • Contains freeform markdown (can include H2+ headings within the entry)
  • Is append-only (never edit previous entries)

The ---\n# Log: pattern is used because it's extremely unlikely to appear in normal markdown content, making parsing robust even when log entries contain markdown headings.

This structure makes concurrent additions merge cleanly with git's union merge strategy.

Dependencies

blocked_by

List of task IDs that must be closed or cancelled before this task can proceed.

blocked_by:
  - a1b2c3d4
  - c3d4e5f6

When you add a blocker using yatl block, the task is automatically moved to the blocked/ directory.

Determining "Ready" Tasks

A task is ready when:

  1. It is in the open/ directory
  2. All tasks in blocked_by have been closed or cancelled

Configuration File

Optional .tasks/config.yaml:

# Default author for new tasks (falls back to git config user.name)
default_author: brian

Git Integration

.gitattributes

Created automatically by yatl init:

*.md merge=union

The merge=union strategy concatenates both sides for text conflicts, which works well for the append-only log section. Frontmatter conflicts still need manual resolution, but they're small and obvious.

Commit Message Convention

yatl: short description

yatl(close): fix login bug
yatl(new): add oauth support
yatl(update): reprioritize auth work

Agent Integration

Agents can work with tasks by:

  1. CLI: Use yatl commands directly
  2. Reading: Parse YAML frontmatter + markdown body
  3. Creating: Generate file with proper naming and format
  4. Updating: Modify frontmatter fields, append to log
  5. Querying: Use find, grep, or parse all files

Example: Find Ready Tasks (pseudocode)

for each file in .tasks/open/*.md:
    parse frontmatter
    if blocked_by is empty:
        yield task
    else:
        for dep_id in blocked_by:
            if task_status(dep_id) not in [closed, cancelled]:
                break
        else:
            yield task

Note: Tasks in blocked/ are not considered ready. The automatic blocking system moves tasks to blocked/ when blockers are added and back to open/ when all blockers are resolved.

Comparison with Alternatives

Feature yatl Beads git-bug
Storage Markdown files JSONL Git objects
Status Directory-based Field-based Field-based
Dependencies Yes (blocked_by) Yes (4 types) No
Merge handling Git default + union Custom driver Lamport timestamps
Query File parsing SQL (SQLite) Custom index
Setup Install binary Install binary Install binary
Human editable Yes No No
Agent friendly Yes Yes Needs CLI

Future Considerations

Things explicitly not in v0.1 that could be added:

  • Templates: .tasks/templates/bug.md, etc.
  • Time tracking: Log entries with duration metadata
  • Kanban board generation: Static HTML from task data
  • SQLite cache: For faster queries on large task sets
  • Git hooks: Automatic syncing