Skip to main content

Last-in-first-out (LIFO), Git-inspired, LLM-assisted, Shell-friendly task manager for the busy and frequently interrupted.

Project description

tasklifo

Logo

Last-in-first-out (LIFO), Git-inspired, LLM-assisted, Shell-friendly task manager for the busy and frequently interrupted. What does this logo mean? See here for an explanation.

Why tasklifo?

Modern work is constant interruptions and context switches.

  • You juggle multiple projects and roles.
  • Your day is frequently interrupted with meetings, interruptions, and "can you just..." requests.
  • You have precious little time to sit down and carefully describe every new task - but you want your future self to have good context and actionable next steps.

Most task managers use FIFO - your latest, most urgent tasks get buried.

tasklifo is a Shell tool designed for the real world, built on Unix principles and modern technology:

  • LIFO workflow: Newest tasks are always on top - just like a stack.
  • Plain storage: Everything is local, plain-text, and human-readable.
  • Composable: Works with your shell, can be scripted, piped, or manipulated with standard Unix tools.
  • Git-like internals: Attachments and blobs are hashed (SHA-1), tasks are JSON files - safe, deduplicated, portable.
  • LLM support: Draft clear tasks with the help of language models, but you always review in your own $EDITOR.

Features

  • LIFO workflow: Latest tasks are always on top.
  • LLM-assisted task entry: Draft task title/description with any LLM that implements the OpenAI Chat Completions API.
    • Including GPT, Gemini, DeepSeek, and local models (like Ollama) via compatible endpoints.
    • Review and edit LLM feedback with $EDITOR, just like editing a Git commit message.
  • Supports attachments: Attach logs, screenshots, or any file to a task.
  • Git-like data storage: Attachments stored content-addressed, tasks as plain JSON.
  • Works everywhere: Python 2 & 3, POSIX & Windows, zero non-Python dependencies.

Installation

pip install tasklifo

Usage

In the commands below, if DIRECTORY is omitted, defaults to a user-global ~/.tasklifo. Providing DIRECTORY allows you to use different directories for different task LIFOs - for development, support, personal tasks, etc.

Initialize an empty task LIFO in DIRECTORY

python -m tasklifo [--directory DIRECTORY] init 

Push (add) a task, manually

python -m tasklifo [--directory DIRECTORY] push \
  [--title TITLE] \
  [--description DESCRIPTION] \
  [ATTACHMENT...]
  • Copies attachments to DIRECTORY/objects Git-style.
  • Creates a task JSON under DIRECTORY/tasks/active with ISO 8601 timestamp as file name, e.g., DIRECTORY/tasks/active/20250908T000000Z.json, storing:
    • Title
    • Description
    • SHA-1 hashes of attachments

Push (add) a task, with LLM assistance

python -m tasklifo [--directory DIRECTORY] llmpush \
  --api-key API_KEY \
  --base-url BASE_URL \
  --model MODEL \
  [--message MESSAGE [--message MESSAGE]...] \
  [ATTACHMENT...]
  • API_KEY, BASE_URL, MODEL follow OpenAI Chat Completions API conventions.
  • One or more --message allows adding user messages (e.g., "I have to fix this error message") into the prompt sent to the LLM.
  • If no --message is provided, ee launch the user's $EDITOR, just like editing a Git commit message.
  • Attachments are supported as usual.
  • LLM drafts task title and description.
  • No LLM hallucination accepted blindly. We launch the user's $EDITOR and allow the user edit the LLM's output, just like editing a Git commit message.

Get the top (most recent) task

python -m tasklifo [--directory DIRECTORY] top
  • Dumps top task JSON to STDOUT.

Log (list) all tasks

python -m tasklifo [--directory DIRECTORY] log [--all]
  • Dumps task JSONs to STDOUT in reverse chronological order.
  • By default, only dumps active tasks. Providing --all also dumps completed task JSONs.

Checkout (retrieve) an attachment

python -m tasklifo [--directory DIRECTORY] checkout SHA1
  • Dumps file contents to STDOUT.
  • Use redirection (e.g., > output.txt) to write to a file.

Pop (complete) a task

python -m tasklifo [--directory DIRECTORY] pop [TIMESTAMP]
  • Defaults to popping the most recent task.
  • Moves the task JSON from DIRECTORY/tasks/active to DIRECTORY/tasks/completed.
  • Dumps the moved task JSON to STDOUT.

Git-Style Local Storage

When you run python -m tasklifo [--directory DIRECTORY] init, it creates DIRECTORY with the following structure. Everything is local, plain. Fast, portable, no cloud, no lock-in, no database or server:

- DIRECTORY
  # Content-addressable store for attachments
  # Like `.git/objects/`
  - objects/
    - ab/
      - c123def...
      - ...
  # Task JSONs, with ISO 8601 timestamps as file names
  - tasks/
    # Active tasks
    - active/
      - 20250908T000000Z.json
      - ...
    # Completed tasks
    - completed/
      - 20250907T000000Z.json
      - ...

Example Task JSON

{
    "timestamp": "20250908T000000Z",
    "title": "Send follow-up email",
    "description": "Email the customer with the debugging results.\nCheck attached log file.",
    "attachments": [
        {
            "sha1": "3f784781b4289ca5b5f7dc6789b4dcf6cd5e1d3b",
            "filename": "debug-log.txt"
        }
    ],
    "status": "active"
}

Philosophy

  • Interrupt-driven workflow: Treat new tasks as stack "pushes", pop each as done, and never lose momentum - even after being interrupted.
  • Context always captured: Attach files, add detail, or use LLMs for well-formed entries without blank-page anxiety.
  • Human-in-the-loop: LLM outputs are never saved without your review in an editor.
  • Unix philosophy, local control:
    • Do one thing well: tasklifo just manages your LIFO task stack - no agenda, calendars, or proprietary ecosystem.
    • Text streams and composition: Input and output are simple. Pipe, redirect, and script as needed.
    • Local-first, human-readable: No lock-in, no cloud, no silo. All your data is immediately accessible.
    • Git-inspired design: Secure, deduplicated file storage; import into Git for versioning if you wish.

Future Work: LLM-powered Semantic Search

Why LLM-Powered Semantic Search?

  • Traditional search is keyword-based. If you forgot an exact phrase or typo, you're out of luck.
  • Semantic search (using LLM embeddings) lets you "find what you meant" - by intent, related concepts, even tone - across your tasks and attached content.
  • Burn out and memory issues: If you only remember a fuzzy idea ("something about logs from last week" or "the meeting with the urgent customer bug"), you can still find it.

Command Synopsis

python -m tasklifo [--directory DIRECTORY] llmgrep "all tasks where I attached a legal contract for review"

Testing

  • Make sure you have coverage installed.
  • Set the $API_KEY, $BASE_URL, $MODEL environment variables.

Quick Test

# Should either print "Initialized tasklifo in '/home/$USER/.tasklifo'"
# Or raise an exception if you have already initialized
python -m coverage run --append tasklifo.py init

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Task description", 
#  "timestamp": "...", 
#  "title": "My Task"
#}
python -m coverage run --append tasklifo.py push --title "My Task" --description "Task description"

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Task description", 
#  "timestamp": "...", 
#  "title": "My Task"
#}
python -m coverage run --append tasklifo.py top

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Second task description", 
#  "timestamp": "...", 
#  "title": "My Second Task"
#}
python -m coverage run --append tasklifo.py push --title "My Second Task" --description "Second task description"

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Second task description", 
#  "timestamp": "...", 
#  "title": "My Second Task"
#}
python -m coverage run --append tasklifo.py top

# Should print two JSONs resembling:
#{
#  "attachments": [], 
#  "description": "Second task description", 
#  "timestamp": "...", 
#  "title": "My Second Task"
#}
#{
#  "attachments": [], 
#  "description": "Task description", 
#  "timestamp": "...", 
#  "title": "My Task"
#}
python -m coverage run --append tasklifo.py log

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Second task description", 
#  "timestamp": "...", 
#  "title": "My Second Task"
#}
python -m coverage run --append tasklifo.py pop

# Should print a JSON resembling:
#{
#  "attachments": [], 
#  "description": "Task description", 
#  "timestamp": "...", 
#  "title": "My Task"
#}
python -m coverage run --append tasklifo.py log

# Should print two JSONs resembling:
#{
#  "attachments": [], 
#  "description": "Second task description", 
#  "timestamp": "...", 
#  "title": "My Second Task"
#}
#{
#  "attachments": [], 
#  "description": "Task description", 
#  "timestamp": "...", 
#  "title": "My Task"
#}
python -m coverage run --append tasklifo.py log --all

# Should start an interactive session
# Should print a JSON resembling:
#{
#  "attachments": [
#    {
#      "filename": "README.md", 
#      "sha1": "..."
#    }
#  ], 
#  "description": "Revise the tasklifo README to improve clarity, organization, and completeness. Ensure sections are clearly written, concise, and easy to follow. Check for grammar and style consistency, fill in any missing information, and enhance formatting where needed for better readability.", 
#  "timestamp": "...", 
#  "title": "Polish the tasklifo README for clarity and completeness"
#}
# Should also print diagnostic information to STDERR
python -m coverage run --append tasklifo.py llmpush \
  --api-key $API_KEY \
  --base-url $BASE_URL \
  --model $MODEL \
  --message "$(cat README.md)" \
  --message "I have to polish this readme" \
  README.md
  
# Replace $SHA1 with actual SHA-1 of README.md
# Should print first few lines of README.md
python -m coverage run --append tasklifo.py checkout $SHA1 | head

Coverage Visualization

python -m coverage html

Then view tasklifo_py.html inside your browser.

Explanation of Logo

This logo is not a logo. It wears the posture of a crest, yet rejects the entire Western European grammar of heraldry:

No cross, no shield, no lions or eagles.

Instead: the North Asian cosmology of five colors and five directions:

  • East - Electric Blue (#7df9ff): Python, creation and vitality.
  • West - White (#ffffff): Ollama, wisdom and guardianship.
  • South - Electric Red (#e60000): Git, flow and collaboration.
  • North - Black (#000000): Bash, depth and command.
  • Center - Electric Amber (#ffbf00): JSON, simplicity and fidelity.

The motto "与时偕行 / Tempus Sequi" is not in solemn Latin, but in # - at once a Markdown header, a satire of pompous mottos, and a mark of today's hashtag culture.

This is, thoroughly, a parody - of heraldry's authority, of its empty solemnity.

And also, a reconstruction - a new cosmogram of time and code, guarded by modern mascots.

Contributing

Contributions are welcome! Please submit pull requests or open issues on the GitHub repository.

License

This project is licensed under the AGPL-3.0 License.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

tasklifo-0.1.0a1.tar.gz (21.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

tasklifo-0.1.0a1-py2.py3-none-any.whl (21.8 kB view details)

Uploaded Python 2Python 3

File details

Details for the file tasklifo-0.1.0a1.tar.gz.

File metadata

  • Download URL: tasklifo-0.1.0a1.tar.gz
  • Upload date:
  • Size: 21.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.2

File hashes

Hashes for tasklifo-0.1.0a1.tar.gz
Algorithm Hash digest
SHA256 d9f53660f47d8a5b43a60f5524e71dca5e523e7d7b4e78995357c833c3915b79
MD5 7cd88da070ecff86235d25f45b6c89c6
BLAKE2b-256 33f551a22280b984980fcba63dce1e4956c700969cc0a88ef94860e0c6b5b19c

See more details on using hashes here.

File details

Details for the file tasklifo-0.1.0a1-py2.py3-none-any.whl.

File metadata

  • Download URL: tasklifo-0.1.0a1-py2.py3-none-any.whl
  • Upload date:
  • Size: 21.8 kB
  • Tags: Python 2, Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.12.2

File hashes

Hashes for tasklifo-0.1.0a1-py2.py3-none-any.whl
Algorithm Hash digest
SHA256 9da4f0658b75714fb716c9bfb36bec2300f4a81b0ec7c71f0226336fca2e7c18
MD5 6515fad7e2fbccf2e80ef813ce772854
BLAKE2b-256 80d4ac969c68af6853919366403030ecd43433832dcceb8e6e9dd7fb03869a7f

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page