Skip to main content

CLI Reference

The UnDercontrol CLI (ud) is a command-line tool for managing tasks from the terminal. It supports both direct commands and an interactive TUI mode with vim-style keybindings.

Installation

# Global install
npm install -g @oatnil/ud

# Or run directly without installing
npx @oatnil/ud --help

Homebrew (macOS/Linux)

brew tap oatnil-top/ud
brew install ud

Install Script

curl -fsSL https://get.oatnil.com/ud | bash

Manual Download

Download the appropriate version for your platform:

PlatformFilename
macOS (Apple Silicon)ud_x.x.x_darwin_arm64.tar.gz
macOS (Intel)ud_x.x.x_darwin_amd64.tar.gz
Linux (x64)ud_x.x.x_linux_amd64.tar.gz
Linux (ARM64)ud_x.x.x_linux_arm64.tar.gz
Windowsud_x.x.x_windows_amd64.zip

macOS / Linux:

# Extract
tar -xzf ud_x.x.x_darwin_arm64.tar.gz

# Move to PATH
sudo mv ud /usr/local/bin/ud

# Verify
ud --version

Windows:

  1. Extract the .zip file
  2. Move ud.exe to a directory in your PATH
  3. Or add the extracted directory to your system PATH

Authentication

Login

ud login

You'll be prompted for:

  • Username: Your account email
  • Password: Your account password

The server URL comes from the active context (or the --api-url flag). To log in to a specific server and save it as a named context in one step, use --api-url with --name/-n:

ud login --api-url https://ud.oatnil.com -n personal

You can also pass credentials non-interactively with -u/--username and -p/--password. Credentials are saved to ~/.config/ud/config.yaml.

Multi-Context Support

The CLI supports kubectl-style contexts for managing multiple accounts. See CLI Multi-Context Authentication for details.

# List contexts
ud config get-contexts

# Switch context
ud config use-context work

# Login to specific context
ud login --context work --api-url https://ud.company.com

Resource Commands (kubectl-style)

The CLI supports kubectl-style top-level verbs for managing resources. These are the recommended way to interact with resources.

Get Resources

ud get task [id] [--status <status>]

Display one or many tasks in a table format.

Options:

  • --status: Filter by status (todo, in-progress, pending, stale, done, archived)

Examples:

# List all tasks
ud get task

# List only todo tasks
ud get task --status todo

# Show a single task in table format
ud get task abc123

Describe Resource

ud describe task <id>

Show detailed information about a specific task, including title, description, status, tags, deadline, timestamps, linked tasks, attachments, and notes.

Examples:

# View full task details
ud describe task abc123

# Using short prefix
ud describe task 3de
Short ID Support

All commands that accept a task ID support prefix matching. You can use the 8-character short IDs shown in get task output, or even shorter prefixes as long as they're unique.

ud describe task 3de9f82b    # Full short ID from list
ud describe task 3de # Shorter prefix (if unique)
ud describe task 3de9f82b-fc49-4e84-b288-9ae3174f69ae # Full UUID also works

If a prefix matches multiple tasks, you'll see an error listing the matches:

Error: ambiguous ID prefix '3' matches 2 tasks:
3de9f82b (Task title one)
3fbf7c24 (Task title two)
Please use a longer prefix

Apply Resource from File

ud apply -f <file>       # .md for tasks/notes, .yaml for other resources
ud apply -f - # Read from stdin (auto-detects format)

Create or update resources declaratively from files (kubectl-style). Supports all resource types:

FormatResourcesAuto-detection
.mdTask (default), Note (when task_id in frontmatter)task_id present → Note
.yaml / .ymlBoard, Budget, Account, Expense, Incomekind field in YAML

Quick examples:

# Task
echo '---
title: New Task
status: todo
---
Description here.' | ud apply -f -

# Note (auto-detected by task_id)
echo '---
task_id: abc123
---
Progress update.' | ud apply -f -

# Board (YAML)
ud apply -f board.yaml

# Multi-document YAML (multiple resources in one file)
ud apply -f setup.yaml

For the full schema reference, all supported fields, and YAML resource format details, see the Apply & Resource Schema guide.

Delete Resource

ud delete task <id>

Delete a task by ID.

Examples:

ud delete task abc123
ud delete task 3de9f82b

Working with Tasks

The ud CLI is kubectl-style: there is no ud task create/done/edit subcommand. Instead, you create, update, and change task state declaratively with ud apply.

Create a Task

Pipe a markdown document (YAML frontmatter + body) to ud apply -f -. With no id in the frontmatter, this creates a new task:

cat <<'EOF' | ud apply -f -
---
title: Fix login bug
status: todo
tags: [backend, urgent]
---
Update the auth middleware to handle expired refresh tokens.
EOF

You can also apply a file directly:

ud apply -f task.md

If title is omitted, it's derived from the first line of the body (or the filename). See the Apply & Resource Schema guide for all fields.

Update a Task / Change Status

To update an existing task — including marking it done — apply the same document with the id present. Set status: done to complete it:

cat <<'EOF' | ud apply -f -
---
id: abc123
status: done
---
EOF

A convenient round-trip is to export a task, edit it, and re-apply it:

# Export the task in apply-compatible format
ud describe task abc123 -o apply > task.md

# ...edit task.md in your editor...

# Re-apply the changes
ud apply -f task.md

You can also edit tasks interactively in the TUI (ud or ud tui).

# Bidirectional peer link
ud link task abc123 def456

# Make one a subtask of another
ud link task parent123 child456 --subtask

# Set the parent of a task
ud link task child123 parent456 --parent

Query Tasks

ud query "<query>" [flags]

Query tasks using SQL-like syntax.

Flags:

  • --page: Page number (default: 1)
  • --limit: Items per page (default: 50)
  • --sort: Sort field (title, deadline, created_at, updated_at)
  • --order: Sort direction (asc, desc)

Examples:

# Find todo tasks
ud query "status = 'todo'"

# Search by title
ud query "title ILIKE '%api%'"

# Find tasks due this week
ud query "deadline BETWEEN 'today' AND '+7d'"

# Find tagged tasks
ud query "tags = 'urgent'"

# Complex query
ud query "(status = 'todo' OR status = 'in-progress') AND deadline <= 'today'"

Notes

Notes let you add comments, progress updates, and context to tasks. They're useful for tracking work history and AI agent collaboration. Like tasks, notes are managed with ud apply — a markdown document is detected as a note when its frontmatter contains a task_id.

Add a Note

cat <<'EOF' | ud apply -f -
---
task_id: abc123
---
✓ Auth middleware done
EOF

Or apply a file that has task_id in its frontmatter:

ud apply -f progress.md

To update an existing note, include its note_id in the frontmatter alongside task_id.

List Notes

ud get notes --task <task-id>
ud get notes -t <task-id> # short flag

Delete a Note

ud delete note <note-id>

Example:

ud delete note 4223db11

AI Agent Workflow

Notes enable seamless collaboration between humans and AI agents:

# AI creates a task from a plan (no id = create)
cat <<'EOF' | ud apply -f -
---
title: Add user authentication
status: in-progress
---
JWT-based auth with refresh tokens.
EOF
# Created task: abc12345

# AI reads the task for context
ud describe task abc123

# AI logs progress via notes (task_id = note)
cat <<'EOF' | ud apply -f -
---
task_id: abc123
---
✓ Completed step 1: Database schema
EOF

# AI reports a blocker
cat <<'EOF' | ud apply -f -
---
task_id: abc123
---
⚠️ Blocked: Need API key for external service
EOF

# Once unblocked, AI completes the task (id + status = update)
cat <<'EOF' | ud apply -f -
---
id: abc123
status: done
---
EOF

File Upload & Attachment Commands

Upload files as resources and optionally attach them to entities like tasks or expenses. Files are uploaded via presigned URLs directly to cloud storage.

Upload a File

ud upload resource <file-path> [flags]

Upload a file as a resource. Optionally attach it to an entity in a single step.

Flags:

  • -t, --entity-type: Entity type to attach to (e.g., todolist, expense)
  • -e, --entity-id: Entity ID to attach to (supports prefix matching for tasks)

Examples:

# Upload a standalone file
ud upload resource ./receipt.png

# Upload and attach to a task
ud upload resource ./design.pdf --entity-type todolist --entity-id abc123

# Short flags
ud upload resource ./photo.jpg -t todolist -e abc123

# Upload a document to a task (partial ID)
ud upload resource ./notes.txt -t todolist -e 3de

Output:

Uploading ./receipt.png...
Uploaded: receipt.png
ID: 2a2e542e-0711-4e7f-aafb-09a432e71860
Type: image
Size: 102.4 KB
MIME: image/png
MIME Type Detection

The CLI automatically detects MIME types from file extensions. Common mappings:

  • Images: .png, .jpg, .gif, .webp, .svgimage
  • Documents: .pdf, .doc, .docx, .txt, .csvdocument
  • Diagrams: .drawio, .drawio.pngdiagram
  • Other: all other extensions → other

Attach Existing Resource

ud attach resource <resource-id> --entity-type <type> --entity-id <id>

Link an already-uploaded resource to an entity. Both --entity-type and --entity-id are required.

Flags:

  • -t, --entity-type: Entity type (required)
  • -e, --entity-id: Entity ID (required, supports prefix matching for tasks)

Supported entity types:

Entity TypeDescription
todolistTasks
expenseExpenses
budgetBudgets
accountAccounts

Examples:

# Attach resource to a task
ud attach resource 2a2e542e-0711-4e7f-aafb-09a432e71860 -t todolist -e abc123

# Attach to an expense
ud attach resource 2a2e542e -t expense -e def456

Download a Resource

To download a resource, use ud get entity to retrieve the presigned download URL, then download with curl:

# Get resource details (includes presigned download URL)
ud get entity 2a2e542e-0711-4e7f-aafb-09a432e71860

# Download using the presigned URL from the response
curl -o receipt.png "https://storage.example.com/...?signature=..."

Upload Workflow Example

A typical workflow for attaching files to tasks:

# 1. Find the task
ud get task --status in-progress

# 2. Upload and attach a file
ud upload resource ./screenshot.png -t todolist -e 3de9f82b

# 3. Verify the attachment
ud describe task 3de9f82b
# Shows: [2a2e542e] screenshot.png (image/png, 102.4 KB)

# 4. Later, download the file
ud get entity 2a2e542e
# Copy the presignedUrl from the output
curl -o screenshot.png "<presigned-url>"

TUI Mode

Run ud without arguments to enter the interactive terminal UI.

List View Keybindings

KeyAction
j / kMove down/up
ggJump to top
GJump to bottom
EnterView task details
iCreate new task
eEdit task (uses $EDITOR)
xToggle task status
ddDelete task
/Search
n / NNext/previous search result
rRefresh list
fOpen file picker
qQuit
?Show help

Detail View Keybindings

KeyAction
j / kScroll content
xToggle task status
eEdit task
ddDelete task
Esc / qReturn to list

File Picker

Press f in list view to open an fzf-like file picker:

  • Fuzzy search files in current directory
  • Select file to create task
  • First line = title, rest = description
  • Binary files are skipped

Configuration Commands

View Configuration

ud config view

Shows the full configuration with tokens partially masked.

List Contexts

ud config get-contexts

Switch Context

ud config use-context <name>

Show Current Context

ud config current-context

Create/Update Context

ud config set-context <name> [flags]

Flags:

  • --api-url: API server URL
  • --api-key: API key (for CI/CD)

Delete Context

ud config delete-context <name>

Rename Context

ud config rename-context <old-name> <new-name>

Environment Variables

VariableDescription
UD_CONTEXTOverride current context
UD_API_URLOverride API URL
UD_API_KEYOverride API key
UD_TOKENOverride auth token
EDITOREditor used by the TUI when editing a task

Examples:

# Use different context for one command
UD_CONTEXT=staging ud get task

# Override API URL
UD_API_URL=http://localhost:4000 ud get task

# Set editor
export EDITOR=vim

Common Workflows

AI Agent Integration

Create .claude/instructions.md or .cursorrules in your project:

# Task Management

Use UnDercontrol CLI to manage project tasks:

- List tasks: `ud get task`
- View task details: `ud describe task <id>`
- Create or update a task: `ud apply -f -` (no `id` = create, `id` = update)
- Complete a task: apply the task with `status: done`
- Add a progress note: `ud apply -f -` with `task_id` in the frontmatter
- Delete a task: `ud delete task <id>`

Before implementing features, check related tasks for context.

Batch Updates with Apply

Create a template file and apply to multiple tasks:

# Create status update template for each task
for id in abc123 def456 ghi789; do
echo "---
id: $id
status: done
---" | ud apply -f -
done

Export and Edit Workflow

# View task, copy content
ud describe task abc123

# Create markdown file with updates (include id for update)
cat > update.md << 'EOF'
---
id: abc123
title: Updated Title
status: in-progress
tags:
- reviewed
- approved
---

Updated description with new requirements.
EOF

# Apply changes
ud apply -f update.md

Troubleshooting

Login Failed

Problem: API error: Invalid credentials

Solutions:

  1. Verify username and password
  2. Check server URL is correct
  3. Try logging in via web to verify account

Connection Timeout

Problem: connection timeout

Solutions:

  1. Check network connection
  2. Verify server URL is accessible
  3. Check firewall settings

Token Expired

Problem: API error: Token expired

Solution: Run ud login to re-authenticate.

Editor Not Working

Problem: Editing a task in the TUI has no effect

Solution: Set the EDITOR environment variable:

export EDITOR=vim  # or nano, code, etc.

Invalid Status Error

Problem: API error: An unexpected error occurred when using apply

Solution: Ensure status is one of: todo, in-progress, pending, stale, done, archived

Context Not Found

Problem: context "work" not found

Solution: Create the context first:

ud config set-context work --api-url https://ud.company.com
ud login --context work