1<!--
2SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
3
4SPDX-License-Identifier: CC0-1.0
5-->
6
7# AGENTS.md
8
9This file guides LLM agents through interacting with and maintaining
10the lune project—a CLI for the Lunatask productivity app.
11
12## Lunatask concepts
13
14Lunatask is end-to-end encrypted and any sensitive information
15(person/task/note/habit names, contents, etc.) is all omitted. The API
16only returns basic metadata (IDs, timestamps, status, etc.). That also
17means there is no way to dynamically list the user's areas, habits, or
18notebooks; they must copy those details from the desktop app into lune
19during interactive initialisation or reconfiguration.
20
21## Commands
22
23Run these most to least often:
24
25```bash
26task fmt lint:fix staticcheck test # Important ones to run often
27task # Include vulnerability and copyright checks
28```
29
30The Taskfile auto-installs tools (gofumpt, staticcheck, govulncheck) when
31running their respective tasks.
32
33## Architecture
34
35```
36main.go → cmd.Execute() entrypoint
37cmd/
38 root.go → Root command, registers all subcommands and groups
39 init/ → Interactive setup wizard (huh forms, multi-step navigation)
40 ping.go → Token verification command
41 add.go, done.go, jrnl.go → Shortcuts (delegate to resource commands)
42 task/ → task add/list/show/update/delete
43 note/ → note add/list/show/update/delete
44 person/ → person add/list/show/update/delete/timeline
45 area/ → area list/show (read-only)
46 goal/ → goal list/show (read-only)
47 journal/ → journal add
48 habit/ → habit track
49internal/
50 client/ → Lunatask API client factory (uses system keyring)
51 config/ → TOML config at ~/.config/lune/config.toml
52 completion/ → Shell completion helpers (config-based + static values)
53 dateutil/ → Natural language date parsing via go-dateparser
54 stats/ → Usage statistics helpers
55 ui/ → Lipgloss styles (Success, Warning, Error, H1, H2, FormatDate)
56 validate/ → Input validation (delegates to go-lunatask Parse* functions)
57```
58
59**Command flow**: `fang.Execute()` wraps Cobra with version/commit info and
60signal handling. Resource commands live in subpackages (`cmd/task/`); shortcuts
61in `cmd/` delegate to resource commands by calling their `RunE` directly and
62copying their flagset.
63
64**API client pattern**: `client.New()` returns a `*lunatask.Client`. Create
65operations use builders: `client.NewTask(name).InArea(id).WithStatus(s).Create(ctx)`.
66Update operations use separate builders: `client.UpdateTask(id).WithStatus(s).Update(ctx)`.
67
68## Command patterns
69
70**Resource commands** (task, note, person, etc.):
71
72- Parent command in `<resource>.go` with `GroupID: "resources"`
73- Subcommands (add, list, get, update, delete) in separate files
74- Export the `*Cmd` vars for shortcuts to reference
75
76**Shortcuts** (add, done, jrnl):
77
78- Live in `cmd/` directly with `GroupID: "shortcuts"`
79- Copy flags from resource command:
80 `addCmd.Flags().AddFlagSet(task.AddCmd.Flags())`
81- Call resource command's `RunE` directly
82
83**Shell completions** registered inline via `RegisterFlagCompletionFunc`;
84see `cmd/task/add.go:56-63` for examples. Use `completion.Areas`, `completion.Goals`,
85etc. for config-based completions, or `completion.Static("val1", "val2")` for
86fixed options.
87
88## Core dependencies
89
90Reference docs via context7 or doc-agent when unsure:
91
92- `git.secluded.site/go-lunatask` (context7:
93 `/websites/pkg_go_dev_git_secluded_site_go-lunatask`): Lunatask API client.
94 Amolith maintains it, so issues can be resolved or missing features added
95 quickly.
96- `github.com/charmbracelet/huh` (context7: `/charmbracelet/huh`):
97 powerful and attractive libs for interactive forms and prompts
98- `github.com/charmbracelet/lipgloss` (context7: `/charmbracelet/lipgloss`):
99 Terminal styling.
100- `github.com/charmbracelet/fang` (context7: `/charmbracelet/fang`): Cobra
101 wrapper with fancy styling, version injection, signal handling.
102- `github.com/zalando/go-keyring` (context7: `/zalando/go-keyring`):
103 Cross-platform interface to the system keyring
104- `github.com/BurntSushi/toml` (context7: `/burntsushi/toml`): Config file
105 parsing.
106- `github.com/spf13/cobra` (context7:
107 `/websites/pkg_go_dev_github_com_spf13_cobra`): CLI framework.
108- `github.com/markusmobius/go-dateparser` (context7:
109 `/markusmobius/go-dateparser`): Natural language date parsing.
110
111## Gotchas
112
113### Enum validation
114
115Use `validate.TaskStatus()`, `validate.Motivation()`, `validate.RelationshipStrength()`
116to parse and validate string inputs to `lunatask.*` types. These normalize
117case and return typed values or wrapped errors (`ErrInvalidStatus`, etc.).
118
119### Date parsing
120
121`dateutil.Parse()` accepts natural language ("yesterday", "2 days ago", "March 5")
122and ISO dates ("2024-01-15"). Empty input returns today's date. Returns
123`lunatask.Date` type.
124
125### Stdin convention
126
127Many commands accept `-` as an argument or flag value to read from stdin:
128- `task add -` reads task name from first stdin line
129- `--note -` reads entire stdin as the note content
130
131The implementations differ: name uses `bufio.Scanner` (single line), note uses
132`os.ReadFile("/dev/stdin")` (all content).
133
134### Deep link support
135
136Commands accepting IDs also accept `lunatask://` deep links. Use
137`validate.Reference()` to normalize either format to a UUID. Deep link
138parsing and building use `lunatask.ParseDeepLink()` and `lunatask.BuildDeepLink()`
139from go-lunatask.
140
141### Linter exclusions for cmd/
142
143The `.golangci.yaml` disables several linters for `cmd/`:
144
145- `gochecknoglobals`, `gochecknoinits`: Cobra requires package-level vars and
146 `init()`
147- `errcheck`, `godox`: Stub implementations deliberately print without checking,
148 TODOs are placeholders
149- `wrapcheck`: CLI returns errors for display; wrapping adds noise
150- `dupl`: Builder types (`TaskBuilder`, `TaskUpdateBuilder`) share method
151 signatures but differ in type; duplication is structural
152
153These patterns are intentional.
154
155### Config key lookups
156
157Areas, goals, notebooks, and habits are stored with user-defined `key` fields
158(short aliases like "work", "personal"). Commands accept keys, not UUIDs.
159Lookup methods: `cfg.AreaByKey()`, `area.GoalByKey()`, `cfg.NotebookByKey()`,
160`cfg.HabitByKey()`. There are also `*ByID()` methods for reverse lookups.
161
162Goals require their parent area context—use `cfg.FindGoalsByKey()` to find goals
163across all areas, which returns `[]GoalMatch{Goal, Area}` pairs.
164
165### Access token
166
167Read from system keyring via `internal/client.New()`. No interactive
168prompts—fail fast with `client.ErrNoToken` if not configured.
169
170### Output formatting
171
172Use `cmd.OutOrStdout()` and `cmd.ErrOrStderr()` for testability. Styles are in
173`internal/ui/styles.go`—use `ui.Success`, `ui.Error`, etc. rather than inline
174colors.
175
176## Testing
177
178Table-driven tests with `t.Parallel()`. Use `_test` package suffix for black-box
179testing (see `cmd/init/ui_test.go`). When testing commands, use `cmd.SetOut()` /
180`cmd.SetErr()` to capture output.
181
182### Init wizard
183
184The `cmd/init/` package implements a multi-step wizard using `huh` forms.
185Navigation uses `wizardNav` (navNext/navBack/navQuit) with sentinel errors
186(`errQuit`, `errReset`). Steps are functions returning navigation direction;
187the wizard loops through them allowing back/forward navigation.