wk — files-first project management
wk is project management that lives in a folder you own. Projects, open questions, outstanding
items and work history are plain markdown files in a git repo on your machine — the "work repo". The
extension puts a sidebar over those files; it never locks them away. Everything stays readable,
editable, greppable and diffable with any tool, forever, whether or not the extension is
installed.
If you use Claude Code, wk also connects the two: sessions show
up live in the sidebar attached to the project they're working on, buttons hand work to Claude
with the right context, and Claude reads and writes the same markdown files under rules it
understands. Without Claude, the sidebar is a fast read-only view over your notes with light
management commands — everything else still works.
- Now — live Claude Code sessions, grouped under the project each is working on, with the
project's open questions, pending migrations and backlog directly underneath. Each session row
says how many turns it has had and when its last message was. At the bottom, Inbox lists
the notes in your books'
inbox/ folders that nobody has triaged yet.
- Review — projects set aside: the code is deployed and bedding in, and a review in a few
days is the work that remains. Oldest set-aside first.
- Next — current projects not being worked on right now, in priority order (priority, then
size, then age), the answer to "what should I pick up next?", with planned ones in a fold at
the bottom.
- All Projects — every book, every project, current and archived, with subprojects nested
under the project they belong to.
- Questions — open questions from every current project's
QUESTIONS.md, in one place,
with a folded Closed (n) under each project listing its answered questions, newest first.
- Remember — the things that otherwise get lost: outstanding items (deliberate temporary
hacks that must be undone), pending live migrations, and questions waiting on someone else.
Questions and Remember are optional: hide them from the sidebar's … menu and they cost nothing
(no registers are read for them until they show again).
Now's toolbar holds the quick starts:
- wk: Quick Notes (pencil) opens today's note,
<book>/inbox/<date>-notes.md, ready to type
into — created if it isn't there. Right-click a note in the Inbox group → Triage in Claude
starts a chat that proposes where each fragment belongs, creates or updates projects once you
agree, and appends a ## Triaged <date> section to the note, which takes it out of the Inbox.
- wk: Odd Job in Claude… (spanner) asks for a one-line job and starts a chat on it, attached to
the book's standing
odd-jobs project (created the first time). Claude does the job and records
it as one dated line in that project's history — for changes too small to be a project.
- wk: New Project (+, also on All Projects) asks for a title such as "Customer Orders" and
shows the directory it will get (
customer-orders) as you type.
- wk: Planning Session (lightbulb) — a brain-dump into a planning chat.
Which books a window shows
Now, Next, Questions and Remember show one book by default — the one whose checkout this window
has open (All Projects always shows every book). To choose instead, run wk: Choose Books for
this Window… (in Now's and Next's … menu), or right-click a book in All Projects → Show in
this window / Hide in this window. The choice is saved in work.books for this workspace;
the first book chosen is the window's own, which Next lists first.
Getting started (60 seconds)
- Install the extension.
- Open the wk sidebar. With no work repo yet, every view offers Start tracking work — it
creates a work repo (default
~/.wk, which needs no setting at all, or anywhere you
choose), writes a starter repos.yml
and a getting-started project, and runs git init for you. No git knowledge needed, no remote
needed.
- That's it. Add projects with the + button (or ask Claude to start one).
wk looks for the work repo in ~/.wk first, then ~/.work (the default before 0.15, so an
existing repo there needs nothing moved), then at whichever registered repo's repos.yml claims a
folder this window has open; work.repoPath (per machine, never synced) overrides all of them.
Already keeping notes in a folder? Use Use an existing folder instead, or set the
work.repoPath setting. To move the work repo later, run wk: Move the Work Repo… - it moves
the folder and updates the setting, the hook registry and the window that points at it.
The work repo
The work repo is an ordinary git repo of markdown files. At its top level, one directory per
book — a broad area of work, usually mapping to a codebase — declared in repos.yml:
version: 1 # optional
repos:
shop: # book name = its directory name in the work repo
title: Web Shop # optional display name
paths: # optional - where that codebase is checked out
- /home/me/src/shop
infra: {} # no paths: a "virtual" book - registers and notes, no code checkout
That is the whole schema: repos: maps book name → { title?, paths? }. A missing or empty
paths means a virtual book. Unknown top-level keys are ignored.
Within a book, a project is a directory in one of four lifecycle stages — current/
(being worked), review/ (deployed and bedding in, awaiting a review), planned/ (agreed
someday-work) or archive/<year>/ (done) — holding:
(later/ was this stage's name before 0.14 and still reads as the same stage, in the same pane;
nothing moves a later/ project until you do.)
project.yml — name, title, status, icon, priority/size/tags for the Next view
README.md — what the project is, where it stands, what's next (kept current, not appended to)
HISTORY.md — dated prose: what changed and why
QUESTIONS.md and OUTSTANDING.md — numbered registers of live questions and outstanding
items, where an entry's status lives in a small stamped meta line (Raised, Waiting on:,
Answered, …). Once an entry has been dealt with it moves, keeping its number, to
QUESTIONS-CLOSED.md / OUTSTANDING-CLOSED.md, so the open files stay short
HANDOFF.md — notes from one session to the next one on the project (where it got to, the
uncommitted state, the exact next step), deleted as they are consumed. Present only when a
session has left something behind; the sidebar marks projects that have one
- optionally
BACKLOG.md, research/, migrations/pending|applied/
A project can name another project in the same book as its parent: in project.yml, making it
a subproject. Directories stay flat — a subproject is an ordinary project directory at its own
lifecycle stage, named <parent>-<thing> by convention — and every rule works on it unchanged; the
parent: line is the only link. All Projects nests it under its parent, and Now and Next show its
own title with the parent's in front. A parent with children is an area: its README is the standing
picture of the whole effort and its Next up lists the children. Add kind: area to a parent that
is only ever orientation and Next stops offering it — its children are what you pick up instead.
A project belongs to whichever book's directory it sits in, and nothing else keys on the book -
so Move to book… on a project's right-click menu simply moves the directory, at its own
stage, into another book (subprojects travel with their parent). Use it when an area of work
outgrows its codebase's book, or when a codebase's branch or worktree earns a book of its own.
By convention (Claude follows it, and you can too) a book can also hold an inbox/ for raw
braindumps awaiting triage and a reference/ for durable how-tos — plain folders, created when
first needed. The sidebar reads everything directly off disk — there is no database and no
index to corrupt.
Claude Code integration
Run wk: Set Up Claude Integration (also offered once, unobtrusively, when Claude Code and a
work repo are both present). It does four concrete things:
- Copies the bundled hook script and its library to
~/.claude/wk/ (a stable home that
survives extension updates), plus a config.json listing your work repos.
- Backs up
~/.claude/settings.json to settings.json.wk-backup (once, only if no backup
exists), then merges five hook entries into it — SessionStart, UserPromptSubmit, PostToolUse
(file edits), Stop, SessionEnd — each running ~/.claude/wk/hooks.js with the first node 18+
on your PATH (VS Code's own bundled node only when there is none, since a VS Code update
deletes it). Your other hooks are left untouched.
- Installs the
work skill to ~/.claude/skills/work/SKILL.md, which teaches Claude the file
formats and the bookkeeping rules (register the session against a project, record history,
add Project: trailers to commits, keep the README current).
- On later extension updates, quietly refreshes those copies when the bundled version is newer,
wires up any hook event a newer version added, and repoints any of its hook entries whose node
has moved or gone — an upgrade never needs a re-run.
What the hooks record: a small JSON row per session under <work repo>/.state/sessions/ (which
project it's attached to, when it was last seen, which files it touched, how much context the
chat is carrying), an append-only
activity log, and — at session start and session end — an auto-commit of anything left
uncommitted in the work repo, followed by a pull and a push if it has a remote. The hooks fast-exit for sessions outside your
registered work repos and codebases, and are written to never break a session: any failure
degrades to doing nothing.
wk: Check Setup opens a report of the whole chain — repo, git state, which books this window
shows and why, hooks and the node they run with, settings entries, skill, Claude extension — with
what's wrong and how to fix it. It always reuses the
same read-only tab, so running it repeatedly while fixing something leaves no tabs behind.
No Claude? Skip all of the above. The sidebar, projects, registers and planning views work the
same; only the session tracking and the hand-to-Claude buttons need Claude Code.
Syncing between machines
The work repo is plain git, so syncing is a remote: create an empty private repo anywhere
(GitHub, GitLab, a bare repo on a server you own) and run wk: Connect Work Repo to a
Remote…. After that it syncs itself: the sidebar commits, pulls and pushes every few minutes
(work.syncMinutes, and about a minute after any change it makes itself), and Claude Code
sessions do the same at their start and end. Both skip a repo that is mid-rebase and record a
failure for wk: Check Setup to report. No remote is required — a purely local work repo is
fully supported, and the periodic run then just commits.
Settings
work.repoPath — path of the work repo (set for you by Start tracking work). Per machine:
Settings Sync never carries it between machines, since an absolute path on one is rarely a work
repo on another. Empty looks in ~/.wk, then ~/.work, then at the repo registered in
~/.claude/wk/config.json whose repos.yml claims this window's folder.
work.syncMinutes — how often the sidebar syncs the work repo (commit, pull --rebase, push);
default 5, 0 turns it off and leaves syncing to the Claude Code hooks.
work.books — the books this window shows in Now, Next, Questions and Remember, by their
repos.yml names; the first is the window's own book. Set by Choose Books for this Window…
and the book right-click in All Projects, per workspace. Empty infers the book from the
workspace folders.
work.activeBook — which book this window is for (drives the Next view's ordering); empty
infers it from the workspace folders. The first of work.books wins when that is set.
work.handoff — whether Work on this in Claude opens the chat panel (instructions arrive
invisibly via the hooks at session start; the prompt is only pre-filled as a fallback when
the hooks aren't set up) or a terminal running the CLI.
Work on this in an Agent Chat (experimental), on the same right-click menu, hands the work
to VS Code's own agent host instead - the chat-view style session behind the Agents window -
which submits a prompt rather than pre-filling it. It needs a VS Code whose chat offers a
Claude session type (1.137 or later) and says so when it doesn't; the session type ids it
relies on are undocumented and move with VS Code releases.
work.liveWindowMinutes — how recently a session must have been seen to count as live.
work.contextBudget — context size, in tokens, past which Claude is told the chat is over
budget (default 300000; 0 turns it off). Every turn re-sends the whole conversation, so a
long chat costs more per turn than a fresh one: the Now view shows each session's context
size and flags the ones over budget, and Claude, told the size as it starts a turn, finishes
the request and then asks once whether to compact and carry on or write a handoff and
continue in a fresh chat. The costlier case is a chat that comes back after an hour idle: its
prompt cache has expired, so that turn re-reads everything at full price, and every later
return does too. Past half the budget, a cold return gets the same nudge, once per return.
work.showOtherBooks — superseded by work.books, and ignored when that is set. Off by
default: Now, Next, Questions and Remember show this window's book only, and the badge counts
what they show. All Projects always shows every book, and a window that is no book's checkout
sees everything. Turn it on to see the other books faded in Next and listed everywhere else.
Notes
- Windows is not supported. The extension and hooks assume a POSIX environment (Linux,
macOS, WSL, dev containers, remote SSH); on native Windows they will stay quiet rather than
misbehave, but nothing will work.
- Not affiliated with Anthropic. Claude is a trademark of Anthropic, PBC.
- MIT licensed.
| |