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