cork-todo

module
v0.9.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 22, 2026 License: MIT

README

cork

A tiny, cross-environment terminal todo CLI — one shared file is the single source of truth.

English · 한국어

cork is a single static binary with zero runtime dependencies. Jot a task down in one container, VM, or machine, and see it from every other environment that reads the same data directory — no server, no daemon, no per-environment setup.

Why cork?

When your work is split across isolated environments — containers, VMs, git worktrees, several machines — there is no standard channel to hand a follow-up task ("in this environment, run the migration after pulling") to another environment or to your future self. Follow-ups get lost silently, and you only notice after working with a stale setup.

cork makes every task name the workspace it belongs to and keeps the whole list in one shared file, so a task you write anywhere is visible everywhere that file is reachable — and one command can fan a task out to every registered workspace at once.

Features

  • Single shared file = single source of truth. All state is JSONL in one data directory; every environment reading it sees the same list.
  • Zero runtime dependencies. One static binary. Nothing else to install.
  • Workspace-aware. Each item carries its workspace, with per-workspace grouping and filtering; the workspace is auto-detected (git repo name, else directory name) when you don't specify one.
  • Fan-out. One command copies a task into every registered workspace.
  • Interactive TUI. Full-screen list with cursor navigation, toggle, edit, delete-with-confirm, and search.
  • Stable --json output. A machine-readable contract for scripts and AI agents that does not break when human-facing text changes.
  • Concurrency-safe. File lock + atomic writes; item-level last-write-wins.
  • Auto-archive. Completed items move out of the active file after a retention window.
  • Offline only. No network, no telemetry — data never leaves your machine or mount.
  • Loud on failure. A missing or unreadable data directory is an explicit error, never a silently empty list.

Install

cork is one static binary — every channel produces the same runnable cork with no extra runtime dependency.

Homebrew (macOS / Linux)
brew install beomeodev/tap/cork
go install
go install github.com/beomeodev/cork-todo/cmd/cork@latest
Prebuilt binary

Download the archive for your OS/architecture from the Releases page, extract it, and put cork on your PATH. Each archive ships the binary plus its LICENSE; verify it against the release SHA256SUMS.

Architecture must match. Per-architecture binaries are provided (Linux/macOS on amd64 and arm64). Pick the one matching your machine — uname -m prints arm64 (Apple Silicon) or x86_64 (Intel).

Quick start

cork add "Write the release notes"        # add a task
cork add "Buy milk" -w home               # add to a specific workspace
cork list                                 # show open tasks
cork done 3f                              # complete by id (any unique prefix works)
cork list --done                          # show completed tasks
cork                                      # launch the interactive TUI

Each item shows a short id (e.g. 3f7abc12), its status, its workspace, and the text. You address items by full id or any unique prefix; an ambiguous prefix is an error, never a guess.

Core commands
Command What it does
cork add <text> [-w <ws>] [--fan-out] Add a task; --fan-out copies it into every registered workspace
cork list [--done] [-w <ws>] [-s <query>] List tasks, optionally filtered by state / workspace / search
cork done <id> / cork undo <id> Complete / reopen a task
cork edit <id> <text> Change a task's text
cork pin <id> Pin a task to the top
cork rm <id> Remove a task (active, completed, or archived)
cork workspace add/remove/list <name> Manage the shared workspace registry

Add --json to any command for stable machine-readable output.

Interactive TUI

Run cork with no arguments in a real terminal to open the full-screen list:

Key Action
/ (or k / j) Move cursor
space Toggle done
a Add a new task inline
e Edit
p Toggle pin
d Delete (confirm y, cancel n)
tab Switch active ↔ completed
/ Search
w Filter by workspace
q Quit

Sharing one list across environments

This is what cork is built for. Point every environment at the same data directory and they all share one list:

export CORK_DATA_DIR=/path/to/shared/cork   # a directory reachable from each environment
cork list                                    # the same list, everywhere

Because cork is a single static binary, you can also drop one copy on a shared mount and run it from every environment of the same architecture — no per-environment install:

cp cork /mnt/shared/bin/cork
/mnt/shared/bin/cork list

Configuration

Variable Purpose
CORK_DATA_DIR Data directory (highest priority). Point every environment here to share one list.
XDG_DATA_HOME When CORK_DATA_DIR is unset, data lives in $XDG_DATA_HOME/cork.
CORK_WORKSPACE Overrides workspace detection for add.
CORK_ARCHIVE_RETENTION_DAYS Days a completed item stays active before archiving (default 30; must be a positive whole number).

Data & storage

The data directory is resolved in order: CORK_DATA_DIR$XDG_DATA_HOME/cork~/.local/share/cork. Active tasks live in todos.jsonl, archived tasks in archive.jsonl.

Storage is JSONL — one JSON object per line, one line per item, each carrying a version field. The format is forward-compatible: a binary that does not recognize a field preserves it verbatim across a read-modify-write, so newer and older cork versions can share one file without dropping each other's data.

Archiving

Completed items older than the retention window are moved out of todos.jsonl into archive.jsonl, keeping the active file small. Archiving is automatic — it happens opportunistically as cork runs and touches nothing when nothing is old enough.

  • Retention defaults to 30 days, configurable via CORK_ARCHIVE_RETENTION_DAYS.
  • cork list --done --archived shows archived items alongside the completed view.
  • cork rm <id> removes an item wherever it lives — active, completed, or archived.

Concurrency & filesystem support

Multiple environments can write the shared file at the same time without losing data. Every mutation takes an exclusive file lock around its read-modify-write, then persists via an atomic temp-file

  • rename. Concurrent changes to different items are all preserved; concurrent changes to the same item resolve by item-level last-write-wins, and a record is never left torn.

Advisory file locks (flock) are reliable on local filesystems and container/VM bind mounts — the intended shared-mount setup. On network filesystems (e.g. NFS) locking can degrade; the atomic write is the mitigation, but reliable locking there is not guaranteed.

Platforms

Linux and macOS are first-class. Windows builds are provided; Windows validation (including the TUI) is not yet complete.

License

MIT © beomeodev. See LICENSE.

Directories

Path Synopsis
cmd
cork command
@CODE:CRUD-016 @CODE:WS-013 @CHAIN: @SPEC:LIST-002 -> @TEST:LIST-002 -> @CODE:LIST-002 (pin sub-command wiring; toggle owned in internal/cli/commands.go) @CHAIN: @SPEC:LIST-007 -> @TEST:LIST-007 -> @CODE:LIST-007 (list --search/-s flag wiring; filter owned in internal/cli/commands.go) @CHAIN: @SPEC:FANOUT-008 -> @TEST:FANOUT-008 -> @CODE:FANOUT-008 (add --fan-out wiring; result rendering in internal/cli) @CHAIN: @SPEC:FANOUT-009 -> @TEST:FANOUT-009 -> @CODE:FANOUT-009 (empty-registry --json wiring) @CHAIN: @SPEC:TUI-001 -> @TEST:TUI-001 -> @CODE:TUI-001 (no-arg TTY launch + non-TTY one-shot fallback; TUI owned in internal/tui) Command cork is the cross-environment terminal todo CLI.
@CODE:CRUD-016 @CODE:WS-013 @CHAIN: @SPEC:LIST-002 -> @TEST:LIST-002 -> @CODE:LIST-002 (pin sub-command wiring; toggle owned in internal/cli/commands.go) @CHAIN: @SPEC:LIST-007 -> @TEST:LIST-007 -> @CODE:LIST-007 (list --search/-s flag wiring; filter owned in internal/cli/commands.go) @CHAIN: @SPEC:FANOUT-008 -> @TEST:FANOUT-008 -> @CODE:FANOUT-008 (add --fan-out wiring; result rendering in internal/cli) @CHAIN: @SPEC:FANOUT-009 -> @TEST:FANOUT-009 -> @CODE:FANOUT-009 (empty-registry --json wiring) @CHAIN: @SPEC:TUI-001 -> @TEST:TUI-001 -> @CODE:TUI-001 (no-arg TTY launch + non-TTY one-shot fallback; TUI owned in internal/tui) Command cork is the cross-environment terminal todo CLI.
internal
cli
@CODE:CRUD-018
@CODE:CRUD-018
store
@CODE:ARCHIVE-001 @CODE:ARCHIVE-002 @CODE:ARCHIVE-003 @CODE:ARCHIVE-004 @CODE:ARCHIVE-007 @CODE:ARCHIVE-008
@CODE:ARCHIVE-001 @CODE:ARCHIVE-002 @CODE:ARCHIVE-003 @CODE:ARCHIVE-004 @CODE:ARCHIVE-007 @CODE:ARCHIVE-008
tui
@CODE:TUI-002 @CODE:TUI-015 @CODE:TUI-016 @CHAIN: @TEST:FIX-TUI-001 -> @CODE:FIX-TUI-001 (add mode + workspace source; primary anchor in update.go) @CHAIN: @TEST:FIX-TUI-002 -> @CODE:FIX-TUI-002 (cursor follows the item across pin re-sorts) @CHAIN: @SPEC:TUI-002 -> @TEST:TUI-002 -> @CODE:TUI-002 (list surface: grouped, pinned-first) @CHAIN: @SPEC:TUI-015 -> @TEST:TUI-015 -> @CODE:TUI-015 (state observable without rendering) @CHAIN: @SPEC:TUI-016 -> @TEST:TUI-016 -> @CODE:TUI-016 (mutation persists through the storage path)
@CODE:TUI-002 @CODE:TUI-015 @CODE:TUI-016 @CHAIN: @TEST:FIX-TUI-001 -> @CODE:FIX-TUI-001 (add mode + workspace source; primary anchor in update.go) @CHAIN: @TEST:FIX-TUI-002 -> @CODE:FIX-TUI-002 (cursor follows the item across pin re-sorts) @CHAIN: @SPEC:TUI-002 -> @TEST:TUI-002 -> @CODE:TUI-002 (list surface: grouped, pinned-first) @CHAIN: @SPEC:TUI-015 -> @TEST:TUI-015 -> @CODE:TUI-015 (state observable without rendering) @CHAIN: @SPEC:TUI-016 -> @TEST:TUI-016 -> @CODE:TUI-016 (mutation persists through the storage path)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL