AGENTS.md

  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.