Skip to content

udpate - #216

Open
plasmobit wants to merge 64 commits into
hmans:mainfrom
plasmobit:just-beans
Open

udpate#216
plasmobit wants to merge 64 commits into
hmans:mainfrom
plasmobit:just-beans

Conversation

@plasmobit

Copy link
Copy Markdown

No description provided.

Plasmobit and others added 30 commits October 2, 2026 16:57
- Add fork note to README naming hmans/beans and Hendrik Mans
- Add Credits section to README
- Add NOTICE file for Apache-2.0 attribution
- Install from source with mise or just; the fork has no releases yet
- Name the three binaries beans, beans-tui and beans-serve; mention the web UI
- Keep only the license badge, pointed at plasmobit/beans
- Fix OpenCode plugin paths and the gitignored .conversations/ directory
- Point Contributing and Getting in Touch at the fork's issues
- Add Core.ClosedAncestor: nearest closed ancestor of an open bean;
  completed/scrapped beans return nothing without walking the parent chain
- List/tree (CLI and TUI): a red ↑ takes the place of the space left of the
  status (`↑T`) instead of the ` ↑completed` title suffix; status stays aligned
- beans show: `parent: <id> !<status>` in red when the parent is closed,
  otherwise an extra `ancestor: <id> !<status>` line; header suffix removed
- ImplicitStatus, the GraphQL implicitStatus field and filters are unchanged

Refs: beans-5fp6
- Rows below a closed ancestor carried a ` ↑completed` suffix appended after
  a title already truncated to the full title width; at width 120 the rows
  wrapped inside the 39-column list pane and pushed the top of the TUI off
  screen, depending on which rows the visible page held
- The suffix is replaced by the in-column ↑ marker (beans-5fp6); add a
  regression test that the list pane renders exactly its given size

Refs: beans-1q77
- Tests in internal/ui and internal/commands import it directly; go mod tidy moves it out of the indirect block
- Recipes for setup, deps, codegen, build, install, test, test-e2e, beans, beans-serve, beans-tui, dev-frontend
- Run pnpm as corepack pnpm@10, since pnpm 11+ ignores onlyBuiltDependencies

Refs: beans-xwvt
- Add `h` key in the list view that hides beans with an archive status
  and beans below a closed ancestor
- Show the mode in the list title as "Beans (active)"
- esc / clear filter leaves the mode untouched
- Add footer and help overlay entries
- Add tests for filtering, tag-filter combination and toggling

Refs: beans-9bmv
- Enable mouse cell motion, so the TUI receives mouse events (also under tmux)
- Left click on a list/tree row selects that bean; the wheel does not scroll the list
- Mouse wheel scrolls the body in the detail view, even while links are focused
- Mouse wheel over the two-column preview scrolls its body; header stays fixed,
  scroll resets on cursor change and survives a reload of the same bean

Refs: beans-xbqz
…nals

- Render the preview body with a glamour renderer that wraps at the pane's
  content width, so lines are wrapped once instead of twice
- Widen the side preview to 88 columns, which leaves 80 columns of
  paragraph text after border, padding and glamour margins
- Show the preview below a 15-row list when the terminal is at least
  35 rows tall and too narrow for a side preview with 80 columns of text
  (< 128 columns); short terminals keep the shrunk side preview from 120
- Cap the stacked preview at 120 columns of text
- Mouse wheel over the stacked preview scrolls it; clicks in the list select
- Replace pane-layout literals in tui.go, preview.go and list.go with named
  constants (borders, footer, separator, paddings, glamour margins)
- Add tests for single wrapping, layout selection and the stacked layout

Refs: beans-cwsf, beans-e8qv, beans-c3t7
…tus names

- CalculateResponsiveColumns reserved 10 columns for the full type name
  while RenderBeanRow rendered 12, so truncated rows overflowed by 2 and
  the pane border wrapped "..." onto its own line
- Share ColWidthStatusFull and ColWidthTypeFull between both
- Add TestListRowsFitPane

Refs: beans-bzbo
- add tui.stacked_list_height to .beans.yml (default 15, minimum 5)
- stack only when the terminal has list height + 20 rows
- keep the setting when the config is saved

Refs: beans-sg3r
- size the list model to its rendered pane (stacked, two-column, single)
- refit before forwarding messages, covering resizes in other views
- share the pane size between paging and the mouse hit test

Refs: beans-0jew
- with a preview visible, pgup/pgdown scroll it by 3 rows
- without a preview they keep paging the list
- list the keys in the help overlay

Refs: beans-dexi
- Add ui.DarkMarkdownStyle and ui.AutoMarkdownStyle: glamour styles with Document.Margin = 0
- beans show: use AutoMarkdownStyle, so text wraps at the full 80 columns
- TUI detail view and preview: use DarkMarkdownStyle; drop glamourMarginX from previewChromeX
- Test that rendered text starts at column 0 and glamour defaults stay unmodified

Refs: beans-l4t4
- List title, or the filter input while typing a filter, sits in the
  list's top border instead of a title bar (gains two rows)
- Bean ID sits in the preview's top border; the header starts with the
  title (gains one row)
- withBorderTitle truncates long titles to keep the pane width
- List click hit-testing no longer offsets by a title bar
- Tests for border titles, filter input and truncation

Refs: beans-bcxk
- New config tui.preview_position: auto (size-based, default), right, below
- A position that does not fit falls back to the other layout, then the list alone
- Key v in the list view toggles right/below until the TUI exits
- List v in the help overlay and the footer
- Tests for layout selection per position, the toggle and the config round trip

Refs: beans-m5hh
- New okf/tui-taxonomy.md: views, list view layouts with the preview
  position, panes, bean row columns and row states, parts of the
  preview pane and the detail view
- Each name gives the code location that defines it

Refs: beans-h08d
- New okf/okf-format.md: the OKF v0.2 subset a project needs to keep its
  documentation as a bundle - layout, frontmatter, sources, linking,
  index and log formats, authoring steps
- New okf/index.md: bundle-root index with okf_version 0.2
- OKF frontmatter for okf/tui-taxonomy.md

Refs: beans-ekdb, beans-b175
- Type/status show names cut to 5 columns from pane width 120 and grow
  to 12 by width 160, taking turns so the title never shrinks
- Tags column appears at 140 with 24 columns, grows to 70 between 160
  and 220; MaxTags follows from the tags width
- RenderBeanRow takes TypeColWidth/StatusColWidth instead of UseFullNames
- Tests for column widths, row text per width, rows fitting the pane
- okf/tui-taxonomy.md describes the column growth

Refs: beans-v3i8
- RenderBeanRow marks a blocked open bean with an amber ⊘ before the
  status; the closed-ancestor ↑ takes precedence, dimmed rows stay
  unmarked
- TUI loadBeans computes blocked beans via Core.IsBlocked (direct,
  incoming blocking links, blocked ancestors)
- h cycles the list view all -> active -> unblocked -> ready instead of
  toggling hide-closed; title shows the mode, footer the next one
- beangraph.AddReadyFilter holds the --ready filter, shared by
  `beans list --ready` and the TUI ready view
- okf/tui-taxonomy.md describes the view modes and the ⊘ mark
- Tests for the mark, the blocked set, each view mode and the h cycle

Refs: beans-cc97, beans-4cko
- e2e/run.sh builds test binaries with plain go build and falls back to `just build-embed` when mise is absent
- justfile passes recipe arguments with their quoting intact (positional-arguments + "$@")
- justfile disables corepack's interactive download prompt and documents corepack as a prerequisite for Node 25+
- `just install` creates ~/.local/bin if missing
- Add bean for git tests that break under a global push.pushOption

Refs: beans-ubkt, beans-eudm

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Title reads 'Blocks:' instead of 'Manage Blocking'
- Legend '● = blocked by <id>' above the key hints

Refs: beans-aln3
- The preview's metadata line shows an amber "⊘ blocked" after the status
  when the list row carries the ⊘ mark
- beanItem.showsBlocked holds the list's precedence: a closed ancestor
  suppresses the blocked mark
- cursorChangedMsg carries the flag; the beansLoadedMsg handler takes it
  from the selected item
- okf/tui-taxonomy.md mentions the mark in the preview header
- Tests for the rendering and for the flag after load and cursor moves

Refs: beans-i597
- beans show prints a "blocked by:" line per direct blocker, from the
  bean's own blocked_by field and from incoming blocking links; a
  resolved blocker is marked with its status
- show --json and list --json print every direct blocker in blocked_by,
  wherever the relation is stored; the file is unchanged
- New output.Bean view for the JSON output
- Fix: list --json without --full printed a wrong etag, because it
  cleared the body of the core's in-memory beans before the etag was
  computed; the body also stayed lost for later reads in the process.
  The view now takes the etag from the full bean and omits the body
  on a copy
- Tests: TestFormatRelationships_BlockedBy, TestJSONBeansBlockedBy,
  TestBeanJSON, TestListJSONETag

Refs: beans-34gf, beans-pl3m
- Add config.FormatVersion (v0.3.0, the last breaking format change) and a top-level format_version field
- beans init writes it; Load leaves it empty when the file has none, so an empty value means the format is unknown
- Save writes the field first with a comment and omits it when empty
- Add format_version to the project's own .beans.yml

Refs: beans-vl03
- Add Bean.Properties (string:string), stored under the `properties` front matter key, plus ValidatePropertyKey
- GraphQL: Bean.properties sorted by key, CreateBeanInput.properties, UpdateBeanInput.setProperties/removeProperties
- CLI: --property key=value on create/update, --remove-property on update, properties in beans show and JSON output
- Show properties in the TUI preview/detail view and in the Beans UI bean detail
- Document the new flags in the agent prompt
- Add follow-up bean beans-1ae4 for filtering, UI editing and format version

Refs: beans-digu, beans-1ae4

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- viewContent clips the list content to the pane's inner width and height
- TestListViewConstrained_ExactSize uses tree depths up to 6, which overflow without the clip

Refs: beans-1q77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- beans update applies only the last --body-replace-old/--body-replace-new pair

Refs: beans-jtas

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- TestListViewContentClipsWideRows renders rows twice the list width, independent of row rendering
- TestListViewConstrained_ExactSize returns to its original tree depths
- Record the opencode review verdicts in the bean

Refs: beans-1q77

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- RenderBeanRow renders the full title when the title budget is 0

Refs: beans-q7ye

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Plasmobit and others added 30 commits October 9, 2026 14:09
- Core.Update(b, base, opts...) takes base, the ETag of the stored bean the
  caller cloned, in place of ifMatch, and writes only if the stored bean still
  has that ETag; otherwise it returns ETagMismatchError
- ETagMismatchError.Concurrent marks a mismatch found by the compare-and-swap,
  with the message "bean changed concurrently"
- Remove the file-byte etag branch; Bean.ETag() serves reads and the check
- Add Bean.ApplyDefaults for type, priority, tags and blocking; loadBean,
  loadBeanFrom, Create and Update all apply it, so a stored bean renders like
  its reloaded form and keeps its ETag
- Move the require_if_match check to validateETag in beangraph, which now
  returns the beancore error types
- Add CoreResolver.cloneForUpdate: get, clone, reject a stale ifMatch early
- UpdateBean, SetParent, AddBlocking, RemoveBlocking, AddBlockedBy and
  RemoveBlockedBy modify a clone, never the stored bean
- Add Core.DetectCycleWith so cycle checks see links pending on the clone
- The TUI editor path updates a clone of the reloaded bean
- Port core tests to clone-modify-swap; add CAS tests for stale bases,
  dirty beans, and concurrent writers sharing one base, and
  TestStoredETagSurvivesReload

BREAKING CHANGE: Core.Update takes base string in place of ifMatch *string.

Refs: beans-o1if

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The etag that the Bean query reports is accepted by UpdateBean with
  ifMatch, for a bean file without a priority line (reproduces beans-o1if)
- A dirty bean (WithPersist(false)) accepts its current etag
- A rejected UpdateBean, SetParent, AddBlocking, RemoveBlocking,
  AddBlockedBy or RemoveBlockedBy leaves the stored bean unchanged
- UpdateBean detects a cycle formed by links added in the same request
- An empty ifMatch under require_if_match fails with ETagRequiredError
- A wrong client etag yields ETagMismatchError with Concurrent false
- Complete beans-o1if with a summary of changes

Refs: beans-o1if

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- beans-o1if: correct the in-place-writer race statement, add ApplyDefaults and Concurrent to the summary, one verdict line per review finding
- beans-6we9: Core methods modify stored beans in place, plus the cross-bean cycle race

Refs: beans-o1if, beans-6we9

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- beans-eudm: rewrite around git tests escaping their temp dirs via
  GIT_DIR and related variables (observed under git rebase --exec);
  list all 10 tests failing under a global push.pushOption; critical
- beans-4vu3: new critical bug, agent tests spawn the real Claude CLI;
  blocks beans-eudm
- beans-28re: new bug, beans serve passes GIT_DIR and related variables
  to spawned agents and terminals; blocked by beans-eudm

Refs: beans-eudm, beans-4vu3, beans-28re
- Add Manager.SetAgentCommand; NewManager leaves the command empty
- Route spawnAndRun, GenerateQuickReplies and GenerateDescription through
  newAgentCmd, which refuses an empty command with errNoAgentCommand
- serve sets the agent command "claude" explicitly
- Test that managers built by NewManager cannot spawn, and that the
  generators run a configured stub executable
- Update test comments that assumed no claude binary is installed

Refs: beans-4vu3
- Add internal/gittest: Isolate() unsets git's local env vars, hides
  global/system config, sets a discovery ceiling at the temp root and
  allows only the file protocol; RequireGitDirInside() fails a test whose
  repository resolves outside its temp dir
- Call Isolate() from TestMain in gitutil, worktree and graph
- Check the git dir right after creating each test repository
- initBranchedTestRepo pushes to the bare repo by path
- TestFetchBaseRefTimesOut allows ssh for itself, makes its sshCommand
  actually hang, and fails if the fetch returns before the timeout
- E2E fixtures apply the same isolation to the Playwright process

Refs: beans-eudm
- beans-gvsj: e2e tests leave worktrees in ~/.beans/worktrees

Refs: beans-gvsj
- beans-qypq: writers in separate processes are not coordinated; drift cases, flock + atomic write design
- beans-6we9: link to beans-qypq

Refs: beans-qypq, beans-6we9
…ks for cycles

- Archive, Unarchive, LoadAndUnarchive, RemoveLinksTo, FixBrokenLinks, SaveDirty and SaveBean store a modified clone instead of writing into the bean in c.beans, so a reader holding a pointer from Core.Get never races with them
- RemoveLinksTo and FixBrokenLinks store a bean only after its save succeeds
- Core.Update re-checks the parent, blocking and blocked_by links a bean adds, under the write lock, and returns CycleError, so two concurrent updates on different beans cannot store a cycle together
- Tests for all seven writers, RemoveLinksTo concurrent with Clone (-race), crossing updates, and a stored cycle not blocking unrelated updates
- beans-9sxr, beans-unjf: follow-ups from the review

Refs: beans-6we9, beans-9sxr, beans-unjf
- codegen, build, test, test-e2e and beans run through the justfile in this fork
…se from agent rules

- dev runs setup, then backend and frontend in parallel; one exiting, Ctrl-C or a closed Run terminal stops both, without signalling the caller
- dev ports: BEANS_PORT/VITE_PORT, else the Run session's BEANS_WORKSPACE_PORT (frontend) and +1 (backend), else 22880/5173; dev-frontend uses --strictPort
- dev-serve rebuilds /tmp/beans-serve-dev-<port> with wgo on non-test .go changes; dev-kill stops the dev servers of every checkout
- release-patch/minor/major tag with svu
- wgo v0.6.2 and svu v3.2.4 via go run, pinned in the justfile; both build with Go 1.24
- .gitignore: /dist/ so internal/web/dist/.gitkeep is committed and a fresh checkout compiles beans-serve
- .beans.yml worktree setup/run, .claude/rules: just instead of mise

Refs: beans-b5a0
- CI workflows install just (extractions/setup-just@v4) and run just deps/build/test/build-frontend
- conductor.json: just setup, just dev with the CONDUCTOR_PORT wiring
- README: just is the only build path
- frontend/e2e/run.sh calls just directly
- justfile header describes the file itself
- mise.toml removed

Refs: beans-jjbr
- beans-xg8t: RemoveLinksTo and FixBrokenLinks bypass Update's routing and send no events
- beans-jhba: terminal Session.Close leaves the shell's children running
- beans-n6n7: release recipes tag a dirty tree or an already tagged HEAD
- beans-6we9: link to beans-xg8t

Refs: beans-xg8t, beans-jhba, beans-n6n7, beans-6we9
- beans-26we: rewrite as "checks that relate a bean to other beans run outside the write lock"; absorbs beans-unjf
- beans-unjf: scrap, merged into beans-26we
- beans-rren: scrap, premise gone since beans-o1if; lock-stall concern moved to beans-qypq
- beans-xg8t: narrow to worktree routing; events arrive via the watcher echo
- beans-i0ag: new, Delete/Archive/Unarchive ignore worktree routing
- beans-qypq: add refresh of other beans under the lock, dirty/worktree compare, temp-file suffix, lock order, lock-file location, Windows; blocked by beans-26we and beans-xg8t

Refs: beans-qypq, beans-26we, beans-xg8t, beans-i0ag, beans-unjf, beans-rren
- beans-xg8t: priority low, parent beans-oyic, add reachability note
- beans-i0ag: parent beans-oyic
- beans-qypq: parent beans-5txp

Refs: beans-xg8t, beans-i0ag, beans-qypq
- beans-qypq: remove blocked_by beans-xg8t; the lock can cover RemoveLinksTo and FixBrokenLinks as they are

Refs: beans-qypq, beans-xg8t
…iew mode

- Add a settings overlay on `,` (list and detail view, not while typing a
  filter) for preview position, preview ratio (10-90 %) and view mode;
  changes apply at once and last for the session only
- Position `below` splits the height by the preview ratio (default 50 %),
  keeps at least 5 rows per pane, and no longer falls back to two columns
- Modals show the real list layout dimmed behind them (`renderListLayout`)
- Resize the inactive list and detail view on a terminal resize, so they
  fit after a modal closes
- Add `,` to the help overlay; describe the layout rules, the ratio and the
  overlay in okf/tui-taxonomy.md
- Tests for ratio, resize, overlay keys, modal background and resize
  behind a modal

Refs: beans-376r
- next.focus is a single milestone/epic ID; drop <global>
- .beans.local.yml carries only next.focus; init appends it to root .gitignore
- invalid focus: refused at set, fallback with warning at next
- refine lane for drafts under a front; open child = not completed/scrapped
- interrupt lane ranks by bean priority first
- define --limit default, --in-progress, JSON shape
- prompt.tmpl update added as todo
- beans-f8mp: TUI key sets/clears the single focus

Refs: beans-p17z, beans-f8mp
- RankNext: lanes interrupt, focus, refine, rest, in-progress
- fronts: explicit focus or in-progress milestones/epics, nearest ancestor wins
- drop milestones, epics and beans with an open child
- ordering by front, then bean priority/type/order/created_at; interrupt ranks bean priority first
- FocusProblem validates a focus ID
- table-driven tests

Refs: beans-p17z
- next.focus key in .beans.yml, saved with a comment
- .beans.local.yml read next to the config dir, also without .beans.yml; only next.focus
- Focus() returns the value and its source file
- SetLocalFocus / ClearLocalFocus write only the local file

Refs: beans-p17z
- config.IgnoreLocalConfig appends the entry if missing, creating the file if absent
- beans init calls it in the cwd branch (not with --beans-path)
- add the entry to this repo's .gitignore

Refs: beans-p17z
- beans next: ranked rows with lane and reason, scope header, multi-front hint
- candidates: --ready set plus unblocked drafts; --in-progress lists beans to resume
- flags --limit (default 10, 0 = unlimited), --all, --in-progress, --json
- JSON {scope, hint, warning, rows}; rows are list beans plus lane, reason, front
- invalid focus falls back to in-progress fronts with a warning
- beans focus / focus set / focus clear on .beans.local.yml; set refuses invalid IDs

Refs: beans-p17z
- "what to work on next" uses beans next --json and --in-progress
- CLI command list gains beans next and beans focus set
- relationship notes name existing commands instead of ready/next/start
- prime_test.go: every `beans <cmd>` in the prompt is a registered command or alias

Refs: beans-p17z
- all todo items done, summary of changes added

Refs: beans-p17z
- with no front, beans next shows the rest lane; scope "no fronts – all ready beans"
- multi-front hint skips in-progress fronts under a completed or scrapped ancestor
- beans focus, focus set and focus clear accept --json
- prompt: focus example uses --json, moved into the CLI command block
- prime_test resolves full command paths, flags bare mentions of planned commands, survives -count=2
- next_test: rest-lane order fixed by manual order instead of same-second created_at
- config.Load with a missing file anchors configDir at its directory and reads .beans.local.yml

Refs: beans-p17z
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant