No description
  • Rust 98.9%
  • Nix 1.1%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-29 18:00:52 +00:00
.hooks add cog 2025-12-02 11:41:51 +01:00
.moira fix: ci 2026-05-18 09:34:18 +02:00
src feat(login): remember the user id, and accept API tokens 2026-09-29 20:00:29 +02:00
.gitignore init 2024-06-06 08:48:36 +02:00
Cargo.lock Merge branch 'main' into mdsync 2026-09-29 18:35:34 +02:00
Cargo.toml Merge branch 'main' into mdsync 2026-09-29 18:35:34 +02:00
cog.toml add cog 2025-12-02 11:41:51 +01:00
flake.lock fix: nix build 2026-01-21 22:01:46 +01:00
flake.nix ci: declare moiraFlake so the crane checks actually get built 2026-08-07 21:56:22 +02:00
README.md feat(login): remember the user id, and accept API tokens 2026-09-29 20:00:29 +02:00
renovate.json Add renovate.json 2026-03-21 03:02:20 +00:00

vk

A fast, opinionated terminal interface for Vikunja. Built for people who live in the terminal.

  ◆  Fix authentication bug           [Hydra]      ★   2d ago
  ◆  Update README                    [vk]              just now
  ◆  Design CLI vision                [vk]          ★   just now
  ◆  vikunja-rs patches               [Sidequest]       overdue 2d

Install

cargo install --git https://git.hydrar.de/jmarya/vk

Setup

vk stores its config at ~/.config/vk.toml.

Login with your credentials:

vk login --host vikunja.example.com --username user --password pass
vk login --host vikunja.example.com --username user --password pass --totp 123456

Or with an API token. API tokens cannot tell vk which user they belong to, so
pass your user id too (needed for vk claim and vk --mine):

vk login --host vikunja.example.com --token tk_... --user-id 1

Both check the credentials before saving them. A password login records your
user id by itself.

Usage

vk                   # your tasks
vk -d                # include done tasks
vk -f                # favorites only
vk --from myproject  # tasks from a specific project
vk -l mylabel        # tasks with a specific label
vk stats             # dashboard with stats overview

Tasks:

vk new "fix the bug"                         # create in default project
vk new "fix the bug" --project myproject     # create in specific project
vk new "fix the bug" --due 2024-12-31        # with due date
vk new "fix the bug" --label urgent          # with label
vk new "fix the bug" --priority 4           # with priority

vk info 42           # full task detail
vk context 42        # everything about a task as markdown (see below)
vk edit 42           # edit a task
vk done 42           # mark as done
vk done -u 42        # undo
vk fav 42            # mark as favorite
vk fav -u 42         # undo
vk rm 42             # delete

Comments:

vk comments 42       # show comments
vk comment 42 "text" # post a comment

Relations:

vk relation 7 parent 42    # make #42 a parent of #7
vk relation 42 blocked 7   # mark #42 as blocked by #7
vk relation 42 sub 7       # make #7 a subtask of #42
vk relation --delete 42 blocked 7

Assignments:

vk assign user 42    # assign user to task (username or numeric id)
vk assign -u user 42 # unassign

Labels:

vk label urgent 42   # add label to task
vk label -u urgent 42

vk labels ls
vk labels new urgent --color ff0000
vk labels rm urgent

Projects:

vk prj ls
vk prj add "My Project" --description "..." --color 8800ff
vk prj add "Sub Project" --parent "My Project"
vk prj rm "My Project"

Timeline:

vk timeline              # every task, laid out by its dates
vk timeline -s           # only tasks with a start, end, due date or reminder
vk timeline -p myproject # one project
vk timeline -l mylabel -d
vk timeline --sort newest  # time (default), newest, project, due, activity

Rows take their project's colour (or a stable one from a built-in palette when
the project has none). A darker ▄ lifeline runs from when a task was created
until it was done (or today), lighter at its last update. On top of it,
start–end is drawn as a taller ▆ bar in full colour, ◆ marks the due date (red when overdue), ◇ its projected repeats,
◷ reminders and ✓ when it was done. Keys: j/k select, h/l scroll, H/L page,
+/- zoom (6 hours, day, week, month per column), s cycle sort, t today, c center on
the selected task, enter show its details, q quit.

Scripts and agents

vk is built to be driven by scripts and AI agents as well as by hand.

Read a task in one call:

vk context 42              # fields, description, checklist, relations, comments as markdown
vk changes --since 12h     # tasks created, done or updated since then (30m, 3d, 2w, or a date)
vk changes -p myproject --since 2026-09-28

JSON everywhere. Add --json (or -j) anywhere on the command line, or set
VK_JSON=1. Commands that change something print the result: vk new --json
returns the created task with its id, vk rm --json returns
{"deleted": {"task": 42}}.

Errors and exit codes. Failures go to stderr, as
{"error": {"kind": "...", "message": "..."}} in JSON mode.

Exit Kind Meaning
0 success
1 other anything else
2 usage bad arguments or input, or a command that needs a terminal
3 not_found no such task, project, label or user
4 auth not logged in, or the token lacks permission
5 conflict the task changed since you read it, or someone else claimed it
6 api the server rejected the request
7 network the server could not be reached

Don't overwrite other people's changes. Every command that changes a task
takes --expect-updated <time>: pass the task's updated value from when you
read it, and vk refuses with exit 5 if the task has changed since.

vk edit 42 --title "New title" --expect-updated 2026-09-29T10:00:00+02:00

Preview before writing. --dry-run (-n) on every command that changes
something shows what would happen without doing it:

$ vk edit 42 --title "New title" --priority 3 -n
Would edit task #42:
  priority: 0 → 3
  title: Old title → New title

Long text from stdin. - reads a description or comment from stdin:

generate-notes | vk comment 42 -
vk edit 42 --description - < notes.md

Claiming tasks. When several agents (or you and an agent) share a board:

vk claim 42          # assign yourself; exit 5 if someone else has it
vk claim 42 --force  # claim it alongside whoever has it
vk unclaim 42        # release it
vk --mine            # what you have claimed

Claiming a task you already hold, or releasing one you don't, succeeds without
changing anything, so retries are safe. If two agents claim the same task at
the same moment, the one with the lower user id keeps it.

vk needs to know which user it acts as. vk login saves it for password
logins; API tokens need --user-id at login (or VK_USER_ID, e.g. one per
agent). Your id is created_by.id on a task you created:
vk info <id> --json.

Configuration

Full config reference with defaults:

host  = "https://vikunja.example.com"
token = "your-token"
user_id = 1                   # who you are, for `vk claim`; needed with API tokens

# display
bullet          = "◆"        # task bullet — any string works
show_id         = false       # show task ID in the list
show_age        = true        # show relative timestamp
show_labels     = false       # show label chips in the task list
date_format     = "relative"  # "relative" | "absolute" | "hidden"

# behaviour
default_view    = "tasks"     # what `vk` shows with no args: "tasks" | "stats"
default_project = "Inbox"     # project used by `vk new` when --project is omitted
page_size       = 25          # tasks shown in list view
sort_by         = "created"   # "created" | "due" | "priority" | "updated"
order           = "desc"      # "asc" | "desc"

# vk stats
stats_logo      = true        # show ASCII logo in stats view