AGENTS.md

AGENTS.md

Guidance for AI coding agents working in this repository. Document only reflects what exists in code/docs.

Project Type

  • Language: Go
  • CLI: Cobra executed via charmbracelet/fang
  • Module path: git.secluded.site/np
  • Binary name: np

Note: a stable, usable version of np is already in your PATH. If you're Codex, you need to escalate and ask user permission to run np commands. If you're another coding agent like Crush or Amp or Claude Code or Cursor, just execute np as a normal shell command. To use the development build against the user's stable database (BE CAREFUL ABOUT MIGRATIONS!) run task build, then execute ./np.

Development Commands (Taskfile)

  • Format: task fmt (installs and runs gofumpt)
  • Lint: task lint (golangci-lint)
  • Static analysis: task staticcheck
  • Tests: task test (go test -v ./...)
  • Vulnerabilities: task vuln (govulncheck)
  • License compliance: task reuse (REUSE)
  • Build: task build (produces ./np, injects version via ldflags)
  • Run: task run -- <flags> (runs with ldflags)
  • Docs: task docs (generates CLI docs via internal/tools/docgen)
  • Pack: task pack (UPX compresses np)
  • Clean: task clean / task clean-all
  • Release: task release (interactive semver release with gum/svu)
  • Full check: task (default runs fmt, lint, staticcheck, test, vuln, reuse)

Single test:

go test -v -run TestName ./path/to/package

Repository Layout

  • main.go: wires fang.Execute(RootCmd) and sets version from build info
  • cmd/: Cobra commands
    • Root and top-level: a (archive), m (monitor/TUI stub), p (plan printout stub), r (resume), s (start)
    • cmd/g/: goal command group; g (show stub), g s (set goal stub with -t/-d)
    • 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)
  • internal/:
    • db/: Badger wrapper: options, tx helpers, key builders, path hashing
    • goal/: goal document + store
    • task/: task types + store (status index, deterministic IDs)
    • event/: event types + store + payload builders
    • timeutil/: clocks and UTC helpers
    • testutil/: temp DB and test clocks
    • tools/docgen/: CLI doc generator
  • docs/: additional design docs (e.g., Potential schema.md)

CLI Commands (current state)

Commands exist and are registered, but most are stubs that print placeholder output:

np s   # start session
np a   # archive session
np p   # print plan
np r   # resume session
np m   # monitor TUI (stub)
np g   # goal; np g s -t -d (set), np g u -t -d -r (update)
np t   # tasks; -s status flag for filtering
np t a # add tasks; supports batch: -t "one" -d "desc" -t "two" -d "desc"
np t u # update tasks; supports batch status: -i id1 -s status1 -i id2 -s status2

Fang is used for execution/versioning; Cobra provides the command tree.

Data Layer and Storage

Implemented under internal/db, internal/goal, internal/task, internal/event.

  • Database options (internal/db/options.go)
    • Default path: os.UserConfigDir()/nasin-pali/data
    • Retries: MaxTxnRetries (default 5) with exponential ConflictBackoff (default 10ms)
    • SyncWrites defaults to true when not ReadOnly
    • No-op logger by default; Badger logger bridged via adapter
  • Database helpers (internal/db/db.go)
    • View(ctx, fn) for read-only; Update(ctx, fn) for read-write with retries
    • Txn helpers: Get, Set, Delete, GetJSON, SetJSON, Exists, Iterate, IncrementUint64
    • Errors normalized: ErrClosed, ErrReadOnly, ErrKeyNotFound, ErrTxnAborted
    • Iterator uses prefix scans; IterateOptions{Prefix, Reverse, PrefetchValues}
    • Value log size set to 64 MiB when writable
  • Keyspace builders (internal/db/keys.go)
    • Meta/schema: meta/schema_version
    • Per-directory: dir/{dir_hash}/active, dir/{dir_hash}/archived/{ts_hex}/{sid}
    • Global indexes: idx/active/{sid}, idx/archived/{ts_hex}/{sid}
    • Per-session: s/{sid}/meta, s/{sid}/goal, s/{sid}/task/{id}
    • Status index: s/{sid}/idx/status/{status}/{id}
    • Events: s/{sid}/meta/evt_seq (counter), s/{sid}/evt/{seq_hex}; prefixes for scans exist
  • Path handling (internal/db/path.go)
    • CanonicalizeDir: abs + EvalSymlinks + Clean + ToSlash; lowercase on Windows
    • DirHash: blake3-256 of canonical path (hex)
    • ParentWalk: yields canonical parents up to root
  • Encoding helpers (internal/db/encoding.go)
    • Big-endian u64 encode/decode; Uint64Hex for zero-padded lower-hex

Domain Stores

  • Goal (internal/goal)
    • Document: {title, description, updated_at} (UTC)
    • Store: Get, Exists, Set; title is trimmed and required
    • Transaction-scoped TxnStore mirrors operations
  • Task (internal/task)
    • Status: pending, in_progress, completed, failed, cancelled with validation helpers
    • Task: {id, title, description, status, created_at, updated_at, created_seq} (UTC)
    • ID: GenerateID(sid, title, description) uses blake3 of normalized (trim + squash spaces) title/description + sid; first 6 hex
    • Store: Create, Get, Update, UpdateStatus, Delete, List, ListByStatus, Exists
    • Maintains status membership keys; sorts by created_seq, then created_at, then id
  • Event (internal/event)
    • Types: goal_set, goal_updated, task_added, task_updated, task_status_changed
    • Record: {seq, at, type, reason?, cmd, payload}; reason optional; cmd required and trimmed
    • Store: Append, List (supports After and Limit), LatestSequence
    • Sequence stored as 8-byte big-endian counter at s/{sid}/meta/evt_seq; keys use hex-encoded seq
    • Payload helpers in payloads.go build stable snapshots for events

All stores accept an optional timeutil.Clock; default is a UTC system clock. timeutil.EnsureUTC normalizes timestamps.

Testing

  • Tests live under internal/*_test.go (goal, task, event)
  • Helpers: testutil.OpenDB(t) opens a temp Badger DB with cleanup; testutil.SequenceClock yields deterministic times
  • Run: task test or go test -v ./...
  • Example single test pattern: go test -v -run TestName ./internal/task

Doc Generation

  • Tool: internal/tools/docgen (cobra/doc based)
  • task docs runs two invocations: one tree under docs/cli/, and a single-file reference docs/llm-reference.md
  • Note: the Taskfile passes -exclude m but docgen has no -exclude flag; adjust if this causes failures

Output Format for LLMs

  • Status icons: ☐ pending, ⟳ in progress, ☑ completed, ☒ failed, ⊗ cancelled (only show failed/cancelled in legend when present)
  • Commands that change state should print the full plan immediately (current CLI commands are stubs)

Conventions

  • Formatting: gofumpt (not go fmt)
  • Errors and validation follow idiomatic Go patterns visible in stores
  • All source files include SPDX headers; source is AGPL-3.0-or-later; docs/config are CC0-1.0

Gotchas

  • task docs may fail due to -exclude flag unsupported by docgen
  • db.Options sets SyncWrites=true by default when not read-only (durability over throughput)
  • Event sequence counter is raw 8-byte big-endian; do not store decimal strings
  • Windows: directory canonicalization lowercases paths; hashes derive from canonicalized form

Implementation Status

  • CLI commands exist but are stubs that print placeholders
  • Data layer (db, goal, task, event) is implemented with tests; session orchestration and wiring from CLI to stores is not yet implemented
  • docs/Potential schema.md captures intended end-state for sessions, indexes, and events; use as design context, not as a guarantee