Skip to main content

CLI Apply & Resource Schema

The ud apply -f command lets you create and update resources declaratively from files — similar to kubectl apply. The file is the single source of truth: apply it once to create, apply it again (with the ID) to update.

ud apply -f task.md          # create or update a task
ud apply -f note.md # create or update a note (auto-detected)
ud apply -f board.yaml # create or update a board
ud apply -f resources.yaml # apply multiple resources from one file
cat spec.yaml | ud apply -f - # read from stdin

Two File Formats

ExtensionResourcesStructure
.mdTask, NoteYAML frontmatter + markdown body
.yaml / .ymlBoard, Budget, Account, Expense, Incomek8s-like apiVersion/kind/metadata/spec

The format is determined by file extension. For stdin (-f -), format is auto-detected: content starting with apiVersion: is parsed as YAML, otherwise as markdown.


Markdown Resources (.md)

Markdown files use YAML frontmatter between --- delimiters, followed by a markdown body.

Task

A .md file without task_id in frontmatter is a Task.

---
title: Ship v1 release
status: in-progress
tags:
- release
- urgent
kickoff: 2025-05-01
deadline: 2025-06-01
board: abc123
---

Final checklist before the v1 launch:

- [ ] Run full test suite
- [ ] Update changelog
- [ ] Tag release
- [ ] Deploy to production

Fields:

FieldTypeRequiredDescription
idstringnoTask UUID or prefix. Present = update, absent = create.
titlestringnoDerived from body first line or filename if omitted.
statusstringnotodo (default), in-progress, pending, stale, done, archived
tagsarraynoList of tags.
kickoffstringnoStart date (YYYY-MM-DD or ISO 8601).
deadlinestringnoDue date (YYYY-MM-DD or ISO 8601).
boardstringnoBoard ID or prefix — creates the task directly in the board.
(body)stringnoBecomes the task description.

Title derivation (when title is not in frontmatter):

  1. First non-empty line of the body (with # prefix stripped)
  2. Filename without .md extension (dashes replaced with spaces)
  3. "Untitled"

Note

A .md file with task_id in frontmatter is a Note — no subcommand needed.

---
task_id: a1b2c3d4
---

## Progress Update

- Completed API integration
- Next: wire up the frontend

Fields:

FieldTypeRequiredDescription
task_idstringyesParent task UUID or prefix.
note_idstringnoNote UUID or prefix. Present = update, absent = create.
(body)stringnoNote content in markdown.
Auto-detection

You don't need ud apply note -f anymore. Plain ud apply -f note.md detects the Note format automatically by checking for task_id in frontmatter. The ud apply note subcommand still works as a backward-compatible alias.


YAML Resources (.yaml / .yml)

YAML files use a k8s-like envelope with four top-level fields:

apiVersion: ud/v1
kind: Board
metadata:
id: abc12345 # present = update, absent = create
tags: [work, sprint]
spec:
name: Sprint Board
# kind-specific fields...
FieldRequiredDescription
apiVersionyesAlways ud/v1.
kindyesResource type: Board, Budget, Account, Expense, Income.
metadatanoCommon fields: id (for update), tags.
specyesKind-specific fields (see below).

Board

apiVersion: ud/v1
kind: Board
spec:
name: Sprint Board
board_type: private
default_tags: [sprint-1]
columns:
- name: Backlog
query: "status:todo"
- name: In Progress
query: "status:in-progress"
- name: Review
query: "status:pending"
- name: Done
query: "status:done"
FieldTypeRequiredDescription
namestringyesBoard name.
board_typestringnoprivate (default) or shared.
columnsarraynoOrdered list of columns.
columns[].namestringyesColumn display name.
columns[].querystringnoFilter query (e.g., status:todo).
default_tagsarraynoTags auto-applied to new tasks in this board.

Budget

apiVersion: ud/v1
kind: Budget
metadata:
tags: [food]
spec:
name: Groceries
amount:
amount: 500.00
currency: USD
starts_at: "2025-01-01"
plans:
- amount:
amount: 500.00
currency: USD
frequency: monthly
effective_from: "2025-01-01"
reason: Initial monthly budget
FieldTypeRequiredDescription
namestringyesBudget name.
amountmoneyyesInitial budget amount.
starts_atstringnoBudget start date (YYYY-MM-DD).
plansarraynoRecurring budget plans.
plans[].amountmoneyyesPlan amount per period.
plans[].frequencystringyesdaily, weekly, biweekly, monthly, quarterly, yearly.
plans[].effective_fromstringyesPlan start date.
plans[].effective_tostringnoPlan end date (omit for open-ended).
plans[].reasonstringnoWhy this plan was created.

Account

apiVersion: ud/v1
kind: Account
metadata:
tags: [bank]
spec:
name: Checking
balance:
amount: 5000.00
currency: USD
off_budget: false
notes: Primary checking account
FieldTypeRequiredDescription
namestringyesAccount name.
balancemoneyyesCurrent balance.
off_budgetbooleannoExclude from budget calculations (default: false).
notesstringnoFree-form notes.

Expense

apiVersion: ud/v1
kind: Expense
metadata:
tags: [food, lunch]
spec:
title: Team lunch
amount:
amount: 85.50
currency: USD
budget_id: abc123
account_id: def456
occurred_at: "2025-03-15"
description: Monthly team lunch at the Italian place
FieldTypeRequiredDescription
titlestringnoExpense title.
amountmoneyyesExpense amount.
descriptionstringnoAdditional details.
budget_idstringnoBudget UUID or prefix.
account_idstringnoAccount UUID or prefix (paid from).
occurred_atstringnoWhen the expense occurred (YYYY-MM-DD).

Income

apiVersion: ud/v1
kind: Income
metadata:
tags: [salary]
spec:
title: March salary
amount:
amount: 5000.00
currency: USD
source: salary
account_id: abc123
occurred_at: "2025-03-31"
FieldTypeRequiredDescription
titlestringyesIncome title.
amountmoneyyesIncome amount.
descriptionstringnoAdditional details.
sourcestringnosalary, freelance, investment, gift, other.
account_idstringnoAccount UUID or prefix (deposited to).
occurred_atstringnoWhen the income was received (YYYY-MM-DD).

Money Type

All financial resources use a money object:

amount:
amount: 42.50 # decimal in major currency units
currency: USD # ISO 4217 code (defaults to USD if omitted)

Multi-Document YAML

A single .yaml file can contain multiple resources, separated by ---:

apiVersion: ud/v1
kind: Account
spec:
name: Checking
balance:
amount: 5000.00
currency: USD
---
apiVersion: ud/v1
kind: Account
spec:
name: Savings
balance:
amount: 20000.00
currency: USD
off_budget: true
---
apiVersion: ud/v1
kind: Budget
metadata:
tags: [rent]
spec:
name: Rent
amount:
amount: 2000.00
currency: USD
starts_at: "2025-01-01"
plans:
- amount:
amount: 2000.00
currency: USD
frequency: monthly
effective_from: "2025-01-01"

Resources are applied in order. An error in one document does not stop processing of the rest.


Create vs Update

All resources follow the same declarative rule:

ConditionAction
No id in frontmatter/metadataCreate new resource
id presentUpdate existing resource

IDs can be full UUIDs or unique prefixes (first 8 characters are usually enough):

# Update — uses prefix
metadata:
id: a1b2c3d4
---
id: a1b2c3d4-e5f6-7890-abcd-ef1234567890
title: Updated title
---

Supported Resources

Run ud api-resources to see all resource types and their available verbs:

NAME       SHORTNAMES   VERBS
task tasks,t get,describe,apply,delete,annotate
note - get,apply,delete
board boards get,describe,apply,query
budget budgets,b get,describe,apply
expense expenses,e get,describe,apply
account accounts,a get,describe,apply
income incomes,i get,describe,apply
resource - upload
column columns get

Schema Definitions

Formal JSON Schema definitions for all resource types are published at:

https://github.com/oatnil-top/ud-schemas

SchemaFormatResources
task.v1.schema.jsonMarkdownTask files
note.v1.schema.jsonMarkdownNote files
resource.v1.schema.jsonYAMLGeneric envelope (shared definitions)
board.v1.schema.jsonYAMLBoard resources
budget.v1.schema.jsonYAMLBudget resources
account.v1.schema.jsonYAMLAccount resources
expense.v1.schema.jsonYAMLExpense resources
income.v1.schema.jsonYAMLIncome resources

Examples

Set up a project from scratch

# Create accounts
cat <<'EOF' | ud apply -f -
apiVersion: ud/v1
kind: Account
spec:
name: Checking
balance:
amount: 10000.00
currency: USD
EOF

# Create budgets
ud apply -f monthly-budgets.yaml

# Create a sprint board
ud apply -f sprint-board.yaml

# Create tasks
cat <<'EOF' | ud apply -f -
---
title: Set up CI/CD pipeline
status: todo
tags:
- infra
- sprint-1
board: Sprint
---
Configure GitHub Actions for build, test, and deploy.
EOF

AI agent workflow

AI agents (Claude Code, Cursor) can use ud apply -f - to create and update resources programmatically:

# Agent creates a task
cat <<'EOF' | ud apply -f -
---
title: Implement user auth
status: in-progress
---
JWT-based auth with refresh tokens.
EOF

# Agent adds a note
cat <<'EOF' | ud apply -f -
---
task_id: abc123
---
## Progress
- Added login endpoint — commit a1b2c3d4
- Next: refresh token rotation
EOF

# Agent logs an expense
cat <<'EOF' | ud apply -f -
apiVersion: ud/v1
kind: Expense
spec:
title: API hosting - March
amount:
amount: 29.99
currency: USD
budget_id: infra
occurred_at: "2025-03-31"
EOF

Batch setup with multi-doc YAML

# Create all accounts in one file
ud apply -f accounts.yaml

# accounts.yaml contains multiple Account resources separated by ---