<!--
SPDX-FileCopyrightText: Amolith <amolith@secluded.site>

SPDX-License-Identifier: CC0-1.0
-->

# AGENTS.md

This file guides LLM agents through interacting with and maintaining
the lune project—a CLI for the Lunatask productivity app.

## Lunatask concepts

Lunatask is end-to-end encrypted and any sensitive information
(person/task/note/habit names, contents, etc.) is all omitted. The API
only returns basic metadata (IDs, timestamps, status, etc.). That also
means there is no way to dynamically list the user's areas, habits, or
notebooks; they must copy those details from the desktop app into lune
during interactive initialisation or reconfiguration.

## Commands

Run these most to least often:

```bash
task fmt lint:fix staticcheck test  # Important ones to run often
task                                # Include vulnerability and copyright checks
```

The Taskfile auto-installs tools (gofumpt, staticcheck, govulncheck) when
running their respective tasks.

## Architecture

```
main.go              → cmd.Execute() entrypoint
cmd/
  root.go            → Root command, registers all subcommands and groups
  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/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
  completion/        → Shell completion helpers (config-based + static values)
  dateutil/          → Natural language date parsing via go-dateparser
  stats/             → Usage statistics helpers
  ui/                → Lipgloss styles (Success, Warning, Error, H1, H2, FormatDate)
  validate/          → Input validation (delegates to go-lunatask Parse* functions)
```

**Command flow**: `fang.Execute()` wraps Cobra with version/commit info and
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.):

- Parent command in `<resource>.go` with `GroupID: "resources"`
- Subcommands (add, list, get, update, delete) in separate files
- Export the `*Cmd` vars for shortcuts to reference

**Shortcuts** (add, done, jrnl):

- Live in `cmd/` directly with `GroupID: "shortcuts"`
- Copy flags from resource command:
  `addCmd.Flags().AddFlagSet(task.AddCmd.Flags())`
- Call resource command's `RunE` directly

**Shell completions** registered inline via `RegisterFlagCompletionFunc`;
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

Reference docs via context7 or doc-agent when unsure:

- `git.secluded.site/go-lunatask` (context7:
  `/websites/pkg_go_dev_git_secluded_site_go-lunatask`): Lunatask API client.
  Amolith maintains it, so issues can be resolved or missing features added
  quickly.
- `github.com/charmbracelet/huh` (context7: `/charmbracelet/huh`):
  powerful and attractive libs for interactive forms and prompts
- `github.com/charmbracelet/lipgloss` (context7: `/charmbracelet/lipgloss`):
  Terminal styling.
- `github.com/charmbracelet/fang` (context7: `/charmbracelet/fang`): Cobra
  wrapper with fancy styling, version injection, signal handling.
- `github.com/zalando/go-keyring` (context7: `/zalando/go-keyring`):
  Cross-platform interface to the system keyring
- `github.com/BurntSushi/toml` (context7: `/burntsushi/toml`): Config file
  parsing.
- `github.com/spf13/cobra` (context7:
  `/websites/pkg_go_dev_github_com_spf13_cobra`): CLI framework.
- `github.com/markusmobius/go-dateparser` (context7:
  `/markusmobius/go-dateparser`): Natural language date parsing.

## 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. Deep link
parsing and building use `lunatask.ParseDeepLink()` and `lunatask.BuildDeepLink()`
from go-lunatask.

### Linter exclusions for cmd/

The `.golangci.yaml` disables several linters for `cmd/`:

- `gochecknoglobals`, `gochecknoinits`: Cobra requires package-level vars and
  `init()`
- `errcheck`, `godox`: Stub implementations deliberately print without checking,
  TODOs are placeholders
- `wrapcheck`: CLI returns errors for display; wrapping adds noise
- `dupl`: Builder types (`TaskBuilder`, `TaskUpdateBuilder`) share method
  signatures but differ in type; duplication is structural

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
prompts—fail fast with `client.ErrNoToken` if not configured.

### Output formatting

Use `cmd.OutOrStdout()` and `cmd.ErrOrStderr()` for testability. Styles are in
`internal/ui/styles.go`—use `ui.Success`, `ui.Error`, etc. rather than inline
colors.

## Testing

Table-driven tests with `t.Parallel()`. Use `_test` package suffix for black-box
testing (see `cmd/init/ui_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.
