@hasna/todos 0.11.6 → 0.11.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -416
- package/dist/cli/index.js +422 -50
- package/dist/mcp/index.js +456 -84
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,450 +1,50 @@
|
|
|
1
1
|
# @hasna/todos
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[](LICENSE)
|
|
5
|
-
[]()
|
|
6
|
-
|
|
7
|
-
Universal task management for AI coding agents. CLI + MCP server + library, all sharing a single SQLite database.
|
|
8
|
-
|
|
9
|
-
## Features
|
|
10
|
-
|
|
11
|
-
- **CLI** with interactive TUI (React/Ink) and JSON output mode
|
|
12
|
-
- **MCP server** (29 tools) for Claude, Codex, Gemini, and any MCP-compatible agent
|
|
13
|
-
- **Library** for programmatic access from Node.js/Bun
|
|
14
|
-
- **Agent registration** with short UUID identity system
|
|
15
|
-
- **Task lists** for organizing tasks into named containers (backlog, sprint-1, bugs)
|
|
16
|
-
- **Task prefixes** with auto-incrementing short IDs per project (e.g., `APP-00001`)
|
|
17
|
-
- **Plans** as execution groups, separate from task list containers
|
|
18
|
-
- **SQLite** with WAL mode, optimistic locking, and automatic migrations
|
|
19
|
-
- Task dependencies with cycle detection
|
|
20
|
-
- Exclusive agent locking with 30-minute auto-expiry
|
|
21
|
-
- Full-text search across tasks
|
|
22
|
-
- Project auto-detection from git repositories
|
|
23
|
-
- Subtask hierarchies with cascade deletion
|
|
24
|
-
- Bidirectional sync with Claude Code, Codex, Gemini task lists
|
|
3
|
+
Universal task management for AI coding agents - CLI + MCP server + interactive TUI
|
|
25
4
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
bun add -g @hasna/todos
|
|
30
|
-
```
|
|
5
|
+
[](https://www.npmjs.com/package/@hasna/todos)
|
|
6
|
+
[](LICENSE)
|
|
31
7
|
|
|
32
|
-
|
|
8
|
+
## Install
|
|
33
9
|
|
|
34
10
|
```bash
|
|
35
11
|
npm install -g @hasna/todos
|
|
36
12
|
```
|
|
37
13
|
|
|
38
|
-
##
|
|
39
|
-
|
|
40
|
-
```bash
|
|
41
|
-
# Register your agent (get a short UUID for identity)
|
|
42
|
-
todos init my-agent
|
|
43
|
-
|
|
44
|
-
# Create a task
|
|
45
|
-
todos add "Fix login bug" --priority high --tags bug,auth
|
|
46
|
-
|
|
47
|
-
# List active tasks
|
|
48
|
-
todos list
|
|
49
|
-
|
|
50
|
-
# Start working on a task (claims + locks it)
|
|
51
|
-
todos start <id>
|
|
52
|
-
|
|
53
|
-
# Mark complete
|
|
54
|
-
todos done <id>
|
|
55
|
-
|
|
56
|
-
# Create a task list
|
|
57
|
-
todos lists --add "sprint-1"
|
|
58
|
-
|
|
59
|
-
# Add task to a list
|
|
60
|
-
todos add "Build search" --list <list-id>
|
|
61
|
-
|
|
62
|
-
# Register MCP server with AI agents
|
|
63
|
-
todos mcp --register all
|
|
64
|
-
|
|
65
|
-
# Launch interactive TUI
|
|
66
|
-
todos
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
## Agent Registration
|
|
70
|
-
|
|
71
|
-
Agents register once to get a persistent 8-character UUID. This ID is used to track task ownership, locking, and activity.
|
|
72
|
-
|
|
73
|
-
```bash
|
|
74
|
-
# Register (idempotent — same name returns same ID)
|
|
75
|
-
todos init claude
|
|
76
|
-
# Agent registered:
|
|
77
|
-
# ID: 56783129
|
|
78
|
-
# Name: claude
|
|
79
|
-
|
|
80
|
-
# Use the ID on future commands
|
|
81
|
-
todos add "Fix bug" --agent 56783129
|
|
82
|
-
|
|
83
|
-
# List all registered agents
|
|
84
|
-
todos agents
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Registration is idempotent: calling `init` with the same name returns the existing agent and updates `last_seen_at`.
|
|
88
|
-
|
|
89
|
-
## Task Lists
|
|
90
|
-
|
|
91
|
-
Task lists are named containers for organizing tasks (like folders). They're separate from plans.
|
|
92
|
-
|
|
93
|
-
```bash
|
|
94
|
-
# Create a task list
|
|
95
|
-
todos lists --add "backlog"
|
|
96
|
-
todos lists --add "sprint-1" --slug sprint-1 -d "Current sprint"
|
|
97
|
-
|
|
98
|
-
# List all task lists
|
|
99
|
-
todos lists
|
|
100
|
-
|
|
101
|
-
# Add tasks to a list
|
|
102
|
-
todos add "Build feature" --list <list-id>
|
|
103
|
-
|
|
104
|
-
# Filter tasks by list
|
|
105
|
-
todos list --list <list-id>
|
|
106
|
-
|
|
107
|
-
# Move a task to a different list
|
|
108
|
-
todos update <task-id> --list <list-id>
|
|
109
|
-
|
|
110
|
-
# Delete a list (tasks keep their data, just lose the list association)
|
|
111
|
-
todos lists --delete <list-id>
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
Task lists can be project-scoped or standalone. Slugs must be unique within a project.
|
|
115
|
-
|
|
116
|
-
## Task Prefixes & Short IDs
|
|
117
|
-
|
|
118
|
-
Every project gets an auto-generated prefix (e.g., "APP" from "My App"). When tasks are created under a project, they get a short ID prepended to the title:
|
|
119
|
-
|
|
120
|
-
```bash
|
|
121
|
-
# Project "My App" has prefix "MYA"
|
|
122
|
-
todos add "Fix login bug"
|
|
123
|
-
# Creates: "MYA-00001: Fix login bug"
|
|
124
|
-
|
|
125
|
-
todos add "Add dark mode"
|
|
126
|
-
# Creates: "MYA-00002: Add dark mode"
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
Custom prefixes can be set when creating a project. Counters auto-increment per project.
|
|
130
|
-
|
|
131
|
-
## Plans
|
|
132
|
-
|
|
133
|
-
Plans are execution groups for organizing work. A task can belong to both a task list AND a plan.
|
|
14
|
+
## CLI Usage
|
|
134
15
|
|
|
135
16
|
```bash
|
|
136
|
-
|
|
137
|
-
todos plans --add "v2.0 Release"
|
|
138
|
-
|
|
139
|
-
# Show plan details
|
|
140
|
-
todos plans --show <plan-id>
|
|
141
|
-
|
|
142
|
-
# Complete a plan
|
|
143
|
-
todos plans --complete <plan-id>
|
|
144
|
-
|
|
145
|
-
# Assign tasks to a plan
|
|
146
|
-
todos add "Build API" --plan <plan-id>
|
|
17
|
+
todos --help
|
|
147
18
|
```
|
|
148
19
|
|
|
149
20
|
## MCP Server
|
|
150
21
|
|
|
151
|
-
Register the MCP server with AI coding agents:
|
|
152
|
-
|
|
153
|
-
```bash
|
|
154
|
-
todos mcp --register claude # Claude Code
|
|
155
|
-
todos mcp --register codex # Codex CLI
|
|
156
|
-
todos mcp --register gemini # Gemini CLI
|
|
157
|
-
todos mcp --register all # All agents
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
Or start manually via stdio:
|
|
161
|
-
|
|
162
22
|
```bash
|
|
163
23
|
todos-mcp
|
|
164
24
|
```
|
|
165
25
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
**Tasks:** `create_task`, `list_tasks`, `get_task`, `update_task`, `delete_task`, `start_task`, `complete_task`, `lock_task`, `unlock_task`, `approve_task`
|
|
169
|
-
**Dependencies:** `add_dependency`, `remove_dependency`
|
|
170
|
-
**Comments:** `add_comment`
|
|
171
|
-
**Projects:** `create_project`, `list_projects`
|
|
172
|
-
**Plans:** `create_plan`, `list_plans`, `get_plan`, `update_plan`, `delete_plan`
|
|
173
|
-
**Agents:** `register_agent`, `list_agents`, `get_agent`
|
|
174
|
-
**Task Lists:** `create_task_list`, `list_task_lists`, `get_task_list`, `update_task_list`, `delete_task_list`
|
|
175
|
-
**Search:** `search_tasks`
|
|
176
|
-
**Sync:** `sync`
|
|
177
|
-
**Audit:** `get_task_history`, `get_recent_activity`
|
|
178
|
-
**Webhooks:** `create_webhook`, `list_webhooks`, `delete_webhook`
|
|
179
|
-
**Templates:** `create_template`, `list_templates`, `create_task_from_template`, `delete_template`
|
|
180
|
-
|
|
181
|
-
### MCP Resources
|
|
182
|
-
|
|
183
|
-
| URI | Description |
|
|
184
|
-
|-----|-------------|
|
|
185
|
-
| `todos://tasks` | All active tasks (pending + in_progress) |
|
|
186
|
-
| `todos://projects` | All registered projects |
|
|
187
|
-
| `todos://agents` | All registered agents |
|
|
188
|
-
| `todos://task-lists` | All task lists |
|
|
189
|
-
|
|
190
|
-
## Web Dashboard
|
|
191
|
-
|
|
192
|
-
Start the web dashboard to manage tasks visually:
|
|
193
|
-
|
|
194
|
-
```bash
|
|
195
|
-
todos serve
|
|
196
|
-
# or
|
|
197
|
-
todos-serve --port 19427
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
Features:
|
|
201
|
-
- **Dashboard** — stats cards, completion rate, recent activity
|
|
202
|
-
- **Tasks** — data table with search, filters, sorting, pagination, kanban board view
|
|
203
|
-
- **Projects** — project management with task breakdown
|
|
204
|
-
- **Agents** — agent monitoring with completion rates, online status, role management
|
|
205
|
-
- **Help** — keyboard shortcuts, CLI reference, MCP configuration
|
|
206
|
-
|
|
207
|
-
The dashboard auto-refreshes every 30 seconds, supports dark mode, and includes keyboard shortcuts (`/` search, `n` new task, `0-4` navigate pages).
|
|
26
|
+
135 tools available.
|
|
208
27
|
|
|
209
28
|
## REST API
|
|
210
29
|
|
|
211
|
-
Start the server with `todos serve` or `todos-serve`. Default port: 19427.
|
|
212
|
-
|
|
213
|
-
### Tasks
|
|
214
|
-
|
|
215
|
-
| Method | Endpoint | Description |
|
|
216
|
-
|--------|----------|-------------|
|
|
217
|
-
| GET | `/api/tasks` | List tasks. Query: `?status=`, `?project_id=`, `?limit=` |
|
|
218
|
-
| POST | `/api/tasks` | Create task. Body: `{ title, description?, priority?, project_id?, estimated_minutes?, requires_approval? }` |
|
|
219
|
-
| GET | `/api/tasks/:id` | Get task details |
|
|
220
|
-
| PATCH | `/api/tasks/:id` | Update task. Body: `{ title?, status?, priority?, description?, assigned_to?, tags?, due_at?, estimated_minutes?, requires_approval?, approved_by? }` |
|
|
221
|
-
| DELETE | `/api/tasks/:id` | Delete task |
|
|
222
|
-
| POST | `/api/tasks/:id/start` | Start task (sets in_progress, locks) |
|
|
223
|
-
| POST | `/api/tasks/:id/complete` | Complete task |
|
|
224
|
-
| GET | `/api/tasks/:id/history` | Get task audit log |
|
|
225
|
-
| POST | `/api/tasks/bulk` | Bulk ops. Body: `{ ids: [...], action: "start" | "complete" | "delete" }` |
|
|
226
|
-
| GET | `/api/tasks/export?format=csv` | Export as CSV |
|
|
227
|
-
| GET | `/api/tasks/export?format=json` | Export as JSON |
|
|
228
|
-
|
|
229
|
-
### Projects
|
|
230
|
-
|
|
231
|
-
| Method | Endpoint | Description |
|
|
232
|
-
|--------|----------|-------------|
|
|
233
|
-
| GET | `/api/projects` | List all projects |
|
|
234
|
-
| POST | `/api/projects` | Create project. Body: `{ name, path, description? }` |
|
|
235
|
-
| DELETE | `/api/projects/:id` | Delete project |
|
|
236
|
-
| POST | `/api/projects/bulk` | Bulk delete. Body: `{ ids: [...], action: "delete" }` |
|
|
237
|
-
|
|
238
|
-
### Plans
|
|
239
|
-
|
|
240
|
-
| Method | Endpoint | Description |
|
|
241
|
-
|--------|----------|-------------|
|
|
242
|
-
| GET | `/api/plans` | List plans. Query: `?project_id=` |
|
|
243
|
-
| POST | `/api/plans` | Create plan. Body: `{ name, description?, project_id?, task_list_id?, agent_id?, status? }` |
|
|
244
|
-
| GET | `/api/plans/:id` | Get plan with its tasks |
|
|
245
|
-
| PATCH | `/api/plans/:id` | Update plan |
|
|
246
|
-
| DELETE | `/api/plans/:id` | Delete plan |
|
|
247
|
-
| POST | `/api/plans/bulk` | Bulk delete |
|
|
248
|
-
|
|
249
|
-
### Agents
|
|
250
|
-
|
|
251
|
-
| Method | Endpoint | Description |
|
|
252
|
-
|--------|----------|-------------|
|
|
253
|
-
| GET | `/api/agents` | List all agents |
|
|
254
|
-
| POST | `/api/agents` | Register agent. Body: `{ name, description?, role? }` |
|
|
255
|
-
| PATCH | `/api/agents/:id` | Update agent. Body: `{ name?, description?, role? }` |
|
|
256
|
-
| DELETE | `/api/agents/:id` | Delete agent |
|
|
257
|
-
| POST | `/api/agents/bulk` | Bulk delete |
|
|
258
|
-
|
|
259
|
-
### Webhooks, Templates, Activity
|
|
260
|
-
|
|
261
|
-
| Method | Endpoint | Description |
|
|
262
|
-
|--------|----------|-------------|
|
|
263
|
-
| GET | `/api/webhooks` | List webhooks |
|
|
264
|
-
| POST | `/api/webhooks` | Create webhook. Body: `{ url, events?, secret? }` |
|
|
265
|
-
| DELETE | `/api/webhooks/:id` | Delete webhook |
|
|
266
|
-
| GET | `/api/templates` | List task templates |
|
|
267
|
-
| POST | `/api/templates` | Create template. Body: `{ name, title_pattern, description?, priority?, tags? }` |
|
|
268
|
-
| DELETE | `/api/templates/:id` | Delete template |
|
|
269
|
-
| GET | `/api/activity` | Recent audit log. Query: `?limit=50` |
|
|
270
|
-
| GET | `/api/stats` | Dashboard statistics |
|
|
271
|
-
|
|
272
|
-
## Sync
|
|
273
|
-
|
|
274
|
-
Bidirectional sync with agent-specific task lists.
|
|
275
|
-
|
|
276
30
|
```bash
|
|
277
|
-
todos
|
|
278
|
-
todos sync --agent codex --task-list default
|
|
279
|
-
todos sync --all --task-list <id>
|
|
280
|
-
todos sync --prefer local # Resolve conflicts favoring local
|
|
281
|
-
todos sync --push # One-way: local → agent
|
|
282
|
-
todos sync --pull # One-way: agent → local
|
|
31
|
+
todos-serve
|
|
283
32
|
```
|
|
284
33
|
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
### Environment Variables
|
|
288
|
-
|
|
289
|
-
| Variable | Description |
|
|
290
|
-
|----------|-------------|
|
|
291
|
-
| `TODOS_DB_PATH` | Database file path (`:memory:` for testing) |
|
|
292
|
-
| `TODOS_DB_SCOPE` | Set to `project` to force project-level DB |
|
|
293
|
-
| `TODOS_AUTO_PROJECT` | Set to `false` to disable auto-project detection |
|
|
294
|
-
| `TODOS_SYNC_AGENTS` | Comma-separated agent list for `--all` |
|
|
295
|
-
| `TODOS_TASK_LIST_ID` | Default task list ID for sync |
|
|
296
|
-
| `TODOS_<AGENT>_TASK_LIST` | Agent-specific task list ID |
|
|
297
|
-
| `TODOS_AGENT_TASKS_DIR` | Base directory for agent task files |
|
|
298
|
-
|
|
299
|
-
### Config File
|
|
300
|
-
|
|
301
|
-
`~/.todos/config.json`:
|
|
302
|
-
|
|
303
|
-
```json
|
|
304
|
-
{
|
|
305
|
-
"sync_agents": ["claude", "codex", "gemini"],
|
|
306
|
-
"task_list_id": "default",
|
|
307
|
-
"agent_tasks_dir": "/Users/you/.todos/agents",
|
|
308
|
-
"agents": {
|
|
309
|
-
"claude": { "task_list_id": "session-or-project-id" },
|
|
310
|
-
"codex": { "task_list_id": "default" }
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
```
|
|
34
|
+
## Cloud Sync
|
|
314
35
|
|
|
315
|
-
|
|
36
|
+
This package supports cloud sync via `@hasna/cloud`:
|
|
316
37
|
|
|
317
38
|
```bash
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
todos show <id> # Full task details with relations
|
|
322
|
-
todos update <id> [--title t] [-s status] [-p priority] [--tags t1,t2] [--estimated 30]
|
|
323
|
-
todos done <id> # Complete a task
|
|
324
|
-
todos start <id> # Claim, lock, and start
|
|
325
|
-
todos delete <id>
|
|
326
|
-
todos approve <id> # Approve a task requiring approval
|
|
327
|
-
todos history <id> # Show task audit log
|
|
328
|
-
todos search <query>
|
|
329
|
-
todos bulk <done|start|delete> <id1> <id2> ...
|
|
330
|
-
todos comment <id> <text>
|
|
331
|
-
todos deps <id> --add <dep_id> # Manage dependencies
|
|
332
|
-
|
|
333
|
-
# Plans
|
|
334
|
-
todos plans [--add name] [--show id] [--delete id] [--complete id]
|
|
335
|
-
|
|
336
|
-
# Templates
|
|
337
|
-
todos templates [--add name --title pattern] [--delete id] [--use id]
|
|
338
|
-
|
|
339
|
-
# Projects & Agents
|
|
340
|
-
todos projects [--add name --path /path]
|
|
341
|
-
todos agents
|
|
342
|
-
todos init <name> # Register an agent
|
|
343
|
-
todos lists # Manage task lists
|
|
344
|
-
|
|
345
|
-
# Utilities
|
|
346
|
-
todos count [--json] # Quick stats
|
|
347
|
-
todos watch [-s status] [-i 5] # Live-updating task list
|
|
348
|
-
todos config [--get key] [--set key=value]
|
|
349
|
-
todos export [--format csv|json]
|
|
350
|
-
todos sync [--task-list id] # Sync with Claude Code
|
|
351
|
-
todos serve [--port 19427] # Start web dashboard
|
|
352
|
-
todos interactive # Launch TUI
|
|
353
|
-
todos upgrade # Update to latest version
|
|
39
|
+
cloud setup
|
|
40
|
+
cloud sync push --service todos
|
|
41
|
+
cloud sync pull --service todos
|
|
354
42
|
```
|
|
355
43
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
## Library Usage
|
|
359
|
-
|
|
360
|
-
```typescript
|
|
361
|
-
import {
|
|
362
|
-
createTask,
|
|
363
|
-
listTasks,
|
|
364
|
-
completeTask,
|
|
365
|
-
registerAgent,
|
|
366
|
-
createTaskList,
|
|
367
|
-
createProject,
|
|
368
|
-
searchTasks,
|
|
369
|
-
} from "@hasna/todos";
|
|
370
|
-
|
|
371
|
-
// Register an agent
|
|
372
|
-
const agent = registerAgent({ name: "my-bot" });
|
|
373
|
-
|
|
374
|
-
// Create a project
|
|
375
|
-
const project = createProject({ name: "My App", path: "/app" });
|
|
376
|
-
|
|
377
|
-
// Create a task list
|
|
378
|
-
const backlog = createTaskList({ name: "Backlog", project_id: project.id });
|
|
379
|
-
|
|
380
|
-
// Create a task (gets short_id like "MYA-00001" auto-prepended)
|
|
381
|
-
const task = createTask({
|
|
382
|
-
title: "Fix login bug",
|
|
383
|
-
priority: "high",
|
|
384
|
-
project_id: project.id,
|
|
385
|
-
task_list_id: backlog.id,
|
|
386
|
-
agent_id: agent.id,
|
|
387
|
-
tags: ["bug", "auth"],
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
// List and filter
|
|
391
|
-
const pending = listTasks({ status: "pending", task_list_id: backlog.id });
|
|
392
|
-
|
|
393
|
-
// Search
|
|
394
|
-
const results = searchTasks("login", project.id);
|
|
395
|
-
|
|
396
|
-
// Complete
|
|
397
|
-
completeTask(task.id);
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
## Database
|
|
401
|
-
|
|
402
|
-
SQLite with automatic location detection:
|
|
403
|
-
|
|
404
|
-
1. `TODOS_DB_PATH` environment variable (`:memory:` for testing)
|
|
405
|
-
2. Nearest `.todos/todos.db` in current directory or any parent
|
|
406
|
-
3. `~/.todos/todos.db` global fallback
|
|
407
|
-
|
|
408
|
-
**Schema** (6 migrations, auto-applied):
|
|
409
|
-
|
|
410
|
-
| Table | Purpose |
|
|
411
|
-
|-------|---------|
|
|
412
|
-
| `projects` | Project registry with task prefix and counter |
|
|
413
|
-
| `tasks` | Main task table with short_id, versioning, locking |
|
|
414
|
-
| `task_lists` | Named containers for tasks |
|
|
415
|
-
| `agents` | Registered agent identities |
|
|
416
|
-
| `plans` | Execution groups |
|
|
417
|
-
| `task_dependencies` | DAG edges between tasks |
|
|
418
|
-
| `task_comments` | Notes on tasks |
|
|
419
|
-
| `task_tags` | Tag index for filtering |
|
|
420
|
-
| `sessions` | Agent session tracking |
|
|
421
|
-
|
|
422
|
-
## Development
|
|
423
|
-
|
|
424
|
-
```bash
|
|
425
|
-
git clone https://github.com/hasna/open-todos.git
|
|
426
|
-
cd open-todos
|
|
427
|
-
bun install
|
|
428
|
-
bun test # Run 172 tests
|
|
429
|
-
bun run typecheck # TypeScript checking
|
|
430
|
-
bun run dev:cli # Run CLI in dev mode
|
|
431
|
-
bun run dev:mcp # Run MCP server in dev mode
|
|
432
|
-
```
|
|
433
|
-
|
|
434
|
-
## Architecture
|
|
435
|
-
|
|
436
|
-
```
|
|
437
|
-
src/
|
|
438
|
-
types/ TypeScript types, enums, custom errors
|
|
439
|
-
db/ SQLite data layer (tasks, projects, agents, task-lists, plans, comments, sessions)
|
|
440
|
-
lib/ Business logic (search, sync, config)
|
|
441
|
-
cli/ Commander.js CLI + React/Ink TUI
|
|
442
|
-
mcp/ MCP server (stdio transport, 29 tools)
|
|
443
|
-
index.ts Library re-exports
|
|
444
|
-
```
|
|
44
|
+
## Data Directory
|
|
445
45
|
|
|
446
|
-
|
|
46
|
+
Data is stored in `~/.hasna/todos/`.
|
|
447
47
|
|
|
448
48
|
## License
|
|
449
49
|
|
|
450
|
-
|
|
50
|
+
Apache-2.0 -- see [LICENSE](LICENSE)
|