Skip to content

Commit a6e06b6

Browse files
committed
Release v0.6.0: merge develop into main
Self-update notifications (CLI/TUI/web) + `nibs upgrade`, plus the deferred-status change and keyword-search ID matching staged for v0.6.0.
2 parents 07bb966 + d98f0f4 commit a6e06b6

362 files changed

Lines changed: 51908 additions & 13718 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ jobs:
2727
- run: cd web && npm ci && npm run build
2828
- run: go build ./...
2929
- run: go test -count=1 ./...
30+
# Run the concurrency-critical packages under the race detector so a
31+
# reintroduced data race fails CI (nibs-7l3v). Linux-only: -race on
32+
# Windows needs a mingw toolchain and is materially slower, and the
33+
# invariants are OS-independent, so one detector lane suffices.
34+
- run: go test -race -count=1 ./internal/nibcore/... ./internal/graph/...
35+
if: matrix.os == 'ubuntu-latest'
3036
- run: cd web && npx vitest run --reporter=default
3137

3238
lint:
@@ -41,4 +47,5 @@ jobs:
4147
node-version: "22"
4248
- run: go generate ./...
4349
- run: cd web && npm ci && npm run build
50+
- run: cd web && npm run check
4451
- uses: golangci/golangci-lint-action@v9

.goreleaser.yaml

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,11 @@ builds:
2121
- -s -w -X github.com/alphaleonis/nibs/cmd.version={{ .Tag }}
2222

2323
archives:
24-
- formats:
24+
# Version-less asset names ({project}_{os}_{arch}) so `nibs upgrade`
25+
# (github.com/creativeprojects/go-selfupdate) can match assets against the
26+
# running platform. install.sh / install.ps1 resolve the same names.
27+
- name_template: "{{ .ProjectName }}_{{ .Os }}_{{ .Arch }}"
28+
formats:
2529
- tar.gz
2630
format_overrides:
2731
- goos: windows
@@ -33,6 +37,11 @@ archives:
3337
dst: .
3438
strip_parent: false
3539

40+
# Single, fixed-name checksum file so go-selfupdate's ChecksumValidator
41+
# (UniqueFilename: "checksums.txt") verifies downloads without templating.
42+
checksum:
43+
name_template: "checksums.txt"
44+
3645
release:
3746
draft: true
3847

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/).
77

88
## [Unreleased]
99

10+
## v0.6.0 - 2026-07-19
11+
12+
### Added
13+
- **Update notifications across CLI, TUI, and web** — nibs checks GitHub for a newer release (cached ~24 h in the user cache directory; silently skipped for dev builds, in CI, or when `NIBS_NO_UPDATE_CHECK` is set) and surfaces it unobtrusively: a trailing line on stderr after an interactive CLI command (never for `--json`, pipes, or `serve`/`graphql`/`query`), a footer hint in the TUI, and a dismissible banner in the web UI — backed by a new best-effort `updateStatus` GraphQL query and remembered per version. Version comparison only: no telemetry and no automatic action. (Refs: nibs-jlzy, nibs-ipmj, nibs-imib, nibs-25od.)
14+
- **`nibs upgrade`** — downloads, checksum-verifies, and replaces the running binary with the latest release (or a specific `--version <tag>`), rolling back automatically on failure. `--check` reports whether an update is available without changing anything; pre-releases are skipped by default. When nibs was installed by a package manager (Homebrew, Nix, Scoop, Chocolatey, WinGet, or `go install`), `upgrade` defers to that manager with guidance instead of replacing the binary itself. (Refs: nibs-hkub.)
15+
16+
### Changed
17+
- **BREAKING:** `deferred` is now a nib *status* (parked; non-terminal; excluded from `--ready`) instead of a priority. The priority axis is now `critical / high / normal / low`, and `--priority deferred` is no longer accepted. Existing nibs with `priority: deferred` are normalized to `priority: low` on load — its lowest-rank equivalent — and the normalization is persisted immediately so on-disk and in-memory values agree. (Refs: nibs-0m5d.)
18+
- Release archives are now named `{project}_{os}_{arch}` (the version is no longer embedded in the asset name) and their checksums are published as a single `checksums.txt`, so `nibs upgrade` can match the asset for the running platform; `install.sh` and `install.ps1` resolve the new names. (Refs: nibs-hkub.)
19+
1020
### Fixed
1121
- Keyword search (web keyword box, `nibs list -S`, GraphQL `search:`) now matches nib IDs and ID fragments directly: a substring of the short ID (very short fragments excluded), a prefix of the full ID, or an exact full ID, case-insensitive, surrounding whitespace trimmed. In queries without an explicit sort (e.g. `nibs query`), ID matches come first (sorted by ID, capped at the search limit), followed by full-text hits in relevance order; sorted surfaces (`nibs list`, the web view) interleave them per their sort. A nib matching both appears once. Previously an ID query returned nothing because the index stores `id` as an unanalyzed keyword field. (Refs: nibs-sn96.)
1222

CLAUDE.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ Nibs is a file-based issue tracker for AI-first workflows. Issues ("nibs") are s
1111
All commands use [Task](https://taskfile.dev/) (`go-task/task`) as the task runner. Tool version pinning (Go, golangci-lint, Task itself) is handled by [mise](https://mise.jdx.dev/) via `mise.toml`, so the only thing contributors need to install manually is mise.
1212

1313
- `task build` - Build the `./nibs` executable (runs codegen first)
14-
- `task test` - Run all tests: Go + web (runs codegen and web:build first)
14+
- `task test` - Run all tests: Go + web (runs codegen and web:build first); includes the `-race` gate on `internal/nibcore` + `internal/graph`
15+
- `task test:race` - Run the `-race` detector on the concurrency-critical packages (`internal/nibcore` + `internal/graph`) only
1516
- `task codegen` - Regenerate GraphQL code (`go generate ./...`)
1617
- `task nibs` - Build and run the CLI in one step (`go run .`)
1718
- `go test ./internal/nib/` - Run tests for a specific package
@@ -21,6 +22,8 @@ All commands use [Task](https://taskfile.dev/) (`go-task/task`) as the task runn
2122
- `task screenshots` - Capture web UI screenshots to `web/screenshots/output/` for visual verification
2223
- `task --list` - List all available tasks
2324

25+
`go build ./...` fails in a fresh git worktree — `embed.go` embeds `web/dist`, which is gitignored, so it looks like a broken checkout (`pattern all:web/dist: no matching files found`). Build the web assets there first, or scope to what you need (`go test ./internal/...`).
26+
2427
## GraphQL Schema Changes
2528

2629
When modifying the GraphQL schema (`internal/graph/schema.graphqls`):
@@ -52,7 +55,7 @@ The GraphQL engine runs in-process for CLI commands (`cmd/graphql.go` executes q
5255
- **`internal/nib/`** - Core `Nib` struct, Markdown+YAML parsing/rendering, ID generation, sorting
5356
- **`internal/nibcore/`** - `Core` type: thread-safe in-memory nib store with filesystem persistence, file watching (fsnotify), search (Bleve), and archive management
5457
- **`internal/graph/`** - gqlgen GraphQL layer. `schema.graphqls` is the schema, `schema.resolvers.go` has resolver implementations, `resolver.go` has shared validation logic (parent hierarchy, cycle detection, etag validation)
55-
- **`internal/config/`** - Configuration from `.nibs.yml`. Hardcoded enums: statuses (draft/todo/in-progress/completed/scrapped), types (milestone/epic/bug/feature/task), priorities (critical/high/normal/low/deferred)
58+
- **`internal/config/`** - Configuration from `.nibs.yml`. Hardcoded enums: statuses (draft/todo/in-progress/deferred/completed/scrapped), types (milestone/epic/bug/feature/task), priorities (critical/high/normal/low)
5659
- **`internal/tui/`** - Bubbletea TUI app. Uses the GraphQL resolver internally for all mutations
5760
- **`internal/search/`** - Bleve full-text search index (lazy-initialized, in-memory)
5861
- **`internal/ui/`** - Shared UI utilities (styles, tree rendering)
@@ -77,22 +80,23 @@ The GraphQL engine runs in-process for CLI commands (`cmd/graphql.go` executes q
7780
- **Event delegation**: TreeTable uses delegated event handlers on the scroll container (not per-row callbacks). TreeTableRow is a pure render component with zero callback props — interactive elements use `data-action` attributes (toggle, title, add-child, drag-handle). New actions require a handler case in TreeTable's `handleDelegatedClick`.
7881
- **Svelte context for ambient state**: SelectionState and DragState are provided via `provideSelection`/`provideDrag` from `contexts.ts`. Components read with `useSelection()`/`useDrag()`. Tests must provide context via `makeTestContext()` from contexts.ts — pass as `context` option to `render()`.
7982
- **Shared field components**: Use `StatusSelect`, `TypeSelect`, `PrioritySelect`, `EstimateSelect`, `TagEditor` from `web/src/lib/components/` instead of inline select/tag markup. Use `renderMarkdown()` from `web/src/lib/markdown.ts` instead of inline DOMPurify+marked. Use `.prose-nib` CSS class for markdown prose styling.
83+
- There is no prettier config — **do not run prettier**; it reformats unrelated files (one run churned 129 lines of untouched code).
8084

8185
### Nib Data Model
8286

83-
Nibs are Markdown files with YAML front matter stored in `.nibs/`. Filename format: `{id}-{slug}.md` or `{id}.md`. Archived nibs go to `.nibs/archive/`. The `Nib` struct fields like `ID`, `Slug`, and `Path` are derived from the filename/path, not from front matter.
87+
Nibs are Markdown files with YAML front matter stored in `.nibs/`. Filename format: `{id}-{slug}.md` or `{id}.md`. Archived nibs go to `.nibs/archive/` but **stay in the store and remain visible in all queries**`Core.Archive` keeps the nib in memory and rewrites its `Path`. Archiving is a move, not a removal (only `Delete` removes). The `Nib` struct fields like `ID`, `Slug`, and `Path` are derived from the filename/path, not from front matter.
8488

8589
The `Path` field always uses forward slashes (normalized via `filepath.ToSlash`) for cross-platform portability. When using `Path` for filesystem operations, combine with `filepath.Join(c.root, b.Path)` which handles mixed separators.
8690

8791
### Configuration
8892

89-
Project config lives in `.nibs.yml` at project root (searched upward from cwd). Key settings: `nibs.prefix` (ID prefix like "myproj-"), `nibs.id_length`, `nibs.path` (data directory, default `.nibs`), `nibs.require_if_match` (optimistic concurrency). Nibs path can also be set via `--nibs-path` flag or `NIBS_PATH` env var.
93+
Project config lives in `.nibs.yml` at project root (searched upward from cwd). Key settings: `nibs.prefix` (ID prefix like "myproj-"), `nibs.id_length`, `nibs.path` (data directory, default `.nibs`), `nibs.require_if_match` (optimistic concurrency). Nibs path can also be set via `--nibs-path` flag or `NIBS_PATH` env var — but those move **only the data directory**; config is still discovered from cwd, so pointing them at another project silently applies *this* project's prefix/id_length/defaults to that project's data. To work against another project, pass `--config <dir>/.nibs.yml` — it resolves that project's data directory too, so `--nibs-path` is unnecessary.
9094

9195
For optional config fields with non-zero defaults, use pointer types (`*int`, `*bool`) with `yaml:"...,omitempty"` so nil means "use default" vs explicit zero/false. See `ServerConfig` for the pattern.
9296

9397
### Agent Integration
9498

95-
`nibs prime` outputs a prompt template (`cmd/prompt.tmpl`) that teaches coding agents how to use the GraphQL CLI. This is the primary interface for AI agents.
99+
`nibs prime` outputs the agent onboarding prompt (slim `cmd/prompt.tmpl`, or the full guide `cmd/prompt-full.tmpl` with `--full`). `nibs cheat` prints the whole CLI grammar on one screen, and `nibs catalog <topic>` emits generated vocabulary (fields, filters, hierarchy, recipes, examples, schema). Together these are the primary interface for AI agents.
96100

97101
## Branching & Workflow
98102

@@ -127,15 +131,17 @@ Before starting any new work, run `git fetch` (and `git -C .nibs fetch`) and che
127131
## Testing
128132

129133
- Always write or update tests for changes
134+
- **Prove a new guard bites**: break the behavior it guards and confirm the test fails. A test that passes while its target is broken is decoration. This keeps happening here — guards placed after an assert that throws first (so they never run), and a mutation that survived the entire 1240-test suite.
130135
- Use table-driven tests following Go conventions
131136
- Never hardcode `/` or `\` in path assertions — use `filepath.Join` for OS paths and forward slashes for nib `Path` fields
132137
- For manual CLI testing: `task nibs` compiles and runs the CLI
133138
- For manual CLI testing, `task demo` serves the web UI with a temporary copy of the sample-project fixture (safe to mutate), and `task demo:tui` does the same for the TUI
134-
- **Test fixture dataset**: `testdata/fixtures/sample-project/` has 87 curated nibs (prefix `tnib-`) covering all types, statuses, priorities, hierarchies, and relationships. Use `fixtures.CopySampleProject(t)` from `testdata/fixtures/` to get a temporary copy for write tests. Regenerate with `bash testdata/fixtures/gen-sample-project.sh`.
139+
- **Test fixture dataset**: `testdata/fixtures/sample-project/` has 89 curated nibs (prefix `tnib-`) covering all types, statuses, priorities, hierarchies, and relationships. Use `fixtures.CopySampleProject(t)` from `testdata/fixtures/` to get a temporary copy for write tests. Regenerate with `bash testdata/fixtures/gen-sample-project.sh`.
135140
- Web UI tests: `cd web && npm install && npx vitest run --reporter=agent` (Vitest + jsdom + @testing-library/svelte). Run `npm install` first — node_modules can go stale after branch switches.
136141
- Web test commands require `web/` as the working directory. If cwd has drifted, `cd` to the project root's `web/` directory first.
137142
- **Always use `--reporter=agent`** when running vitest — it keeps output concise. Never pipe vitest through grep; read the output once.
138143
- `task test` runs both Go and web tests. No need to run them separately unless debugging a specific failure.
144+
- **`-race` runs automatically**: `task test` runs `internal/nibcore` + `internal/graph` a second time under `-race` (via `task test:race`), and CI runs the same detector lane on Linux. These packages carry the concurrency invariants (live-pointer/copy-on-write, clone-under-lock), whose guards degrade to trivial checks without `-race` — so a reintroduced data race now fails the default gate, not just a manual `go test -race`.
139145
- **Visual verification of the web UI**: `task screenshots` captures PNGs of the key UI states (table at each view level, detail panel, editor modal, context menu) into `web/screenshots/output/` (gitignored), served from a temp copy of the sample fixture. Read the PNGs to *see* rendered changes — jsdom tests can't verify pixels. One-time setup: `cd web && npx playwright install chromium` (plain `install`, not `--with-deps` — that flag is apt-only and fails on Fedora). Extend `web/screenshots/capture.spec.ts` when new views or themes land.
140146
- **bits-ui timer flush**: `test-setup.ts` has an `afterAll` that waits 50ms so bits-ui's body-scroll-lock deferred cleanup (24ms setTimeout) fires while jsdom still exists. Without this, the timer fires after jsdom teardown causing a spurious "document is not defined" error.
141147

@@ -160,4 +166,5 @@ When working from a plan or work item:
160166
- No backwards compatibility requirements for CLI usage or APIs — this is a new, unreleased project. Only existing nibs data files (`.nibs/` Markdown+YAML format) must remain compatible. Feel free to make breaking CLI/API changes without migration shims.
161167
- **Always prefer TDD when fixing bugs**: write a failing test that reproduces the bug first, then fix the code to make it pass.
162168
- **Code review findings that are too large to fix in-place should be deferred as nibs**, not silently skipped. If a finding requires architectural redesign or broad refactoring beyond the current task's scope, create a follow-up nib to track it.
169+
- **A finding is a claim, and a nib made from one inherits the claim without its evidence.** Defer findings with the command and output that demonstrate them, or label the claim `[Unverified]`. Reproduce a load-bearing premise before building on it: in one 7-nib batch, 4 premises were false — `disabled` blocks selection (it doesn't, in Chromium), a race detector fired 3/8 (80 runs say never), shorthand `#id` mentions don't link (they do), archiving removes a nib from the list (it doesn't). Every refutation came from running something; none from reading. The one premise that survived came from using the app.
163170
- **When creating a new nib, place it at the appropriate position** using `reorderNib` (e.g. `afterId` of a related nib). Consider development dependencies, complexity, and type (bugs before refactors before features) when choosing where it belongs. Don't leave new nibs at the default position.

README.md

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ task build
5656

5757
Prebuilt binaries are also available on the [Releases](https://github.com/alphaleonis/nibs/releases) page.
5858

59+
### Updating
60+
61+
nibs notifies you when a newer release is available — a trailing line on the CLI, a footer hint in the TUI, and a banner in the web UI. To upgrade in place:
62+
63+
```bash
64+
nibs upgrade # download, verify, and replace the running binary (rolls back on failure)
65+
nibs upgrade --check # just report whether an update is available
66+
```
67+
68+
If nibs was installed by a package manager (Homebrew, Nix, Scoop, Chocolatey, WinGet, or `go install`), `nibs upgrade` defers to that manager with guidance instead of replacing the binary itself. Set `NIBS_NO_UPDATE_CHECK=1` to silence the update notifications.
69+
5970
## Quick Start
6071

6172
Initialize nibs in your project:
@@ -67,10 +78,10 @@ nibs init
6778
This creates a `.nibs/` directory and a `.nibs.yml` configuration file. Both should be tracked in version control.
6879

6980
```bash
70-
nibs create "Set up CI pipeline" -t task -d "Configure GitHub Actions for build and test"
71-
nibs list # list all nibs
72-
nibs tui # interactive terminal UI
73-
nibs web # open the web UI in your browser
81+
nibs new "Set up CI pipeline" -t task # create a task
82+
nibs list # list all nibs
83+
nibs tui # interactive terminal UI
84+
nibs web # open the web UI in your browser
7485
```
7586

7687
## Agent Integration
@@ -111,30 +122,33 @@ Or, if your agent framework supports startup hooks, wire `nibs prime` to run at
111122
| Command | Description |
112123
|---------|-------------|
113124
| `nibs init` | Initialize a new nibs project |
114-
| `nibs create` | Create a new nib (task, bug, feature, epic, milestone) |
125+
| `nibs new` | Create a new nib (milestone, epic, feature, task, bug, or research) |
115126
| `nibs list` | List nibs with filtering by status, type, priority, tags |
116-
| `nibs show <id>` | Display a nib's full contents |
117-
| `nibs update <id>` | Update properties, body content, or relationships |
127+
| `nibs get <id>` | Display one or more nibs (full document by default) |
128+
| `nibs set <id>` | Update a nib's metadata and links, or clear a field |
129+
| `nibs body <id>` | Edit a nib's Markdown body (set, append, or replace sections) |
130+
| `nibs mv <id>` | Reposition a nib among its siblings or reparent it |
118131
| `nibs close <id>` | Mark a nib completed with a summary |
119132
| `nibs context` | Show project status summary with progress |
120133
| `nibs plan <id>` | View an ordered plan of a parent nib's children |
121-
| `nibs graphql` | Execute arbitrary GraphQL queries and mutations |
122-
| `nibs roadmap` | Generate a Markdown roadmap from milestones |
134+
| `nibs query` | Run a GraphQL query or mutation |
135+
| `nibs roadmap` | Generate a Markdown roadmap from milestones and epics |
123136
| `nibs check` | Validate configuration and data integrity |
124137
| `nibs web` | Start the web UI server |
125138
| `nibs tui` | Open the terminal UI |
126139
| `nibs prime` | Output the agent integration prompt (slim default; pass `--full` for the complete reference) |
127140
| `nibs archive` | Move completed/scrapped nibs to the archive |
141+
| `nibs upgrade` | Update nibs to the latest release (checksum-verified, with rollback); `--check` to only check |
128142

129143
Run `nibs <command> --help` for full usage details.
130144

131145
## Data Model
132146

133147
Each nib has:
134148

135-
- **Type**: milestone, epic, feature, task, or bug
136-
- **Status**: draft, todo, in-progress, completed, or scrapped
137-
- **Priority** (optional): critical, high, normal, low, or deferred
149+
- **Type**: milestone, epic, feature, task, bug, or research
150+
- **Status**: draft, todo, in-progress, deferred, completed, or scrapped
151+
- **Priority** (optional): critical, high, normal, or low
138152
- **Estimate** (optional): s, m, l, or xl (t-shirt sizes)
139153
- **Tags**: freeform labels for categorization
140154
- **Relationships**: parent/child hierarchy, blocking/blocked-by dependencies, document links

0 commit comments

Comments
 (0)