Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Project context for any Claude Code session that opens this repo. Keep concise.

> **First time in this repo?** Start with [`docs/agent-briefing.md`](docs/agent-briefing.md) — it walks through orientation (read playbook → recall rememberize-dev context → file first memory note → verify install end-to-end). After the first session, this file is your day-to-day reference.

## What this repo is

Public-facing CLI and Claude Code skill for [rememberize](https://rememberize.app), a portable multi-directional memory system for AI.
Expand Down Expand Up @@ -85,3 +87,51 @@ mcp__rememberize__recall namespace="rememberize-cli-agent" query="last relea
3. The agent runtime injects it via Claude Code settings.

Never commit a real key. `.gitignore` already covers common env files.

## Lessons & gotchas (hard-won from the bootstrap sprint)

These are things future-you wants to know before they bite. Add to this list when you learn something non-obvious.

### Go toolchain alignment

- **`golangci-lint` version is load-bearing when Go minor versions shift.** The bootstrap failed CI three times before we landed on the right combination: `golangci/golangci-lint-action@v8` + pinned `version: v2.11.4`. Earlier versions (v1.64.8, v2.1.6) were built with Go 1.24 and refused configs targeting Go 1.25+. When Go bumps a minor version, check that the pinned lint version has a release built against the new toolchain before merging.
- **Pin, don't `latest`.** Auto-latest picks up whatever GitHub flagged as `Latest` at run time — which may not match your Go target. Explicit version pin in CI is worth the occasional manual bump.

### `.golangci.yml` v2 vs v1

This repo is on the v2 config format (`version: "2"` at the top). Legacy v1 stanzas like `linters.disable-all: true` and enabling `gofmt` as a linter will silently lint nothing. v2 uses `linters.default: none` and moves `gofmt` into a separate `formatters:` section.

### errcheck in CLI code — exclude the usual noise

`.golangci.yml` already excludes `fmt.Fprint`, `fmt.Fprintf`, `fmt.Fprintln`, `(io.Closer).Close`, `(*os.File).Close`, `(*text/tabwriter.Writer).Flush`. Checking these in CLI code produces 20+ false positives and zero insight. If you add a new area that writes to stdout/stderr, you do NOT need to check those returns.

What you DO still need to check (the bootstrap bit us): **`multipart.Writer.Write`, `WriteField`, `Close`**. A silently-dropped error here produces malformed upload bodies. errcheck catches it; don't exclude it.

### Pair protocol — backwards-compat sentinel is load-bearing

`cmd/rememberize/pair.go` sends `client_name: "@auto"` + `hostname: <os.Hostname()>`. Server composes the full display name from its stored `client_hint` + the received hostname. **Older CLI versions still in production send a pre-composed `client_name`** (not `@auto`). The server path keeps both branches alive — if you ever see code that drops the `@auto` check, you've broken every currently-installed binary. Don't. If you genuinely need to change the sentinel, coordinate with the server side first (main repo).

The OTK exchange response includes `connection.name` and `connection.config_target` — **trust those fields.** Use `connection.name` for display, use `connection.config_target` to decide which config file the client writes (claude-code → `.mcp.json`, cursor → `~/.cursor/mcp.json`, cli → no MCP config, generic → print to stdout). Don't resurrect the cwd-sniffing `detectClient()` that used to live here; it was the whole point of F7+F9.

### Two-repo discipline

You cannot import `github.com/ironystock/rememberize/...` — that's the private server repo. If you find yourself reaching for it, you're about to duplicate logic (acceptable, local copies are fine) or design a protocol change (not acceptable here — file a `[MAIN-REPO]` issue and @-mention Brad).

The `internal/transfer/` package here is a minimal local copy, not a sync target. It has its own `Memory` struct (field set reflects only wire formats the CLI parses/emits). If the main repo evolves its `internal/memory.Memory`, this copy does NOT need to follow unless import/export wire formats themselves change.

### IDE diagnostics on a Windows dev host

If you open this repo alongside the private rememberize main repo (`D:\new-projects\rememberize.app\`), gopls may flag spurious "undefined: X" errors on files in `rememberize-cli` — the main repo's workspace doesn't see the sibling module. **These are not real.** Source of truth is `go build ./...` + `go test ./...` + CI, not the IDE. Add a `go.work` at the parent directory if you want cross-repo IDE coherence; don't change source to silence the warnings.

### Release mechanics

- goreleaser cuts on tag push (`v*`). Tags are append-only — don't retag an existing version; cut `v0.x.y+1`.
- `RELEASE_PAT` secret is what lets the release workflow push formula/manifest updates to the sibling `homebrew-rememberize` + `scoop-rememberize` repos. `GITHUB_TOKEN` alone can't do cross-repo pushes.
- Homebrew tap uses the `brews:` goreleaser block (deprecation notice on `brews:` → `homebrew_casks:` exists; we stayed on `brews:` because it still works and `casks` is for GUI apps).
- Windows builds skip `arm64` (goreleaser `ignore: windows/arm64` + `install.sh` errors cleanly on that combo). Add it if demand arrives.

### Misc

- **Binary name is `rememberize`, not `rememberize-cli`.** The repo is `rememberize-cli` for namespace clarity, but the built binary on disk is `rememberize`. Homebrew formula, Scoop manifest, and install.sh all reflect this.
- **Pure Go, `CGO_ENABLED=0` everywhere.** Don't add a CGO dep without a very good reason — cross-compile-for-5-platforms-in-CI becomes a mess.
- **README's canonical install URL is `https://rememberize.app/install.sh`** (served via CF Pages redirect). Raw-GitHub fallback works today but is ugly in docs. If the redirect breaks, fix the redirect, don't edit the README back to raw URLs.
Loading