Skip to content

Commit aeba3af

Browse files
docs: add CODEBASE.md as ~2k-token repo map (#281)
Co-authored-by: Claude Opus 4.7 (1M context) <[email protected]>
1 parent 5dde5d9 commit aeba3af

2 files changed

Lines changed: 298 additions & 56 deletions

File tree

AGENTS.md

Lines changed: 23 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Todoist CLI
22

3+
> For repo structure, where things live, and shared utilities, read
4+
> [CODEBASE.md](./CODEBASE.md) first. This file covers the **rules**;
5+
> CODEBASE.md is the **map**.
6+
37
TypeScript CLI for Todoist. Binary name: `td`.
48

59
## Build & Run
@@ -25,68 +29,21 @@ node dist/index.js <command> ... # run any command
2529

2630
Use this to verify changes work before committing.
2731

28-
## Architecture
29-
30-
```
31-
src/
32-
index.ts # entry point, registers all commands
33-
commands/ # command groups (folders for multi-subcommand, flat files for single)
34-
add.ts # td add (quick add)
35-
auth/ # td auth (login, token, status, logout)
36-
completion/ # td completion (install/uninstall shell completions)
37-
today.ts # td today
38-
inbox.ts # td inbox
39-
task/ # td task <action> — 11 subcommands
40-
project/ # td project <action> — 19 subcommands
41-
label/ # td label <action>
42-
filter/ # td filter <action>
43-
view.ts # td view <url> (URL router)
44-
comment/ # td comment <action>
45-
section/ # td section <action>
46-
... # + notification/, workspace/, reminder/, settings/, stats/, skill/
47-
lib/
48-
api.ts # API client wrapper, type exports
49-
auth.ts # token loading/saving (env var or config file)
50-
completion.ts # Commander tree-walker for shell completions
51-
output.ts # formatting utilities
52-
refs.ts # id: prefix parsing, URL parsing/classification, ref resolution
53-
urls.ts # Todoist web app URL builders
54-
task-list.ts # shared task listing logic
55-
types/
56-
pnpm-tabtab.d.ts # type declarations for @pnpm/tabtab
57-
```
32+
## Rules when changing code
5833

59-
## Key Patterns
60-
61-
- **Ref resolution** (`src/lib/refs.ts`): Entity references are resolved through three strategies:
62-
- **Full name resolution** (`resolveRef` wrappers — `resolveTaskRef`, `resolveProjectRef`): Async, returns the full entity object. Tries URL → `id:` prefix → exact name match → partial substring match → raw ID fallback. Use for entities with user-facing names. Add new wrappers in `refs.ts``resolveRef` is private.
63-
- **ID-only validation** (`lenientIdRef`): Synchronous, no API calls, returns an ID string. Tries `id:` prefix → URL → raw ID → error. Use for entities without a `fetchAll` endpoint (e.g., comments, reminders).
64-
- **Context-scoped resolution** (`resolveSectionId`, `resolveParentTaskId`, `resolveWorkspaceRef`): Async, searches within a parent context (e.g., sections within a project). Each has custom logic in `refs.ts`.
65-
- **Shared helpers**:
66-
- `looksLikeRawId()` decides when a ref is tried as an ID — pure alpha strings (`"Work"`) and strings with spaces are names; mixed alphanumeric without spaces (`"abc123"`) are potential IDs
67-
- `parseTodoistUrl()` extracts IDs from web URLs (task, project, label, filter)
68-
- **Implicit view subcommand**: `td project <ref>` defaults to `td project view <ref>` via Commander's `{ isDefault: true }`. Same for task, workspace, comment, notification. Edge case: if a project/task name matches a subcommand name (e.g., "list"), the subcommand wins — user must use `td project view list`
69-
- **Named flag aliases**: Where commands accept positional args for context (project, task, workspace), named flags are also accepted (`--project`, `--task`, `--workspace`). Error if both positional and flag are provided
70-
- **API responses**: Client returns `{ results: T[], nextCursor? }` - always destructure
71-
- **Priority mapping**: API uses 4=p1 (highest), 1=p4 (lowest)
72-
- **Command registration**: Each command exports `registerXxxCommand(program: Command)` function from its `index.ts` (folder-based commands) or top-level `.ts` file (flat commands). Folder-based commands split each subcommand into its own file with the index.ts wiring them to Commander.
34+
- **Named flag aliases:** where commands accept positional args for context (project, task, workspace), named flags (`--project`, `--task`, `--workspace`) are also accepted. Error if both positional and flag are provided.
35+
- **Implicit `view` subcommand edge case:** `td project <ref>` defaults to `td project view <ref>`. If a project/task name matches a subcommand name (e.g., `"list"`), the subcommand wins — users must use `td project view list`.
36+
- **API response shape:** client returns `{ results: T[], nextCursor? }` — always destructure.
37+
- **Priority mapping:** CLI uses `"p1"``"p4"` strings; API uses 4=p1 (highest), 1=p4 (lowest). Use `parsePriority` from `src/lib/task-list.ts`, never hand-roll.
38+
- **Errors:** throw `CliError(code, message, hints?)` from `src/lib/errors.ts` for anything user-facing. The global `parseAsync().catch` in `src/index.ts` renders it correctly in JSON and pretty modes.
7339

7440
## Testing
7541

7642
Tests use vitest with mocked API. Run `npm test` before committing.
7743

78-
- Tests are colocated next to the command or lib module they cover (for example `src/commands/task/index.test.ts` or `src/lib/refs.test.ts`)
79-
- Shared test helpers live in `src/test-support/` (`mock-api.ts`, `fixtures.ts`)
80-
- When adding features, add corresponding tests
81-
- Pattern: mock `getApi`, use `program.parseAsync()` to test commands
82-
83-
## Auth
84-
85-
Token from `TODOIST_API_TOKEN` env var or `~/.config/todoist-cli/config.json`:
86-
87-
```json
88-
{ "api_token": "your-api-token" }
89-
```
44+
- Co-locate tests next to the command or lib module they cover.
45+
- When adding features, add corresponding tests.
46+
- See CODEBASE.md for the mock-api + fixtures setup.
9047

9148
## Skill Content (Agent Command Reference)
9249

@@ -130,3 +87,13 @@ if (options.json) {
13087
```
13188

13289
Delete, complete, uncomplete, archive, and unarchive commands do not support `--json` as they return no meaningful entity data.
90+
91+
## Keeping CODEBASE.md accurate
92+
93+
`CODEBASE.md` is a structural map, not a file index. Update it when **structure** changes — not on every new file. Triggers:
94+
95+
- new top-level dir under `src/`, or a new command-group folder
96+
- a new broadly-reusable helper in `src/lib/` (the "don't reimplement" catalog)
97+
- changes to command registration, auth/token storage, or build/test/release tooling
98+
99+
Adding a single subcommand to an existing group, or a narrowly-scoped helper used by one caller, does not require an update.

0 commit comments

Comments
 (0)