vault-tasks
Markdown-file task manager for solo devs building with Claude Code.
Tasks are plain markdown files with YAML frontmatter. They live in your repo (or Obsidian vault), are version-controlled with git, and are readable by humans and LLMs alike. Zero runtime dependencies.
Install
npm install -g vault-tasks
Or use without installing:
npx vault-tasks <command>
Requires Node.js >= 20.
Python projects (pip / uv)
If your project's lockfile is Python-based and you'd rather pin vault-tasks alongside your other dev dependencies:
pip install vault-tasks
# or
uv add --dev vault-tasks
The pip wheel is small (~100 KB) and bundles the same compiled JS that ships on npm. It still requires node (>= 20) on PATH — the wheel does not vendor a Node.js runtime.
Quick start
# Initialize in your repo/vault root
vt init
# Create a task
vt new "Fix login redirect bug" --priority high --tags auth,bug
# See what's open
vt list
# Start working on it
vt start 1
# Mark it done (auto-archives by default)
vt done 1
vt init creates a .vault-tasks.toml config and a backlog/ directory. Tasks are markdown files with ULID prefixes (e.g., 01HYX3KQPD7NG8RRGSSFQ9XNHY-fix-login-redirect-bug.md). Sequential numeric IDs (0001-...) are also supported via config.
Commands
| Command | Description |
|---|---|
vt new <title> |
Create a task. Options: --priority, --tags, --source, --commit |
vt list |
List open tasks. Options: --status, --priority, --tag, --all |
vt search <keyword> |
Search titles and body text. --all includes archived. --mode keyword|bm25|semantic|hybrid; --like <id> finds similar tasks; --limit N caps results. See Semantic search |
vt show <id> |
Print full task file |
vt start <id> |
Set status to in-progress |
vt done <id> |
Set status to done (auto-archives) |
vt edit <id> |
Update fields: --status, --priority, --tags |
vt stale |
List open tasks older than 14 days. --days to customize |
vt archive |
Move all completed tasks to the archive directory |
vt tags |
List all tags and their counts |
vt lint |
Audit the vault: broken wikilinks, orphan evergreens, stale refs, drift. --only, --scope, --json, --quiet, --no-suggestions |
vt init |
Initialize config and backlog directory |
vt install-skills |
Install Claude Code skills and rules. --install, --list, --update |
Task lookup (<id>) accepts a ULID prefix (e.g., vt done 01HYX), a numeric ID for sequential vaults (e.g., vt done 1), or a substring match against the filename (e.g., vt done login).
Task format
Each task is a markdown file with YAML frontmatter:
---
title: "Fix login redirect bug"
status: open
priority: high
tags:
- auth
- bug
created: 2026-04-02
source: "[[2026-04-02 Session Log]]"
---
# Fix login redirect bug
After OAuth callback, users are redirected to `/` instead of the page they came from.
- Status:
open,in-progress,done,wont-do - Priority:
high,medium,low - Tags: freeform, filterable via
vt list --tag - Source: where the task was noticed (supports
[[wikilinks]])
Extra frontmatter fields (e.g. due, assignee) are preserved through all operations.
Configuration
vt init creates .vault-tasks.toml at your vault root:
[paths]
backlog_dir = "backlog" # where task files live
archive_dir = "archive" # relative to backlog_dir
# journal_dir = "journal" # build logs and session notes
# projects_dir = "projects" # project folders with CONTEXT.md
# evergreen_dir = "evergreen" # evergreen/zettelkasten notes
[task]
# statuses = ["open", "in-progress", "done", "wont-do"]
# priorities = ["high", "medium", "low"]
# default_priority = "medium"
# default_status = "open"
# archive_statuses = ["done", "wont-do"]
# auto_archive = true
[id]
# strategy = "ulid" # "ulid" | "sequential" | "timestamp"
# pad_width = 4 # zero-pad width (only used with sequential)
[slugify]
# max_length = 60
The config file is discovered by walking up from the current directory, so it works from any subdirectory.
Claude Code skills
vault-tasks ships with skill templates that teach Claude Code how to work with your task backlog:
vt install-skills --install
This installs into .claude/skills/ and .claude/rules/:
| Skill | What it does |
|---|---|
/brief |
Pre-session briefing: open tasks, last session context, stale threads |
/build-log |
End-of-session log: what was built, learned, decided. Extracts tasks |
/weekly-review |
Consolidates journal entries, creates evergreen notes, triages backlog |
/task |
Quick task creation/management from within a session |
/lint |
Vault health check: broken wikilinks, orphans, stale refs, convention drift |
Skills reference configurable vault paths (journal_dir, projects_dir, evergreen_dir) which are substituted from your .vault-tasks.toml at install time. Customize any skill by creating a SKILL.local.md next to the installed SKILL.md -- local files are never overwritten.
An Obsidian Bases dashboard (backlog.base) is also installed for visual task management.
Library API
vault-tasks also exports a programmatic API:
import { loadConfig, TaskStore } from "vault-tasks";
const config = loadConfig();
const store = new TaskStore(config);
// Create
const task = store.create({ title: "My task", priority: "high", tags: ["api"] });
// Query
const all = store.loadAll();
const results = store.search("login");
const stale = store.stale(14);
const tags = store.allTags();
// Update
store.update(task, { status: "done", priority: "low", tags: ["api", "shipped"] });
store.archiveCompleted();
Exports
TaskStore-- all CRUD operationsloadConfig/findConfigFile-- config discovery and parsingparseFrontmatter/writeFrontmatter-- YAML frontmatter utilitiesslugify-- title to kebab-case filenamelintVault-- run all lint checks; returns aLintReport- Lower-level lint primitives:
buildIndex,resolveTarget,collectWikilinks,findBrokenLinks,findOrphanEvergreens,findStaleReferences,findEvergreenDrift,attachSuggestions - Types:
Task,CreateTaskOpts,Config,LintReport,LintOptions,WikiLink,VaultFile,BrokenEntry,Suggestion,SearchHit,SearchMode,SearchOptions
Ranked search (vault-tasks/search)
A separate, zero-dependency subpath export provides BM25-ranked search and
task-to-task similarity. Imported only when needed -- the core vault-tasks
entry point is unaffected.
import { TaskStore, loadConfig } from "vault-tasks";
import { searchTasks, similarTasks, BM25Index, VectorIndex, tokenize } from "vault-tasks/search";
const store = new TaskStore(loadConfig());
// Free-text query, ranked by BM25
const hits = await searchTasks(store, "auth callback", { mode: "bm25", limit: 10 });
// Vector similarity (uses the configured embedding engine)
const semantic = await searchTasks(store, "login flow", { mode: "semantic" });
// Tasks similar to a given task
const target = store.findIncludingArchive("0042");
const related = await similarTasks(store, target, { mode: "hybrid" });
Available modes:
| Mode | Ranking | Needs an engine? |
|---|---|---|
keyword (default) |
substring match across title, body, AND tags; priority-sorted | no |
bm25 |
BM25 relevance, title-weighted | no |
semantic |
cosine similarity over embeddings | yes |
hybrid |
bm25 + semantic fused with Reciprocal Rank Fusion |
yes |
Semantic search
semantic and hybrid modes rank tasks by meaning rather than shared words.
They need an embedding engine to turn text into vectors; keyword and
bm25 never do and stay fully offline.
Local-first by default — no data leaves your machine, no API key. vault-tasks talks to a local Ollama server:
ollama serve # start the local server
ollama pull nomic-embed-text # pull the default model (768 dims)
vt search "auth redirect" --mode semantic
vt search --like 0042 --mode hybrid
Vectors are cached at <vault>/.vault-tasks/embeddings.json, so only new or
changed tasks are re-embedded on later runs. (Add that path to .gitignore if
you don't want to commit it.)
Configure the engine under [search] in .vault-tasks.toml:
[search]
embedding_provider = "ollama" # ollama | lmstudio | llamacpp | openai-compatible
# | transformers | openai | voyage | gemini
embedding_model = "nomic-embed-text" # also: mxbai-embed-large (1024d), all-minilm (384d)
# embedding_endpoint = "" # override server URL; empty = provider default
- Other local servers: set
embedding_providertolmstudioorllamacpp(OpenAI-compatible/v1/embeddings); the default endpoints arehttp://localhost:1234andhttp://localhost:8080. - In-process, no server: install the optional package and switch provider —
npm i @huggingface/transformers, thenembedding_provider = "transformers"withembedding_modelset to a Hugging Face repo id. It's anoptionalDependency, so the core install stays dependency-free. - Cloud (opt-in):
embedding_provider = "openai"(orvoyage/gemini). The API key is read from an environment variable you name viaembedding_api_key_env— it is never stored in config or on disk.
License
MIT
Metadata
Release files for vault-tasks 0.6.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| vault_tasks-0.6.0.tar.gz | 106.3 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| vault_tasks-0.6.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 280.8 kB
Release files / vault_tasks-0.6.0.tar.gz
| Download URL | vault_tasks-0.6.0.tar.gz |
|---|---|
| Size | 106.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
35d40b4116c3d87e66b912b1b52ee1613267c5ddb84a6d07b0492f4830d5baad
|
|
BLAKE2b-256 checksum How to use checksums |
57895fa7776b817040a0b1dcdbad89fc2d4d7e9b3ad7f4d64088da545236bf42
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logRelease files / vault_tasks-0.6.0-py3-none-any.whl
| Download URL | vault_tasks-0.6.0-py3-none-any.whl |
|---|---|
| Size | 174.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ee941814db48241f462f7c3d7a3aa6085101fa68c61491e4c46753688b891379
|
|
BLAKE2b-256 checksum How to use checksums |
3f6007eff7dd9594d218ebb8832741b83aeac2717f830e05041c072177afc972
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logSecurity for vault-tasks 0.6.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for vault_tasks-0.6.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.