@@ -36,18 +36,25 @@ running their respective tasks.
main.go β cmd.Execute() entrypoint
cmd/
root.go β Root command, registers all subcommands and groups
- init.go, ping.go β Top-level commands
+ init/ β Interactive setup wizard (huh forms, multi-step navigation)
+ ping.go β Token verification command
add.go, done.go, jrnl.go β Shortcuts (delegate to resource commands)
- task/ β task add/list/get/update/delete
- note/ β note add/list/get/update/delete
- person/ β person add/list/get/update/delete/timeline
+ task/ β task add/list/show/update/delete
+ note/ β note add/list/show/update/delete
+ person/ β person add/list/show/update/delete/timeline
+ area/ β area list/show (read-only)
+ goal/ β goal list/show (read-only)
journal/ β journal add
habit/ β habit track
internal/
client/ β Lunatask API client factory (uses system keyring)
config/ β TOML config at ~/.config/lune/config.toml
- ui/ β Lipgloss styles (Success, Warning, Error, Muted, Bold)
- validate/ β Input validation (UUID format)
+ completion/ β Shell completion helpers (config-based + static values)
+ dateutil/ β Natural language date parsing via go-dateparser
+ deeplink/ β Parse/build lunatask:// URLs
+ stats/ β Usage statistics helpers
+ ui/ β Lipgloss styles (Success, Warning, Error, H1, H2, FormatDate)
+ validate/ β Input validation (UUID, enums, deep links β UUID)
```
**Command flow**: `fang.Execute()` wraps Cobra with version/commit info and
@@ -55,6 +62,10 @@ signal handling. Resource commands live in subpackages (`cmd/task/`); shortcuts
in `cmd/` delegate to resource commands by calling their `RunE` directly and
copying their flagset.
+**API client pattern**: `client.New()` returns a `*lunatask.Client`. Create
+operations use builders: `client.NewTask(name).InArea(id).WithStatus(s).Create(ctx)`.
+Update operations use separate builders: `client.UpdateTask(id).WithStatus(s).Update(ctx)`.
+
## Command patterns
**Resource commands** (task, note, person, etc.):
@@ -71,8 +82,9 @@ copying their flagset.
- Call resource command's `RunE` directly
**Shell completions** registered inline via `RegisterFlagCompletionFunc`;
-see `cmd/task/add.go:43-56` for examples. Config-based completions load
-from `config.Load()`.
+see `cmd/task/add.go:56-63` for examples. Use `completion.Areas`, `completion.Goals`,
+etc. for config-based completions, or `completion.Static("val1", "val2")` for
+fixed options.
## Core dependencies
@@ -99,6 +111,33 @@ Reference docs via context7 or doc-agent when unsure:
## Gotchas
+### Enum validation
+
+Use `validate.TaskStatus()`, `validate.Motivation()`, `validate.RelationshipStrength()`
+to parse and validate string inputs to `lunatask.*` types. These normalize
+case and return typed values or wrapped errors (`ErrInvalidStatus`, etc.).
+
+### Date parsing
+
+`dateutil.Parse()` accepts natural language ("yesterday", "2 days ago", "March 5")
+and ISO dates ("2024-01-15"). Empty input returns today's date. Returns
+`lunatask.Date` type.
+
+### Stdin convention
+
+Many commands accept `-` as an argument or flag value to read from stdin:
+- `task add -` reads task name from first stdin line
+- `--note -` reads entire stdin as the note content
+
+The implementations differ: name uses `bufio.Scanner` (single line), note uses
+`os.ReadFile("/dev/stdin")` (all content).
+
+### Deep link support
+
+Commands accepting IDs also accept `lunatask://` deep links. Use
+`validate.Reference()` to normalize either format to a UUID. The `deeplink`
+package handles parsing and building these URLs.
+
### Linter exclusions for cmd/
The `.golangci.yaml` disables several linters for `cmd/`:
@@ -113,6 +152,16 @@ The `.golangci.yaml` disables several linters for `cmd/`:
These patterns are intentional.
+### Config key lookups
+
+Areas, goals, notebooks, and habits are stored with user-defined `key` fields
+(short aliases like "work", "personal"). Commands accept keys, not UUIDs.
+Lookup methods: `cfg.AreaByKey()`, `area.GoalByKey()`, `cfg.NotebookByKey()`,
+`cfg.HabitByKey()`. There are also `*ByID()` methods for reverse lookups.
+
+Goals require their parent area contextβuse `cfg.FindGoalsByKey()` to find goals
+across all areas, which returns `[]GoalMatch{Goal, Area}` pairs.
+
### Access token
Read from system keyring via `internal/client.New()`. No interactive
@@ -126,5 +175,13 @@ colors.
## Testing
-Currently stub implementations with `// TODO` markers. When implementing, use
-`cmd.SetOut()` / `cmd.SetErr()` to capture output.
+Table-driven tests with `t.Parallel()`. Use `_test` package suffix for black-box
+testing (see `deeplink_test.go`). When testing commands, use `cmd.SetOut()` /
+`cmd.SetErr()` to capture output.
+
+### Init wizard
+
+The `cmd/init/` package implements a multi-step wizard using `huh` forms.
+Navigation uses `wizardNav` (navNext/navBack/navQuit) with sentinel errors
+(`errQuit`, `errReset`). Steps are functions returning navigation direction;
+the wizard loops through them allowing back/forward navigation.