1<!--
  2SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  3
  4SPDX-License-Identifier: CC0-1.0
  5-->
  6
  7# AGENTS.md
  8
  9Guidance for AI coding agents working in this repository. Document only reflects what exists in code/docs.
 10
 11## Project Type
 12
 13- Language: Go
 14- CLI: Cobra executed via charmbracelet/fang
 15- Module path: `git.secluded.site/np`
 16- Binary name: `np`
 17
 18**Note:** a stable, usable version of `np` is already in your PATH. If
 19you're Codex, you need to escalate and ask user permission to run `np`
 20commands. If you're another coding agent like Crush or Amp or Claude
 21Code or Cursor, just execute `np` as a normal shell command. To use the
 22development build against the user's stable database (BE CAREFUL ABOUT
 23MIGRATIONS!) run `task build`, then execute `./np`.
 24
 25## Development Commands (Taskfile)
 26
 27- Format: `task fmt` (installs and runs gofumpt)
 28- Lint: `task lint` (golangci-lint)
 29- Static analysis: `task staticcheck`
 30- Tests: `task test` (go test -v ./...)
 31- Vulnerabilities: `task vuln` (govulncheck)
 32- License compliance: `task reuse` (REUSE)
 33- Build: `task build` (produces `./np`, injects version via ldflags)
 34- Run: `task run -- <flags>` (runs with ldflags)
 35- Docs: `task docs` (generates CLI docs via internal/tools/docgen)
 36- Pack: `task pack` (UPX compresses `np`)
 37- Clean: `task clean` / `task clean-all`
 38- Release: `task release` (interactive semver release with gum/svu)
 39- Full check: `task` (default runs fmt, lint, staticcheck, test, vuln, reuse)
 40
 41Single test:
 42
 43```bash
 44go test -v -run TestName ./path/to/package
 45```
 46
 47## Repository Layout
 48
 49- `main.go`: wires fang.Execute(RootCmd) and sets version from build info
 50- `cmd/`: Cobra commands
 51  - Root and top-level: `a` (archive), `m` (monitor/TUI stub), `p` (plan printout stub), `r` (resume), `s` (start)
 52  - `cmd/g/`: goal command group; `g` (show stub), `g s` (set goal stub with -t/-d)
 53  - `cmd/t/`: task command group; `t` (list stub with status filter flag), `t a` (add, supports batch via repeatable -t/-d), `t u` (update, supports batch status updates via repeatable -i/-s)
 54- `internal/`:
 55  - `db/`: Badger wrapper: options, tx helpers, key builders, path hashing
 56  - `goal/`: goal document + store
 57  - `task/`: task types + store (status index, deterministic IDs)
 58  - `event/`: event types + store + payload builders
 59  - `timeutil/`: clocks and UTC helpers
 60  - `testutil/`: temp DB and test clocks
 61  - `tools/docgen/`: CLI doc generator
 62- `docs/`: additional design docs (e.g., `Potential schema.md`)
 63
 64## CLI Commands (current state)
 65
 66Commands exist and are registered, but most are stubs that print placeholder output:
 67
 68```bash
 69np s   # start session
 70np a   # archive session
 71np p   # print plan
 72np r   # resume session
 73np m   # monitor TUI (stub)
 74np g   # goal; np g s -t -d (set), np g u -t -d -r (update)
 75np t   # tasks; -s status flag for filtering
 76np t a # add tasks; supports batch: -t "one" -d "desc" -t "two" -d "desc"
 77np t u # update tasks; supports batch status: -i id1 -s status1 -i id2 -s status2
 78```
 79
 80Fang is used for execution/versioning; Cobra provides the command tree.
 81
 82## Data Layer and Storage
 83
 84Implemented under `internal/db`, `internal/goal`, `internal/task`, `internal/event`.
 85
 86- Database options (internal/db/options.go)
 87  - Default path: `os.UserConfigDir()/nasin-pali/data`
 88  - Retries: `MaxTxnRetries` (default 5) with exponential `ConflictBackoff` (default 10ms)
 89  - `SyncWrites` defaults to true when not ReadOnly
 90  - No-op logger by default; Badger logger bridged via adapter
 91- Database helpers (internal/db/db.go)
 92  - `View(ctx, fn)` for read-only; `Update(ctx, fn)` for read-write with retries
 93  - Txn helpers: `Get`, `Set`, `Delete`, `GetJSON`, `SetJSON`, `Exists`, `Iterate`, `IncrementUint64`
 94  - Errors normalized: `ErrClosed`, `ErrReadOnly`, `ErrKeyNotFound`, `ErrTxnAborted`
 95  - Iterator uses prefix scans; `IterateOptions{Prefix, Reverse, PrefetchValues}`
 96  - Value log size set to 64 MiB when writable
 97- Keyspace builders (internal/db/keys.go)
 98  - Meta/schema: `meta/schema_version`
 99  - Per-directory: `dir/{dir_hash}/active`, `dir/{dir_hash}/archived/{ts_hex}/{sid}`
100  - Global indexes: `idx/active/{sid}`, `idx/archived/{ts_hex}/{sid}`
101  - Per-session: `s/{sid}/meta`, `s/{sid}/goal`, `s/{sid}/task/{id}`
102  - Status index: `s/{sid}/idx/status/{status}/{id}`
103  - Events: `s/{sid}/meta/evt_seq` (counter), `s/{sid}/evt/{seq_hex}`; prefixes for scans exist
104- Path handling (internal/db/path.go)
105  - `CanonicalizeDir`: abs + EvalSymlinks + Clean + ToSlash; lowercase on Windows
106  - `DirHash`: blake3-256 of canonical path (hex)
107  - `ParentWalk`: yields canonical parents up to root
108- Encoding helpers (internal/db/encoding.go)
109  - Big-endian u64 encode/decode; `Uint64Hex` for zero-padded lower-hex
110
111## Domain Stores
112
113- Goal (internal/goal)
114  - Document: `{title, description, updated_at}` (UTC)
115  - Store: `Get`, `Exists`, `Set`; title is trimmed and required
116  - Transaction-scoped `TxnStore` mirrors operations
117- Task (internal/task)
118  - Status: `pending`, `in_progress`, `completed`, `failed`, `cancelled` with validation helpers
119  - Task: `{id, title, description, status, created_at, updated_at, created_seq}` (UTC)
120  - ID: `GenerateID(sid, title, description)` uses blake3 of normalized (trim + squash spaces) title/description + sid; first 6 hex
121  - Store: `Create`, `Get`, `Update`, `UpdateStatus`, `Delete`, `List`, `ListByStatus`, `Exists`
122  - Maintains status membership keys; sorts by `created_seq`, then `created_at`, then `id`
123- Event (internal/event)
124  - Types: `goal_set`, `goal_updated`, `task_added`, `task_updated`, `task_status_changed`
125  - Record: `{seq, at, type, reason?, cmd, payload}`; `reason` optional; `cmd` required and trimmed
126  - Store: `Append`, `List` (supports `After` and `Limit`), `LatestSequence`
127  - Sequence stored as 8-byte big-endian counter at `s/{sid}/meta/evt_seq`; keys use hex-encoded seq
128  - Payload helpers in `payloads.go` build stable snapshots for events
129
130All stores accept an optional `timeutil.Clock`; default is a UTC system clock. `timeutil.EnsureUTC` normalizes timestamps.
131
132## Testing
133
134- Tests live under `internal/*_test.go` (goal, task, event)
135- Helpers: `testutil.OpenDB(t)` opens a temp Badger DB with cleanup; `testutil.SequenceClock` yields deterministic times
136- Run: `task test` or `go test -v ./...`
137- Example single test pattern: `go test -v -run TestName ./internal/task`
138
139## Doc Generation
140
141- Tool: `internal/tools/docgen` (cobra/doc based)
142- `task docs` runs two invocations: one tree under `docs/cli/`, and a single-file reference `docs/llm-reference.md`
143- Note: the Taskfile passes `-exclude m` but `docgen` has no `-exclude` flag; adjust if this causes failures
144
145## Output Format for LLMs
146
147- Status icons: ☐ pending, ⟳ in progress, ☑ completed, ☒ failed, ⊗ cancelled (only show failed/cancelled in legend when present)
148- Commands that change state should print the full plan immediately (current CLI commands are stubs)
149
150## Conventions
151
152- Formatting: gofumpt (not `go fmt`)
153- Errors and validation follow idiomatic Go patterns visible in stores
154- All source files include SPDX headers; source is AGPL-3.0-or-later; docs/config are CC0-1.0
155
156## Gotchas
157
158- `task docs` may fail due to `-exclude` flag unsupported by docgen
159- `db.Options` sets `SyncWrites=true` by default when not read-only (durability over throughput)
160- Event sequence counter is raw 8-byte big-endian; do not store decimal strings
161- Windows: directory canonicalization lowercases paths; hashes derive from canonicalized form
162
163## Implementation Status
164
165- CLI commands exist but are stubs that print placeholders
166- Data layer (db, goal, task, event) is implemented with tests; session orchestration and wiring from CLI to stores is not yet implemented
167- `docs/Potential schema.md` captures intended end-state for sessions, indexes, and events; use as design context, not as a guarantee