Changelog
Unreleased
- The screen gate has candidates for twelve more states that were untested for want of data or a seam (#268, decision 595). A new
edgefamily of gate worlds (brickwork/demo/gate_edge.py: theextrasworld plus invented data) holds what the states need: an instruction booklet with no price and a box with only a listing, three catalogue sets nobody owns, a copy whose part list has spare lines with a check that said yes to the spare pass, and two pinned copies.edge-read-onlyis the same data on an instance switched to read-only andedge-emptyhas no copy at all. In the edge worlds only, BrickLink looks configured (invented keys) and Part Spotter's photo recognition is answered by a staged reply (no network). New candidates, none approved: Module states (loading, error, listings only), Item lists read-only, the Add import progress, Part Spotter's Has a sticker, the opened link controls of the Orders import cards, Check this copy (no copies, save error, JavaScript off), the spare pass and the pinned view of Complete sets. The capture script has a newjavascript: falsekey for a capture with scripts switched off. The Add into a lot state stays unbuilt: the Add page has no lot switch.tests/test_gate_edge_world.pyproves that the data of thedemo,showcaseandextrasworlds is unchanged, so no approved baseline moves. - Two screen-gate candidates now show the state they are named for (#268). The Part lot's
set-detectionstate hides the parts list (a script instates.json) so its capture holds the Set detection section instead of the first 3,000 px of the list. The Setstoolbar-options-menustate gets an optionalsizeskey: the options menu does not exist on a phone, so it is captured at 1024 only (Ulf, 12.11.).scripts/screen_gate.pyandscripts/design_screens.py checkhonoursizes(validated; an approved sized state needs one baseline per named width and theme, not six). Both states stayapproved: false. - The local Chrome runner survives a slow start on macOS (#293). The screen gate's capture script and the browser harnesses now count Chrome's printed
DevTools listeningline as started, wait up to 30 s, and launch the whole browser again (fresh profile, the failed process killed, up to 3 attempts) instead of failing withChrome did not start:;chrome.dump_dom()does the same for a rendered test whose--dump-domrun stalls or ends inTeardown watchdog expired. The error after the last attempt shows Chrome's last stderr lines. Linux CI starts Chrome once, as before. On macOSBW_CHROME_HEADLESS_SHELL=1runs the rendered tests on the pinnedchrome-headless-shell(opt-in; the screenshot gate keeps the full Chrome). See Contributing. - The screen gate has candidates for the approved states that were untested (#268).
design/screens/states.jsonnow lists 39 more built states (candidates, not yet approved) for the Shell Jump, the edit sheet, Instruction and Box detail, the Part lot and its pull list and sticker chooser, module states, the copy chooser, item lists, the lot and instruction sheets, filters, grouping and the options menu, orders, the checker, Complete sets and the wish list with a dollar maximum, and records the rest: a page covered by another state names it incovered_by(checked bydesign_screens.py check), and a screen the app does not have (the price watch, the barcode scanner) says so. The data they need is in the gate'sshowcaseworld (orders, a lot, two-copy sets, staged checks) and a newextrasworld (brickwork/demo/gate_extras.py: an instruction, boxes, a dollar wish, a finished check and a running figure check); nothing was added to thedemodataset, so no approved baseline moves. - Build Scout has its own icon, and "No image" fits the small tile (#284). Build Scout no longer borrows the Sets icon in the sidebar and the phone's top strip: it is a magnifier over a brick. A set or part without a picture, in a list row's 56 px thumbnail (Complete sets, Prices, Wishlist, the Workbench lists), now shows its number on one line and a smaller No image under it, inside the tile instead of wrapping and being cut off.
- Fixed: a save line no longer says Undo twice, and a receipt shows only on its own screen (#236). Prices and an item's save line read just Saved beside the one Undo button, as Set Inspector and the Wishlist do. A save's Undo is kept with the screen it was made on: pinning a set on Complete sets no longer shows Saved and an Undo for it on the Wishlist (or on Prices), and the same holds for the collection's saves and the wishlist's own receipt.
- Docs for the new functions, and Zensical 0.1.1. Two tutorials, Find the sets in a bulk lot and Build from what you have, and order the rest, walk through set detection, stickers, the pull list, Build Scout, Order missing parts and Change variant with pictures; the how-to guides say which release brought each, and the README lists them. The docs site is built with Zensical 0.1.1.
- Order missing parts (#225). A new page under Planning, reached from Complete sets (and at
/planning/order-missing-parts), lists every copy with a gap, with a tick, the gap, the repair gain and a pill for a check in progress. Search, Theme, Leave out sets to sell or part out (on by default: a copy whose status or tag says to sell or part it out stays visible, greyed, and can be ticked by hand), Only sets that gain value and Sort live in the address. The order list combines the ticked copies per part, colour and condition, with the quantity still to buy (loose stock taken off as the repair export does) and a chip per source set (6080-1 ×2); its header counts exactly the selection. Lines with no BrickLink number or colour are named and left out. Export K sets · BrickLink XML downloads the samemissing-parts.xmlas Complete sets' export. Read-only, and no script is needed for any of it. - Pull a set out of a lot (#202). Each candidate set of a lot's Set detection has a Pull list: the set's parts (spares left out, whole minifigures as lines) grouped by category with pictures, a counter per line (found of needed), search, Show (To find, Found, All) and Sort (Category, Number). What the lot already holds counts as found; the pieces you tick are kept between visits (a setting row, no schema change, ADR 0029) and need no scripts. Make it a copy is one undoable step: the ticked pieces are filed in the lot, exactly the found pieces move out of this lot into a new copy, everything not found is recorded as missing on it, and the lot keeps the leftovers. The confirm shows the three numbers; Undo puts the pieces back. API v2:
GET /lots/{id}/pull-list/{set_id},POST .../foundandPOST .../make-copy(toolsget_lot_pull_list,make_copy_from_lot); the contract is 199 operations. See Pull a set out of a lot. - Build Scout: which sets can I build from my loose stock (#9). A new Workbench item beside Matchmaker ranks every catalogue set by how much of it your loose parts already make: the percentage of its parts you hold, the missing parts and lines, the whole figures you hold of those it needs, an approximate cost to complete (with the number of lines that have no price) and, listed apart and never in the percentage, the parts that would fit in another colour. Choose the stock (loose stock, lots, storages; damaged off by default) and narrow by minimum percentage, most missing, theme, years and size. Build it makes a copy of the set and moves the matching parts and figures into it as one change you can undo, Add to wishlist notes the wish Buildable from stock, and Missing parts downloads a BrickLink wanted list. The API gets
GET /planning/build-scout(toolget_planning_build_scout) andPOST /items/{id}/build; the contract is 193 operations. A how-to, the reference text and ADR 0027 describe it; saved filter sets, a maximum cost and Reserve parts are not part of this version. - Sets versus a pile of parts (#199). One read-only engine ranks the catalogue's sets by how much of a pile of loose parts each explains, for the set detection and Buildable sets that follow. Every (part, colour) line is weighed by how rare it is (
ln(N/df): a part in thousands of sets weighs almost nothing, one in two sets a lot); a set's evidence is what it holds of the pile, weighed; figures count through their parts and as whole figures, sub-sets through their parent; the same part in another colour or an alternate mould is listed as a swap and never counted. Inverted lists make a query touch only the sets that share a part, cached per catalogue build. API:GET /api/v2/planning/set-scoresover a lot, a storage, all loose stock or a selection of stock lines (and the MCP toolget_planning_set_scores); the Python service isbrickwork.core.set_scoring;scripts/bench_set_scoring.pytimes it on a real catalogue. Reference: Set scoring; decision: ADR 0026. - Lot Detective, backend (#200).
GET /api/v2/lots/{id}/candidate-sets(and the MCP toolget_lot_candidate_sets) ranks the sets a lot may have come from, on the set-scoring engine of #199, read-only. Each set has a score from 0 to 100 (how strongly the found parts point to it, weighed by how rare they are, relative to the best candidate; not a probability), reasons such as "7 of 9 distinctive parts found" and "2 printed parts only in this set", and the distinctive parts found and not found yet with their pictures. Filters: minimum score, theme (id or name, sub-themes included), year range, part count range. Parts that more than N sets hold are ignored by default (ignore_common; N is the settingcandidate_sets_common_max, default 300, shown byGET /settingsand changed withPATCH /settings). A flag named Sticker on a lot's stock is passed to the engine assticker; the screen follows. Reference: Set scoring. - Lot Detective screen (#200). The lot page has a Set detection section, "Which sets are in this lot?": the candidate sets with score bar, reasons, Details (distinctive parts found and not found with pictures, swaps listed apart, Open set), filters for minimum score, theme, years and size, and Ignore common parts, all in the page's address and working without scripts. Candidate sets now list their swaps. See Find the sets in a bulk lot.
- Stickers (#201). Part Spotter's review step has Has a sticker, which tags the filed stock line Sticker; the lot page shows the tag and a chooser, Which sticker is it?, of the sets that hold the part and a sticker sheet, with This one, Keep as a hint and Not a sticker, each undoable (no schema change, ADR 0028). A chosen sticker is strong evidence for its set in set detection and set scores, an open one a small lift. API v2:
GET/POST/DELETEon/lots/{id}/stock/{stock_id}/sticker(s)and three tools. See Mark a sticker. - The screen gate renders in parallel again (#267). Every capture now starts from an empty browser, loads every font face and lays the page out again once the fonts are in, so a capture no longer depends on what a Chrome session rendered before it: one process and four give the same pixels on Linux (
python scripts/screen_gate.py agree, thegate-agreeworkflow). The gate runs on up to four processes by default (BW_GATE_WORKERS=1for one). Six states' baselines were rendered again for a 1 px text shift in drop-downs. ADR 0024 has the cause. - Change an item's variant (#151). A new action moves everything owned of one catalogue item (loose stock, wishes, the figure lines of copies with their whole part lists) to another item of the same kind in one undoable event, keeping each row's id and history, and makes BrickLink's number the new item's preferred link (a link to check is confirmed; the old item's link of it becomes to check). The old item stays a plain catalogue item. Refused like a merge: a merged item, another kind, a job in flight, a line for both items, and a stock row or wish that would meet a live one of the new item. API:
POST /api/v2/items/{id}/change-variant, undone throughPOST /api/v2/events/{id}/undo; the item page has the screen: Change variant… in the Identity module opens a page that copies the merge page (suggestions with the same BrickLink number, search by number or name in the same kind, a preview of what moves, the same refusals in the red message, Undo after the change). How-to: Change an item's variant. - The screen gate shows a fixed version in the footer (#257). The gate's invented world now renders
Brick Work (1.0.0)whatever the release, the text the approved baselines already show, so a release bump no longer changes a baseline and needs no re-approval. The app's own footer is unchanged.
Brick Work 1.0.1 (schema 4.2) · 2026-11-10
A fix release: fresh containers set themselves up on first start and no longer log the gunicorn control-socket error. The schema stays 4.2, so a 1.0.0 collection needs no upgrade step, and going back means starting 1.0.0 on the same file. The published image is ghcr.io/ulef1005/brick-work:1.0.1; a new container no longer needs the console brickwork setup step. Back up brickwork.db and secret.key before you upgrade, as always.
- Containers set themselves up on first start (#266). A new container creates and seeds its missing collection automatically; existing installs are unchanged and the console
brickwork setupstep is no longer needed with this version. The newbrickwork setup --if-missingflag skips any existing collection file. - No control server error at container start (#265). Gunicorn runs with its unused control socket disabled, removing the "Control server error" permission-denied line.
- Facts for AI assistants. The Pages site now serves
/llms.txt(the llmstxt.org convention), built byscripts/build_site.pyfromscripts/site/llms.md: what Brick Work is and is not for, requirements, install, data, keys, imports, API and MCP, what it contacts, with the release's version filled in and links to the docs as raw Markdown. The README has a short For AI assistants section that points to it.tests/test_llms_txt.pychecks that every linked file exists and every placeholder is filled. - What it contacts names the picture downloads. The README's What it contacts now says that pictures of the items you add come from BrickLink and Rebrickable as plain downloads, with no key, as the note under its screenshots already did.
- A video tour. A 1:36 walkthrough on YouTube (watch) shows the collection, Set Inspector, Part Runner and Matchmaker on the demo's invented collection, with a chapter card and captions for each. The README's link bar and its demo line link it, and the landing page has a Watch the tour button beside Try the demo. Its opening and closing scenes are generated with Google Veo, as the video and its description say.
- Set cards show each copy's status again (#258). On Collection › Sets every card said Not checked, also for a copy that is complete, incomplete or sealed; the filter chips above the list were right. The card read the status in a form the list stopped sending with the 4.0 data model (0.6.0). It now shows Complete, Incomplete, Sealed or Not checked for each copy, one pill per status when a set has several copies.
- Install on your computer with Docker Desktop. A new how-to, Install on your computer with Docker Desktop, takes a Windows or Mac user without a server or Git from installing Docker Desktop to the first sign-in: a folder, two files (
compose.yamlof the release anddata/.envwith the password), three commands, and what to do when a step fails. Tested on macOS with Docker Desktop 4.75; Windows is not tested yet. The README's install section and the Pages landing page link it. - The README says who it is for on its first screen. The paragraph under the tagline now says who Brick Work is for, how it relates to Rebrickable and Brickset, and which sites and apps it brings a collection over from. The paragraph on the database files and ids it replaces moved, unchanged, to Works with the sites you already use.
- Discussions with forms. The repository's Discussions are on, and three categories have their own form in
.github/DISCUSSION_TEMPLATE/: Show and tell (your collection, where it runs, what you use, where you came from, what got in the way), Q&A (question, version, where it runs, what you tried) and Ideas (the job, which kind of collector, how you do it today; a clear idea becomes an enhancement issue). Each asks you to leave out personal data. - A social preview picture.
docs/img/social/social-preview-1280x640.pngis the picture GitHub shows when the repository link is shared: the lockup, the lead line and the README's Sets and Part Runner captures on the invented collection. - The install steps follow the release.
tests/test_install_docs.pyfails when the README's or the landing page'sgit clone --branch, or the Docker Desktop guide'scompose.yamllink, names another version thanbrickwork/version.py, so a release commit bumps them with the image tag. - The
checkjob runs in about a third of the time (#254). The tests run in parallel (pytest -n auto --dist loadgroup, pytest-xdist; the Chrome and screen-gate tests share one group), the screen gate runs on its own after them in one Chrome session, as its baselines were made, and a pull request that changes only documentation runs the docs check and the site build instead of the whole gate (scripts/check_scope.py). The standalone smoke test no longer runs twice. No test was removed or loosened; ADR 0024 has the numbers.
Brick Work 1.0.0 (schema 4.2) · 2026-11-09
The first release after milestone B: its maintainer's real collection was set up from scratch through Get started on a test install, and every workflow ran on it. The schema stays 4.2, so a 0.9.0 collection needs no upgrade step, and going back to 0.9.0 means starting it on the same file. It is the first release whose compose.yaml pulls the published image, ghcr.io/ulef1005/brick-work:1.0.0 (amd64 and arm64, with build provenance and an SBOM): install and upgrade with docker compose pull; 0.9.0 and older still build with docker compose build (Upgrade Brick Work). Back up brickwork.db and secret.key before you upgrade, as always.
- The README describes 1.0.0 and introduces the crew. A new section, The crew, above Where we stand, gives each named Workbench workflow a paragraph: Part Spotter, Set Inspector, Part Runner and Matchmaker, with links to their guides; it replaces the short list of three. Where we stand describes release 1.0.0 (milestone B passed, the first release that pulls the published image), and the shipped list names Part Spotter, Storage and the tutorials.
- The upgrade guide shows how to check the published image (#190). Upgrade Brick Work now gives the two
gh attestation verifycommands for a pull-first release: one for the build provenance, one for the SBOM attached to the image, and what a failure means. The README names the SBOM check too. - Tutorial: finish a half-built set (#247). Finish a half-built set is a second learning path in the docs, on the same invented collection as the demo: check a half-built copy in Set Inspector, put the missing parts on a wishlist, receive a parts order against them and watch the copy turn complete. It links Check a set's parts, Manage wishlists and Receive a parts order. Its pictures come from
scripts/site_shots.py(newtut-stems), light and dark; the docs site now shipsdocs/img/tutorials/. - Tutorial: your first set, start to finish (#246). The tutorials page had no tutorial. It now has one: install from the README, the Get started first run (catalogue, keys optional), add one set, check its parts and see what is missing and where it shows up. See Your first set, start to finish.
- Tutorial: build from your bulk (#248). Build from your bulk is a learning path on the user docs site: set up storage with drawers, collect the missing parts of several sets in one pass with Part Runner, then let Matchmaker show the sets your loose stock finishes. Phone and desktop pictures, light and dark, come from
scripts/site_shots.py(new stemsbulk-*). - Tutorial: script your collection (#249). Script your collection is a learning path on the user docs site: create an API token, read and change the collection with the API and the command line, then connect an assistant over MCP and ask it about the collection. Every command and output was run on the invented showcase collection.
- The SBOM attestation uses
actions/attest(#190). The release workflow's SBOM attestation ranactions/attest-sbom, which GitHub has deprecated; it now runsactions/attestv4.2.2 (pinned by SHA) with the same subject, SBOM and registry push. - No empty band under the phone's bottom navigation in the browser (#245). The bottom bar always reserved at least 34 px below its icons, so in Safari, where the browser's own toolbar already sits at the bottom, an empty strip showed under it. The bar now reserves only the space the phone reports: nothing in the browser, the home-indicator space in the installed app. Page content, sheets and save bars still sit just above the bar. The approved phone (390 px) screenshots change by that strip.
- The demo's picture note fits its tile (#197). On the demo, a tile with no picture said where the app gets pictures (Loads from BrickLink when you add the set), even in a list row's small thumbnail, where the sentence spilled out of the tile. The note now goes only into a picture box (
.bc-picture,.bw-picture,.check-picture,.scan-tile) at least 120 px wide; any other tile keeps the app's short No image. The demo page check fails if a note leaves its tile. - The copy of the upstream changelog is gone (#237).
docs/upstream-CHANGELOG.md, the upstream project's release history kept from the fork, is removed; this changelog links the upstream repository for releases 1.4.2 and older. The credit in the README and THIRD_PARTY_NOTICES stays. - The Add search field sits right under the ways to find (#221). On Manage › Add, step 1 put What and Where above the Search, Paste, File and Photo tabs and the search field, so on a phone the field you type into sat below the first screen. The field (or the file and photo choosers) now follows the tabs directly, then What and Where in one row (stacked on a phone), then the results and Review. Nothing else changed, and the Tab key follows the new order. See Bring your collection in from another app.
- The install and upgrade steps for 0.9.0 say
docker compose build(#238). The README and Upgrade Brick Work told you to check outv0.9.0and rundocker compose pull, but that tag'scompose.yamlbuilds the image from source and names no published one, so the pull fetched nothing useful. For 0.9.0 the steps now saydocker compose build, and going back to 0.9.0 or older does too. The pull-first install, and the provenance check of the published image, start with the first release cut after 0.9.0. The tag itself is unchanged. Back up and restore and the Pages landing page say the same. - The Pages landing page no longer lists Collection sync as planned (#239). Its roadmap row said sync was planned although the page's own section says it is available for Rebrickable and Brickset; the row now reads Collection sync with BrickLink, the part that is still planned. The page also said the catalogue uses your own keys; it now says what the README says: the catalogue comes from Rebrickable's public download and needs no key, and your keys add prices, pictures and sync.
- An order e-mail line for a Technic figure in an unknown colour is no longer placed without a colour (#239). A line such as "Red Technic Figure ..." for an old Technic figure that the catalogue holds as a part was placed as that part in no colour even when the e-mail's colour name was not known here, where an ordinary part says The colour name is not known. The figure now takes the no-colour path only when the line names no colour; a named colour that is not known leaves the line for you to match, with that message.
- Lists say the right noun before the page's script runs (#239). The Instructions list's subtitle and Show button said "instructions" until the script replaced it with "booklets", and the Wishlist said "1 wishlist" or "3 wishlist". Both now read "booklets", "1 wish" and "2 wishes" from the first paint, with the same nouns the script uses for every list.
- The Wishlist chips have their gap, and Undo shows once (#224). On Planning › Wishlist the list chips (All lists, Wishlist and your own lists) touched each other; they now have the 8 px gap of the other chip rows. After a save the line read Saved · Undo with an Undo button under it, so Undo showed twice. It now reads Saved with the Undo button beside it on one line, as in Set Inspector. See Manage wishlists.
- Get started and Statistics sit at the top of Tools & Admin (#219). Manage › Tools & Admin now opens with two cards on the soft accent tint, Get started (with how many steps are done) and Statistics, side by side; on a phone they stack. The whole card is a link. The other groups follow in their usual order. See Settings and maintenance.
- Statistics charts read at a glance (#220). Tools & Admin › Statistics drops the cards: two charts sit side by side on a wide screen and one under the other on a phone, each row one line (label, bar, value). All four charts share one scale, so a bar means the same number of copies everywhere, with one note under them instead of one per chart. Each title states its point from your data ("Only 5 copies are complete", "Harbour is the biggest theme, 3 copies"), the headline reads "9 of 25 copies are incomplete", and completeness is in status order (Complete, Incomplete, Not checked, Sealed). After six rows a long tail folds into one outlined row such as "14 more themes". See Settings and maintenance. The approved Statistics screenshots change with it.
- Jump search is calmer (#216). In the search that opens from the top bar (Jump to a set, copy, figure or part, also ⌘K), the highlighted result row is now a soft neutral grey-beige with normal text instead of a clay-tinted fill, and the search field has a thin clay outline instead of a heavy one. The colours follow the light and dark modes; nothing else about the search changed.
- Found 1 on the set page, a missing-only check and a three-step end of a check (#215, #222, #214). Every missing part card on a copy's page has Found 1, which lowers its missing count by one with Undo and leaves the loose stock alone; where the card has Take N, it is a text link under it. Check missing only, beside Check parts, starts a Set Inspector run over just the parts the last check left missing (Missing part n of N, each showing what was missing since the last check); the API's
starttakesscope: missing. The end of any check now shows three steps, 1 Skipped, 2 Missing, 3 Save: you can check the skipped parts at once (recheckin the API) or leave them unchecked, then work through Missing so far. The progress bar in a check now spans the full width. See Check a set's parts. - Found 1 no longer moves a part to the top of Missing so far (#213). In Set Inspector, selecting Found 1 on a part that was still missing afterwards, or answering a listed part again, moved it to the top of the Missing so far list, so the list reordered under your finger. A part already listed now keeps its place, and only a new gap goes on top. See Check a set's parts.
- Items in a storage link to their pages (#223). On Workbench › Storage, the sets, minifigures, parts and other items in a storage were listed as plain text. Their names now open the item's page: a set opens on that copy, anything else on that loose stock. A lot's name stays text, since a lot has no page. In select mode a click on a name still selects the row. See Storage.
- Sort sets by date added (#226). Collection › Sets has a new sort, Date added: when a set came into Brick Work, its newest copy for a set with several. Picking it turns the order to newest first; Ascending turns it round. A collection brought in by an import or a migration has one date for all of it, so those sets keep number order among themselves; sets added from then on sort by when you added them. The API's
GET /copiestakessort=addedtoo. - The Add review shows the set's picture (#217, second half). Reviewing a set, minifigure or other item Brick Work had no picture of showed No image until after Add. The review now fetches and stores the picture when the row is shown (the same sources, order and budgets as the pictures step; a source without one is passed over), and the tile fills in place. The page's line now reads Nothing is saved before the last step, except the pictures fetched to show you. A part waits for its colour. See Pictures and prices.
- A new set's parts get their pictures (#217, first half). Adding a set queued the picture of the set only; its parts and minifigures showed No image until Refresh pictures. Add, and a Fetch from Rebrickable follow-up, now queue the pictures the new copies' parts and figures still lack, as one bulk action that runs after your own work. See Pictures and prices.
- Jobs update live (#218). On Manage › Jobs, only a job's progress bar was polled, and its last update set the bar back to the finished steps and read Import queued for a running job. The state, the step counts and the Bulk actions rows changed only on a reload. While anything is queued, running or waiting, the page now fetches its job area again every five seconds and swaps it in, so states, counts, bars and new jobs show without a reload. When a fetch changes nothing the wait doubles, up to a minute, so a job waiting hours for its budget does not re-render the page every five seconds; a settled page looks once a minute. The search, filters and an open … failed · why list stay as they are, nothing is swapped while you are on a button in the job list, and a hidden tab does not poll. A running import on Add now reads Importing · pictures · 38 of 112 and its bar keeps the running step's share. See Settings and maintenance.
- Breaking for MCP clients: the wishlist tools have plain names (#152).
post_wishlistsiscreate_wishlist,patch_wishlists_idisedit_wishlist,delete_wishlists_idisarchive_wishlist,post_wishlists_id_restoreisrestore_wishlistandpost_wishlists_id_transferistransfer_wishes, with descriptions that say what they do. An assistant or script that calls an old name gets unknown tool and must use the new one; the arguments are unchanged. The REST API and every other tool are unchanged. This is the one rename before v1.0.0 (ADR 0017, amendment of 8 Nov; MCP). - The Workbench workflows have new names (#204). Part to Inventory is Part Spotter, Check Set Parts is Set Inspector, Part Picker is Part Runner and Matcher is Matchmaker, in the navigation, page titles, docs, the README and the site. The old names still work in the jump search, and the addresses, API operation ids, MCP tool names and CLI commands are unchanged.
- The demo and every picture on the README and the Pages site are the built app, on an invented collection only. The demo (
/demo/) shows 22 invented sets (25 copies) over 1989-2023 and a dozen themes with part lists and 44 figures, 8 incomplete copies with missing and damaged parts and 3 missing figures, 90 kinds of loose parts and 33 loose figures in nested storage, gear, books and catalogs, four wishlists with maximum prices, three orders and prices, and it shows Gear, Books, Catalogs, the Matcher, Orders and the Manage pages. None of the design test data's real-named sets, figures, wishes or licensed parts appears: a catalogue item whose name matches the licence list inbrickwork/demo/showcase.py, or a part that is a printed design, is left out. It lives in its own layer, so the screen gate's world and approved baselines are unchanged, and it is built with a fixed clock. Every item has an original black-and-white line drawing instead of an empty picture tile (design/demo-art/, drawn byscripts/demo_art.py, stored as ordinary pictures with the source Demo illustration). The screenshots (README, landing page, use cases, workflows) replace the design project's mock-ups with captures of the running app on that world (scripts/site_shots.py); the sync picture is the built Collection sync screen and is no longer labelled a preview. - Brickset metadata asks for many sets in one call (#194). The Fetching set metadata step asked Brickset about one set per
getSetscall, and Brickset allows 100 of those a day, so a collection of N sets took N/100 days to import. The step now also takes the other queued or waiting jobs whose next step is Brickset metadata, up to 500 sets in all, asks for them in one call and finishes each job's step with its own result (a set Brickset does not return is not found, as before). The call counts once against the daily budget of 100, which is unchanged. If the call fails, the other jobs stay as they were. - The README describes 0.9.0. Where we stand says 0.9.0 is the first stability release and v1.0.0 follows milestone B; the intro and Catalogue, keys and jobs say the catalogue is built from Rebrickable's public download (no key) with BrickLink item lists optional, instead of BrickLink's catalogue XML; the Shipped list names Get started, the other kinds, e-mail and XML orders and the item lists; the services table shows collection sync as available for Rebrickable and Brickset. The Pages landing page, the use-cases page and the tutorials index say the same (no more Pre-1.0,
brickwork migrateordocker compose buildas the install step), and the settings reference no longer namesbricklink-catalog.db. Settings and maintenance has the details. - Install from the published image (#78).
compose.yamlnow namesghcr.io/ulef1005/brick-workat the release's version and keepsbuild: .as the fallback, and the README install is pull-first: clone the release tag, makedata/writable for uid 1000, thendocker compose pull. Upgrade is checking out the new tag anddocker compose pull; going back to 0.8.x or older, which have no published image, still needsdocker compose build. Upgrade Brick Work and Back up and restore say the same. A test keeps the image tag equal to the app version. - A BrickLink figure that the catalogue knows as a part is that part (#150). BrickLink files the old Technic figures (
tech028,tech039) as minifigures, while the catalogue links the same numbers to Rebrickable parts. A BrickLink order line, a BrickLink subsets list orGET /lookup?provider=bricklink&kind=minifigurethat names such a number found no minifigure and made an unidentified one. When no minifigure holds the number and exactly one part holds the very same BrickLink number, it now resolves to that part, as a part line in no colour. A catalogue minifigure still wins, several parts keep today's behaviour, and no other number is tried. Figures already made unidentified keep resolving to themselves. - The Wishlist on a phone has no empty gap under the list chips (#141). At phone width, Planning › Wishlist left about half a screen of empty space between the list chips and the Manage lists, Export, Print and Download CSV buttons. The buttons and the search now follow the chips directly, as on a wider screen. Two approved phone screenshots (light and dark) change with it.
- Counts of one use the singular (#180). The Sets page said "1 copies", the Catalogs page "1 catalogs", and the filter panel's button "Show 1 parts" and the like. A list's subtitle and its Show button, and the Wishlist count, now use the singular for exactly one and the plural otherwise, for every kind.
Brick Work 0.9.0 (schema 4.2) · 2026-11-05
The first stability release (milestone 1.0): a stable schema with tested upgrades from 0.5.x, a written upgrade and backup guide, and the first published container image, ghcr.io/ulef1005/brick-work (amd64 and arm64; see Releases and the container image). A 0.8.x collection (schema 4.1) is upgraded in place when 0.9.0 first opens it read-write: three columns are added and nothing else changes. The upgrade is one-way: 0.8.x cannot open a 4.2 file and stops with a 3.3 file must be migrated; ignore that hint, which is meant for 3.3 files. So back up brickwork.db and secret.key before you upgrade, and to go back, restore that backup (Upgrade Brick Work, Back up and restore). catalogue.db is not touched.
- New items get their picture from every path that adds them (#183). Only Add queued the picture download; an item placed by an order line into loose stock, by Part to Inventory, by Import from BrickTracker, by a Collection sync pull or by Found in the Workbench showed No image until you pressed Refresh pictures. These paths now queue the Downloading images step for an item that has no picture for a colour you hold, once per item and never for an unidentified one. See Pictures and prices.
- Gear, Books and Catalogs get their own icons, simpler filters and a visible phone strip (#153). The sidebar entries for the three kinds no longer borrow the Parts icon: Gear is a shopping bag, Books an open book and Catalogs a catalog over a second page. Their lists drop the filters that only mean something for parts (Problems, Stock: In sets only and Theme), Group by no longer offers Theme, and the search box says Name or number. In the grid, a card without a picture shows its number once, in the picture tile, instead of again above the name; the list view keeps it on the name line, where a long ISBN stays readable. On a phone the top strip scrolls the current entry into view, also after the window is narrowed or the phone turned, so Catalogs no longer sits off the edge. Five approved phone screenshots change with it.
- Brickset's old New and Used values are marked legacy (#173). A collection moved from 3.3 keeps Brickset's set values from that time. Brick Work 3.3 read them from Brickset's website, and Brickset's API has none, so they are never refreshed. The item page's Price records now mark them legacy · Brickset 3.3, not refreshed, and so does the Estimate when it comes from one; the Prices screen labels them the same. Market prices stay BrickLink's. See Pictures and prices.
- An empty kind's page keeps its place in the menu (#171). Opening Gear, Books or Catalogs when the collection holds none, for example from a link, showed no active entry in the sidebar, and on a phone the bottom bar marked Manage and showed its links. While such a page is open, its kind now shows under Collection, marked as the current page. On other pages an empty kind stays hidden, as before.
- Upgrade, backup and restore are written down and tested (#80). New guide Upgrade Brick Work: what each version does to the schema, which step you run yourself (
brickwork migrate4for a 0.5.x collection), how to check the result and how to go back. The README has Upgrade and Backup and restore sections. A new test takes a 0.5.0-shaped (3.3) collection throughmigrate4and the 4.0, 4.1 and 4.2 steps, counting rows and runningbrickwork check's checks at the end. Back up and restore now names the API v2 paths of the export and the check (the v1 paths answer 410). - Schema 4.2. One in-place step adds three columns: who holds a job (#167) and why an order line was not placed (#155). A 4.1 collection is upgraded the first time it is opened, as 4.1 was; Undo of changes made before the upgrade works as before. See Schema notes.
- Order e-mails: more lines get suggestions, and an undone import can be pasted again (#155). A line no item matches exactly now offers Could be candidates from the BrickLink item lists: the longest list name that starts the line's name (a seller's note such as "micro scratches" written after it), then names that hold all of its words (an item BrickLink renamed). They are suggestions only; you still choose. The API's order line has
unplaced_reason, in words, for a line that is not placed. Undoing an import and pasting the same e-mail or XML again brings the document back as a draft, where it was reported as already imported. Export orders with One per order lists only orders that have saved lines. See Receive an order. - A job left running at a restart runs again (#167). If the app stopped mid-job and, after the restart, the old process number belonged to another program, the job could stay running for good, and a catalogue job would refuse every new one as already running. A job claim now records the machine's boot and the start of the process that holds it, and a claim whose process is not that one is taken over. Jobs left running by 4.1 are taken over at the first start on 4.2. A call that was being sent when the process was killed is counted again when the step restarts: restart between jobs, or once the day's budget is used up, to lose none (Sources).
- Brickset's minifigure CSV (#146). Add › Minifigure › File reads Brickset's minifigure export: with Loose the figures you own loose (Brickset's loose count, so the figures in your sets are not added twice), with Wishlist the figures marked wanted. Before, it was refused with CSV needs part_num, set_num or minifig_num. See Bring your collection in from another app.
- Clearer CLI, MCP and order messages (#152).
brickwork mcpcallshttp://127.0.0.1:3333/api/v2by default, the install's own port (was 5000), and a URL that answers with the web app says so instead of returning the page.brickwork settings set incomplete_discount_pctwith a word gives the range message. A secondbrickwork wishlist undoof the same change says Already undone.python -m brickwork.store4 jobsnames an item job's item (was item None). Importing a placed BrickLink order whose items BrickLink has purged says so and suggests pasting the e-mail (was No order lines were found). - What is this? and the import banner (#142, #145). Workbench › What is this? now lights Part to Inventory in the sidebar, the Workbench tool that also identifies a part by photo (was Tools & Admin). After Import from BrickTracker, the banner counts loose items by line, as the preview does, with the pieces beside them: 351 loose items (435 pieces), or just the lines when they agree. Before, it showed the pieces as items.
- Workbench lists show their count (#174). Recent saves on every Workbench tool, and the Part Picker's Pick for which sets? list, showed
<span class="mono" data-count role="status"></span>as text where the number of shown rows belongs. They now show the count. - Focus stays in a sheet you have just opened (#174). Closing a sheet with Escape and at once opening another could move the focus back to the sidebar, out of the new sheet. Focus now goes back to where it came from only when no sheet is open.
Brick Work 0.8.1 (schema 4.1) · 2026-11-04
Two fixes found while setting up and testing milestone B. No schema change: a 0.8.0 collection opens as it is, and going back to 0.8.0 needs no restore. Keep the new secret.key with brickwork.db in your backups.
- Orders with items only BrickLink has (#154). An order line naming an instruction booklet or a BrickLink-only part (some sticker and printed parts) could not be matched, so the order could not be reviewed or saved. When the BrickLink item lists are loaded (Tools & Admin → BrickLink item lists → Load lists), such a line now gets a new item of Brick Work's own, named as BrickLink names it, when the order is read and when you match the line by its number. An e-mail's "(Instructions) for Set 7946" names the set's one booklet (
7946-1). A number another item already holds is never made a second time. Undoing the import leaves the new item, unused. See Receive an order. - Key entry works on a fresh install (#144). Without
BW_SECRET_KEY, Brick Work now makes its own encryption key on first use and keeps it insecret.keybesidebrickwork.db(mode 600), so Get started step 2, Catalogues & keys andPUT /sources/{source}/keyno longer need a setting.BW_SECRET_KEY, when set, still wins and no file is made. If the data folder cannot be written, key entry stays disabled and the message says to setBW_SECRET_KEY(with the command that makes a key) or make the folder writable. A damagedsecret.keyfails closed and is never shown or replaced. Keepsecret.keywithbrickwork.dbin your backups: without it the stored source keys cannot be decrypted and must be entered again (the database export leaves them out anyway). See Back up and restore and Settings.
Brick Work 0.8.0 (schema 4.1) · 2026-11-03
Milestone A, onboarding: a fresh install reaches its own collection through one guided flow, Get started. No schema change: a 0.7.0 collection (schema 4.1) opens as it is, and going back to 0.7.0 needs no restore. See Bring your collection in from another app and Settings and maintenance.
- No key yet is not a failure (#139). A step that only lacks a key (a BrickLink price, Brickset's set data) now ends as done and waiting for the key, so a job no longer shows failed on an install where you skipped the keys. Jobs says Waiting for a key · runs once it is stored. Storing the key puts those steps back in the queue, and so does a start with a key set in the environment. A key the site refuses still fails.
- BrickLink part numbers that name several parts (#140). BrickLink files some Rebrickable parts under one number: 3001 also names the old mould 3556. An XML line for such a part now takes the part with the same Rebrickable number and says so in the review. Without one, it names the candidates. Before, it was refused as Colour needs manual matching although the colour was known.
- Bulk actions are one job (#127): Refresh pictures, Bulk refresh prices and fetching missing booklets show as one row in Jobs, with its progress (done, failed, cancelled, to go), the failed items with their reasons, and Cancel for what is left. Your own work runs first: an Add's import and part list, or a single Update price, go before the batch's next item, so a new set no longer waits up to 45 minutes behind a picture refresh. The per-source budgets hold as before. See Settings and maintenance.
- Get started (#83, milestone A): the first run is one flow of four steps, in this order: Load the catalogue, Set up your keys (optional), Bring your collection in and See how the inventory works. Every step can be skipped for now and taken back. The flow resumes at the first open step, and after the first run it opens again from Tools & Admin › Get started, with how many steps are done. Before, the keys came first and the BrickTracker import was a fourth step. The catalogue step explains what the catalogue is (what it holds, Brick Work ids, what comes later), and once it is done shows how many items and colours it holds and the date of its files (#85). The keys step carries the key cards of Catalogues & keys: what each key gives, a link to where it is made, Test and save, and the site's reason when it refuses one; it says what is missing without keys (#84). Step 3, Bring your collection in, asks where your collection lives today: a Rebrickable or Brickset account (Collection sync), a BrickLink XML file, Import from BrickTracker, another app's BrickLink XML or Rebrickable CSV, or by hand. Each opens its existing path, which offers ‹ Back to Get started. There, a summary counts what came in, how many copies still lack condition and completeness, and links each imported from … tag. Brickset's My Sets CSV is read by Add (File): owned sets with their count, split by new and used, or wanted sets to a wishlist; a file without the columns it needs is refused by name (#12). Add opens on a mode given in its link (
?mode=file). New guide: Bring your collection in from another app (#86). Step 4, See how the inventory works, is five short cards (sets and copies, completeness, loose stock and lots, the workflows at the table, an assistant), each linking to the screen it explains, with the important words in bold; Got it marks it read (#87). See Settings and maintenance.
Brick Work 0.7.0 (schema 4.1) · 2026-11-03
A wish gets a maximum price with box, which brings schema 4.1. A 0.6.0 collection (schema 4.0) is upgraded in place when 0.7.0 first opens it read-write. The upgrade is one-way: 0.6.0 cannot open a 4.1 file, so back up brickwork.db before you upgrade. To go back, restore that backup (Back up and restore).
- Schema 4.1. A wish has a maximum price with box (#131). On a wish's page, Edit has Max price with box and its currency beside Your max price. The price card's footer shows Your max price and Max with box, each a button to its field, or not set. Only a set wish has one. In the API, a set's price with box is compared with the max with box, or with your max price when that is empty: the Wish has
max_price_boxed,max_price_boxed_currencyandunder_max_boxed. A 4.0 collection is upgraded in place when the app starts (or at the first write); a read-only instance (BW_READ_ONLY) or a read-only open refuses a 4.0 file until it has been opened read-write once. Undo of a change made before the upgrade still works. Every wish's ETag changes once at the upgrade, so an API client re-reads a wish before its next edit. The wish card keeps the set's estimate beside the two maxima, and the wishlist CSV export has two new columns, Max with box and its currency, before Note. A stale 4.0 file (made before #124) is refused before the upgrade writes anything, and an upgrade that cannot finish says to open the file again, never to migrate it. The BrickLink wanted list has no such field, so the XML export and import leave it out. See Collection model. - First run says how long loading the catalogue takes: about a minute. Measured on a Raspberry Pi 5 from an empty data folder: 51 s, most of it building the catalogue (#126).
- Faster (#133, #134), measured on a benchmark collection: the jump search by a number 204–262 ms → 29 ms, the item page 185 → 79 ms, the wish page 149 → 58 ms, the Matcher 164 → 71 ms, and app start about 1,000 → 660 ms. A test fixes the outputs of these paths, so the speed-ups change no result.
- Set estimate no longer looks like a link when it does nothing: without edit rights the footer label is plain text (#131).
Brick Work 0.6.0 (schema 4.0, API v2) · 2026-10-28
The data-model release: the collection moves to schema 4.0 with a separate local catalogue, and the API to v2. Breaking: API v1 answers 410 except /api/v1/health; clients move to /api/v2 (API v2). A 0.5 collection is moved with brickwork migrate4 on a copy first (CLI); the 3.3 file is never changed.
- Add says what each step does: numbered steps (Find and select, Review and add, Added), Select instead of Add to list on a search result (tap again to unselect), a bar that keeps Review in view, and an Add button that names where the items go. An item you already own or wish waits for Add another copy or Skip before Add is offered; before, Add was offered and the save failed. The wishlist options show only for the wishlist, and the item types wrap on a phone.
- The site's API reference shows API v2 (#125).
- An order keeps its currency when its document has no total (M.12, #114). An order e-mail has only line prices, so its order now stores EUR and the line prices show it instead of Currency not recorded; a total still needs its currency. Orders stored before get the currency from their raw document when the app starts. See Receive an order.
brickwork checkand the Database page check that the two files belong together (M.12, #114): the collection is bound to the catalogue, every catalogue item and colour in the collection has the same born key there, every part list it names exists, and the digests agree. Each is a named check; a failure names the fix. API v2/database/checkis unchanged. See Back up and restore.- First run needs no key (M.12, #114). Sets on an empty install offers Download the catalogue (or Build from today's files when today's download is on disk, or Activate the catalogue for a file that is there but not switched on): one background job fetches Rebrickable's files, builds the catalogue, creates and seeds the collection file if it is missing, and activates and binds the catalogue. Add by number and Check Set Parts then work with no key. Keys became an optional step. See Settings and maintenance.
- Part lists on the copy page and in Add (M.10 A). The Part list card names the list a copy uses and offers Switch with what changes and which marks will not carry over; a copy can ask for BrickLink's list and waits on the fetch (Cancel stops it); a copy built before a re-download says what changed; retired lines are kept in a collapsed note; a figure line names where its parts came from. The Add review has a Part list picker (with Use this for new copies of this set), warns about a part with no known picture, and offers Fetch from Rebrickable or Add as unidentified for a number not in the catalogue. A missing picture is a quiet dashed tile in light and dark. See Choose and switch a part list.
mainis the 4.0 line: the app runs on the 4.0 store; API v1 answers 410 (except/api/v1/health) until API v2 (M.11).- The collection lists, the item page, the wish, lot and purchase-place pages and the jump search run on the 4.0 store. An item page is
/collection/item/<id>; the old number URLs redirect to it. Screens show the Rebrickable number first with the BrickLink number beside it where it differs, a BrickLink-only item marked, and an unidentified item by its name; search takes both numbers. Conditions and completeness are words on every screen. - Check Set Parts and the collection's writes run on the 4.0 store: a check keeps its answers by part line, so switching a copy to another part list keeps a check in progress; checks in progress before 4.0 start again. Editing, archiving, restoring and Undo (one receipt per save), own photos and captions, new part lots and the loose-stock merge on edit work as before. A figure's own parts are checked at
/workbench/check-parts/<copy>/figure/<line>. Own photos are served at/manage/images/<id>. - The Workbench runs on the 4.0 store: Part Picker, Matcher (Give and Take), Found it, instruction booklets, Part to Inventory (the page, its save and Undo), Storage with its history, and the printable lists with their CSV. A move writes one receipt and a
stock_transferrow naming it. Matching is by item: a part, a figure, or a set's booklet or box meets the loose stock of the same item and colour, and an item still marked to check is matched like any other (the Needs a check list is gone). Instruction booklets are added by the numbers of booklets you already hold or the BrickLink item list names. Photo recognition in Part to Inventory comes back with Identify. - Pictures, prices and keys run on the 4.0 store. The import job fetches a picture (from the Rebrickable catalogue, BrickLink and the Rebrickable API, in the order of the setting; parts try the catalogue first), Brickset metadata and retail price, and BrickLink prices for every colour a part is held in; calls are counted per source and day. An item with no BrickLink number ends the price step as unidentified instead of failing. The Prices screen works by item id and its Update buttons queue the same step. Fetch from Rebrickable now makes the copies (or the wish) the Add row asked for when the job is done, with its own Undo, and says so on the Add page. Updating from 3.3 turns the default picture order into the new default and splits a changed one into the catalogue and the API. See Pictures, prices and where they come from.
- Planning, wishlists and money run on the 4.0 store. Complete sets ranks the copies with a gap by what a repair gains per unit spent, from the cached BrickLink quotes and the repair settings; a pin and the settings are saved and undone as events. Its Export names every line by BrickLink number and colour; an item BrickLink has no number for is left out of the file and named in the message instead of stopping the export. The Wishlist screen, the named lists (create, move, copy, archive, restore, Undo) and the BrickLink XML and Rebrickable CSV exports work by item id; a wish that cannot be named in the chosen format is left out and listed in the export summary. A wish id is now a uuid. Part-out value, retail on the wishlist, wish progress, exchange rates (a rate or the ECB's, converted figures marked ≈) and manual prices (Undo voids the observation) work as before.
- Orders and Identify run on the 4.0 store. An order document (BrickLink XML, the store's e-mail, the BrickLink API) is placed line by line on items through the BrickLink type, number and colour number, looking in your collection's links and the catalogue together; a key that names several items is never guessed: the line stays unmatched, offers its candidates under Could be, and you choose. Review, counting, allocation to a copy's gap or to loose stock, hold, reconcile, the short list and the CSV export work as before; every save is one event with Undo, and an undone import keeps its document and lines as provenance. A total comes with its currency, and a currency can stand without a total (the e-mail's EUR; M.12). A set line cannot be allocated to loose stock (add the set as a copy). What is this? and Part to Inventory recognise a photo through Brickognize and list a number that names several items apart instead of choosing one. Manage → Add takes a photo again: it offers the matches, adds nothing until you choose one, and keeps the photo only with Keep photo.
- Tools & Admin runs on the 4.0 store: Settings (currencies, retail country, the source order, freshness rules; a save is one event with Undo), Catalogues & keys (sources with their budgets, write-only key cards, and a Catalogue card that says what is loaded and names the command when the catalogue is missing or not activated), Values, Jobs, Bulk refresh prices, Statistics, Database (the check keeps its result as
maintenance:database_check; the export is the collection file), Instruction files (a PDF belongs to a set; a booklet shows the files of the set with its number), Identify history and API tokens. A new collection starts with the freshness rules of 0.5. The catalogue is built on the server withpython -m brickwork.store4, not from the browser; the app'scataloguecommand is the same operation.brickwork migrate4ispython -m brickwork.store4 migrate; thebrickwork wishlistcommands take wish ids as text. The BrickLink catalogue XML loader and the colour load are gone with the catalogue builds. - Unresolved items (identity admin) runs on the 4.0 store: the list holds the local items that may be a catalogue item, the links and statuses to check and the items with no number, and each row offers its decisions (merge, confirm or reject a link, link a BrickLink number, keep as unmatched, move to another kind), each with Undo. A merge moves every reference of a local item onto the catalogue item in one step and unmerge puts all of it back exactly. See Resolve unresolved items and merge items.
- Collection sync and Import from BrickTracker run on the 4.0 store (M.8j). A pull places each item by its kind (a set as copies through the part-list preselection, other kinds as loose stock) with one receipt and Undo; a send names an item by its Rebrickable or BrickLink number and lists an item with no number as not on the site; the link is carried by the migration and the first sync compares everything. The BrickTracker import is rewritten on Rebrickable numbers: copies through Add's path with BrickTracker's marks on the part lines, loose parts and figures as stock, lots, wishes and flags, one receipt, one Undo.
brickwork migrateand the "Build a new database instead" form are removed (a 3.3 collection moves withbrickwork migrate4). The demo is rebuilt on a 4.0 collection. Two guards join the suite: no code uses(item_type, item_no)as an identity, and every query on part, figure and loose-figure lines leaves retired rows out. - Tools & Admin looks after the catalogue lifecycle (M.10 C, #112): Catalogue (the current build, Re-download and Rebuild as background jobs with progress, what changed and the copies whose part list changed), BrickLink item lists (load from a folder, what the last load did), Mappings and coverage and the Migration report with downloads. Settings gets Prefer BrickLink's part list for new copies and a reorderable Picture source order. A catalogue swapped in but not yet reconciled is reconciled when the app (or
brickwork worker) starts, as a job the drainer runs;BW_MIGRATION_REPORTnames the report folder. GET /api/v1/healthalso returns the app version (app), so monitors and update checks need one call.- Error responses never carry database or operating-system error text (#76).
- Security:
certifi2026.10.19, outside the range of the emSign root CA advisory (#81). - An API write that queues a catalogue import (adding a set, part or wish, or moving a wish to owned) now starts the import worker; before, the import waited until something in the web app started it (#121).
Brick Work 0.5.0 (first public release) · 2026-10-18
The first public release: a self-hosted web app for a brick collection that helps at the table, not only in the inventory. It is pre-1.0; the schema and the API can still change between minor versions.
- Collection: sets, minifigures, parts, instructions and boxes, with copies, storage, purchase details, statuses, tags and notes, in one SQLite file. Every list is searchable, filterable and sortable.
- Check Set Parts: count a copy's parts at the table, in inventory, colour or largest-first order, with a missing pass, Undo and resume.
- Part Picker: choose unfinished sets and get the parts you can pull from your sorted loose stock; Complete sets shows which sets that stock can finish.
- Matcher, Part to Inventory and What is this?: match loose stock to the sets that need it, and identify parts and minifigures from a photo (Brickognize) with what you already own of them.
- Orders: import a BrickLink order, an email or an XML file, count what arrived and allocate it to sets or loose stock.
- Planning: wishlists with a maximum price per wish, named lists and BrickLink XML or Rebrickable CSV export; prices from BrickLink, Rebrickable and Brickset with your own keys, including a part-out value.
- Storage, printable lists, statistics and an installable web app with light and dark themes.
- For scripts and assistants: a versioned REST API with scoped tokens and an Undo link on every change, an admin CLI and an MCP server.
- Import an existing collection from an older tracker database, read-only.
- Self-hosted with Docker Compose. No telemetry and no account with this project; no catalogue data or images are bundled, each install uses its owner's keys.
Source and compose files only; there is no container image for this release. Install: see the README.
All changes in this release
- Kit controls: no control falls back to the grey bordered look any more. The off-design secondaries (Print missing parts, Pin, Take, the Matcher's help links, the ledger Filters) are the kit's outline clay, the Manage pages use the kit's neutral secondary, the value chips are filter chips, and every
.primaryis the kit's clay primary. The wish page follows frame 7b: Move or copy to another list is a quiet action in the Wanted module that opens a sheet with the lists as segments, and Undo is a quiet action. - Error responses no longer carry database, file-system or other internal error text (#76): messages written for people still show, anything else is logged on the server and replaced by the handler's plain message.
- Tools & Admin → About: version, licence, source link, data credits, the LEGO disclaimer and BrickLink's required notice (also in THIRD_PARTY_NOTICES).
- What is this?: Enable camera opens a live preview with a guide, as in Part to Inventory; the next press (or Space) takes the picture and identifies it. A saved photo stays the quiet alternative, and the Part/Minifigure switch is a kit segment.
- README: how to get BrickLink, Rebrickable and Brickset keys and the limits each service sets; the install starts with the clone and asks for the password before the first start (found by a fresh-machine test).
- Demo: four copies hold a running set check made with the app's own checker at build time (first part, about 40 % answered, finished with six missing, finished clean), so Start, Resume and the finish screens show real states.
- Demo: the missing-picture tiles keep the item number and say where pictures come from: a set's picture from BrickLink when the set is added; part and figure pictures from Rebrickable or BrickLink with Refresh pictures.
- Publication review: the design test data uses invented owner names, and the private-material scans keep only generic patterns in the repository; a maintainer's own patterns come from
BW_PRIVATE_PATTERNS_FILE. - Static demo:
scripts/build_demo.py OUT --base /brick-work/demo/renders the Sets, Minifigures and Parts lists, set and part pages, Check Set Parts, Part Picker, Part to Inventory, Wishlist, Prices, Complete sets and Storage with the real templates on an invented collection (no pictures, no network). Writes say "Demo with sample data: changes are not saved". - The public snapshot keeps executable files executable (
scripts/check.sh,bin/brickwork,entrypoint.shhad lost the bit in the first snapshot). - Migration proof: the reviewed collection counts are re-pinned for the cutover (two set price lookups since the review added two items with their price, source and search rows).
- Item pages: Update price queues a market price refresh for that item (every colour it is used in) and says so. It opened the bulk refresh page, which lists stale prices only and so showed 0 for an item never priced.
- Storage: the selected storage is an inset, rounded band rather than a flush strip, and the list count no longer counts the Not stored row, so it matches the header (2 storages, not 3).
- Part Picker: the set list shows 15 sets a page with the Collection pager (#52). Ticked sets on other pages stay chosen.
- Tools & Admin: every option carries one short sentence on what you can do there.
- The app footer no longer carries the upstream credit; the README credits the upstream project in its closing Acknowledgements section.
- Wishlist management restyled after BrickLink's Wanted Lists: the lists as chips with counts, one row of outline actions (Manage lists, Export, Print, Download CSV), Export and Manage lists as sheets, and a selection bar with Move and Copy that shows while wishes are ticked.
- Part-out value: shown only when at least 90% of a set's lines have a price. With fewer, the price card says "Not enough prices yet" and offers Fetch part prices, which queues a market price refresh for the parts without one. It used to sum whatever few lines were priced (4 of 54 lines gave €0.18).
- Check Set Parts, running check: the header follows frame 3e (set line, name, progress). The bordered Choose another copy button is gone (it belongs to the Check this copy step, as a link) and the status pill shows at the finish only.
- Documentation site for GitHub Pages (
scripts/build_site.py,.github/workflows/pages.yml): the README, the API reference from the OpenAPI contract, and a new MCP guide whose tool lists are generated from the server. A settings reference in the README lists all 38 settings.tests/test_docs_drift.pyfails when the docs name a setting, a command or a link the code does not have, or the code reads a setting the reference does not list. - Check Set Parts, Largest first: orders by the part's physical size (from its name and category: a baseplate, then a 2 x 4 brick, then a 2 x 4 plate, then a 1 x 1 plate), then by count and colour. It ordered by count alone, so twenty 1 x 1 plates came before the baseplate.
- Review follow-ups for #62 to #68: the add page's photo upload keeps its 8 MB; money such as -2.00 stays a number in CSV exports; the plan receipt search runs only for a plan file marked applied without a marker, and keeps the event id; the CLI says how to fix an unwritable data folder (and the README chowns it before setup); the session key file appears whole or not at all and a damaged one is replaced; the token form id is kept in the database.
- Small web defects (#68): query arguments named like url_for's own options (
_external,_anchor,kind) no longer give a 500 or a link to another host; purchase places and collection sync show the usual notice before setup; reloading the page that showed a new token's secret does not create a second token; a read-only instance exports without writing an event; the embedded job drainer cannot miss a job queued while it stops. - Sessions (#66): changing the password ends every open session; a cross-site link cannot log you out (logout also takes POST);
BW_SECURE_COOKIES=1sends the session cookie only over HTTPS; every response carriesX-Content-Type-Options,X-Frame-OptionsandReferrer-Policy; the navigation counts no longer show before login. - Container (#65): runs as uid 1000 with the code read-only, writes only to
/app/data, has a health check on/api/v1/health, and stops with the fix whendata/is not writable (after an upgrade from a root image:sudo chown -R 1000:1000 data). Gunicorn's timeout is 120 s.compose.local.yamlpublishes on127.0.0.1. - CSV exports (lists, orders, wishlists) open as text in a spreadsheet (#67): a cell starting with
=,+,-,@, a tab or a carriage return gets a leading apostrophe. - Review follow-ups for #59 to #64: a warning when forwarded headers arrive with
BW_TRUSTED_PROXIES=0; the check API returns the checker's own event and its Undo link again, and a repeated operation from another token is answered, not a 500;brickwork mcp --transport httpalso refuses an open install; browser uploads get their own caps (8 MB identification, 2 MB add list, 1 MB order files, 15 MB photos, 20 MB PDFs); the session key file is created once even with two workers; plans applied before this release are recognised by their receipt, markers are pruned after three days, and a repeated apply says so instead of repeating the counts. - A sync pull or an import plan applies once (#64): two submits, or a crash between the commit and the plan file, applied it twice. The applied state is now a database row written in the same transaction.
POST /api/v1/copies/{id}/checkworks after its first call (#63): it failed with 500 on any store that has the "Set is checked" flag. Its events now recordvia='api'and the token name, and the response'sevent_idnames the API operation.- Request bodies are capped before they are read (#62): 4 MB for JSON and forms, 8 MB for identification photos, the import limit (
BW_IMPORT_MAX_MB, default 200) for other uploads; larger bodies answer 413. - The legacy import's "Build a new database instead" form (#61): the browser form only reads and writes inside the data folder;
brickwork migratekeeps taking any path. - First run (#60): an empty
BW_AUTHENTICATION_KEYno longer breaks every page; a session key is generated intodata/session.key. The server refuses to start withoutBW_AUTHENTICATION_PASSWORDunlessBW_ALLOW_NO_LOGIN=1, andcompose.yamlpublishes the port on127.0.0.1only. - Forwarded headers are trusted only with
BW_TRUSTED_PROXIESset (#59): a client reaching the app directly can no longer pick its own address to escape the login and token back-off. Behind a reverse proxy, setBW_TRUSTED_PROXIES=1. MCP over HTTP counts each client on its own. - Release files: README status, privacy, repository and trademark sections;
CONTRIBUTING.md,SECURITY.md,CODE_OF_CONDUCT.md(Contributor Covenant 3.0),THIRD_PARTY_NOTICES.mdand the Patrick Hand licence; issue templates; a CI workflow runningscripts/check.shwith read-only permissions and pinned actions; Dependabot;scripts/public_snapshot.py, which exports the public tree without internal build notes and checks it for private material and secrets. - Remaining upstream code replaced: one settings module (13 settings) and one
.envloader, login inweb/auth.py, unused packages and Socket.IO hooks removed, upstream user docs and screenshots removed, upstream history moved todocs/upstream-CHANGELOG.md. - Settings no longer read (setting them does nothing):
BW_UI,BW_TIMEZONE,BW_HIDE_MISSING_PARTS(useBW_HIDE_ALL_PROBLEMS_PARTS),BW_HIDE_TABLE_CHECKED_PARTS,BW_BRICKLINK_LINKSand the other upstreamBW_*display, pagination, folder and socket settings.
4.6d-1 · Collection design comparison (partial)
- Capture the Collection design frames and deployed app; record differences, approved deviations and blocked visual checks.
- Align open cards, compact detail heroes, identity order, mobile module order, Info facts, Prices typography, status dots and edit segments with the kit.
- Keep existing database reads, transactions, events and Undo; post-change screenshots and remaining component differences are still outstanding.
4.5v · list cost and quiet name refresh
- Select list pictures by source priority and recency without filesystem checks; keep containment and missing-file checks on the image route.
- Refresh only changed names and source properties, and report changed identities rather than every catalogue match.
- Label wishlist quantities “wanted”; reserve “missing” for collection defects.
4.5u · names, colours and identity
- Map catalogue names into migrated items with Rebrickable fallback and property provenance; refresh held names on later catalogue loads.
- Load validated BrickLink colour RGB in Catalogues & keys and show colour coverage.
- Show identity numbers once, omit absent names and leading separators, and share unsigned defect labels between templates and browser rows.
-
Restore versioned PWA assets offline, focused-button keyboard activation, missing-asset URL fallback and the Part to Inventory shortcut.
-
Fix review findings: start Planning refresh after commit, require login for all Planning actions, classify migrated/reference pictures consistently, preserve merged stock defects and tolerate later receipt quantities.
- Preserve Planning export selection and Collection row/image nodes across filtering and sorting, restore keyboard actions after button focus, show batch expiry and bulk picture failure reasons, and version Brick Work assets by deployed file mtime.
-
Make Settings SQL tracing and navigation-count tests measure the actual paths; document the manifest shortcut blocked by the task's path allowlist.
-
Suppress cooperative yields during SQLite transactions; materialize inventory per copy and yield after commit.
- Recover same-pid import owners that this process did not claim, without a schema change.
-
Poll future budget waits at their earliest deadline, capped at 60 seconds; require editable mode and CSRF for selective and all-failed-step Retry.
-
Yield between picture identities and other import work units so gevent can serve requests during long jobs.
- Start checkpoint recovery at app startup and retain the existing atomic process-owner claims.
- Show interrupted import jobs with Resume; preserve completed work and budget deadlines.
-
Batch Import jobs step reads and test fixture yield timing, restart, concurrent claims and CLI operation without gevent.
-
Replace the Settings picture identity payload with a small SQL count matrix. Skip picture file checks on page loads; retain exact confirmation selection and report queued counts that differ from the dialog estimate.
-
Keep the rail theme picker below an independently scrolling navigation list at iPad landscape and desktop sizes.
-
Share picture-kind classification between existing-file imports and pipeline downloads: only Rebrickable parts are renders, so refreshing imported set and minifigure photos replaces the same kind.
-
Add Settings picture refresh: source choice, missing/replace scope, colour-specific counts, budgeted import progress and searchable findings. Verify and copy existing BrickTracker cache files using migrated identity evidence; preserve originals and picture priority.
-
Fix Planning phone rows: put wish edits and copy actions in separate flowing blocks, hide closed/hidden controls and empty feedback, and show row prices with at most two decimals while preserving stored precision.
-
Add Planning Wishlist, Prices and Complete sets on brickwork.db, with shared cached prices, audited pins/settings, loose-stock repair estimates and BrickLink XML export. Queue market-price refreshes through the budgeted pipeline. Share missing/damaged gaps with Workbench and move mobile footer clearance into the shell. Report the missing wish-currency and alert-storage contracts before enabling wanted-watch comparisons.
-
Speed up Collection lists with SQL reads scoped to the listed kind and identities; clear the bottom tab bar in every shared list. Merge colliding loose-stock edits by item, colour, condition, lot and storage, retaining minifigures separately, per-row events and exact receipt Undo. Show the remaining stock row after a merge.
-
Rebuild Collection and the home Sets list on brickwork.db: bulk-decorated item lists, shared Info/Prices/Matching/Consists of details, canonical jump links, colour-specific wishes, copy editing and archive Undo, local photos/captions/lightbox, lots, grouping and purchase-location totals. Share bounded matching and reversible transfers into loose-minifigure part gaps. Preserve the previous home at
/house/collection-legacy-home. -
Schema 3.2 adds storage archival. Delete shows copy/entry/piece counts and either requires an empty location or explicitly moves live contents to Not stored atomically. Hide archived locations in pickers and lists; guarded Undo restores contents, and creation Undo archives the new location. Include the NULL archive column in migration mapping and proof.
-
Merge loose-stock additions by live item, colour, condition, lot and storage across Add, Part to Inventory and Orders; keep figures separate and guard quantity Undo with audited before/after receipts. Identification IDs stay independent; photos follow the stock row.
-
Rebuild Part to Inventory on brickwork.db: camera/saved-photo capture, audited Brickognize parts and figures, colour-confirmed queue, atomic loose-stock/lot batches, own photos and receipt Undo. Local model remains unavailable.
-
Add v3 Orders review/import, receipt counting, explicit copy/stock allocation, holds, reconciliation and audited Undo; add Storage counts, location detail/edit and atomic moves. Rebuild navigation. Location archive and creation Undo are available with schema 3.2.
-
Fix checker phone layout: consolidate Saved/Undo above the copy and part headings, remove the floating toast and sticky answer overlap, show colour/name/number once, and replace the wrapped “to go” label with “remaining”.
-
Brick Work 4.2e: schema 3.1 wishlist row ids, colour and quantity, live-key uniqueness and row-id flags. Preserve XML colour/quantity and user notes; explicitly add duplicate quantities with exact Undo. Migrate deterministic wish ids/flags and checksum colour/quantity; include wishes in price colour discovery and live navigation counts.
-
Share derived completeness between checker and workbench: damaged non-spare parts block Complete. Validate booklet batches against catalogue instructions with explicit unknown/ambiguous line errors, index exact stock matches and picker gap counts, and validate transfers only against their requested source and gap.
-
Clear process-global metadata caches when shell test fixtures finish, preventing picker/matcher tests from leaking wish-owner columns into fresh capture databases.
-
Add Part Picker and Matcher on
brickwork.db: copy selection, completion ranking, colour grids and found receipts, exact loose-stock Take/Give for parts, whole figures, physical booklets and boxes, bulk booklet entry, atomic history/events and guarded Undo. -
Add Manage → Add on
brickwork.db: all eight BrickLink types, local catalogue search, paste/XML/CSV review, budgeted Brickognize candidates, explicit confirmation, duplicate choices, audited collection receipts and Undo, durable per-item imports and batch progress. Skip hidden AppleDouble files during catalogue loading. -
Fix Check Set Parts to use the migrated “Set is checked” status flag for Finish, Undo, derived completeness and chooser defaults. Return save deltas without inventory-wide picture lookups.
-
Rebuild Check Set Parts on
brickwork.db: copy chooser, immediate audited counts, figure and spare passes, full miss history, Found 1 recovery, derived-only finish, Undo and an ordered offline queue. -
Add Manage → Tools & Admin on
brickwork.db: source keys and catalogues, durable refresh jobs, unresolved identity review, statistics, values, database export/checks, settings, theme and identification history. Keep the retired tools routes reachable. -
Add the Toni v2 Brick Work shell: four navigation groups, responsive rails and bottom tabs, read-only counts, local brand assets, system pages and Home Screen installation with a shell-only offline fallback.
-
Pin production dependencies and Python 3.14.8; build the local Brick Work image reproducibly.
Fork work since upstream 8b0b85f:
House data store and API
- Add an independent Rebrickable side catalogue and house SQLite store with idempotent migrations, collection tracking and price history.
- Add authenticated house API and CLI workflows for capture, copy/wishlist editing, missing parts, loose inventory, identification history, minifigure resolution and BrickLink XML import/export.
- Add physical box/booklet tracking, manual completeness, reviewed database maintenance and receipt-protected loose-stock transfers with reconciliation after split commits.
Toni UI
- Add selectable toni/upstream UI modes, local light/dark/system themes, responsive navigation and global item jump.
- Rebuild collection lists, item and copy details, inventory tabs, parts checking, editing, statistics, jobs and administration; improve sorting, filters, repeated-figure grouping and mobile controls.
- Add enlarged pictures, booklet reference images, direct found-count saving and a full-width checker Found action.
- Brand the fork surfaces as Brick Work while retaining upstream credits and technical names.
Prices and orders
- Add paced Brickset fetching, BrickLink price slots, condition-aware valuations, settings, colour maps, offline catalogue indexing and part-price observations with due keys.
- Add completion ranking, repair pricing, email/XML/Store API order import, receipt-ledger review, reconciliation and received/reviewed allocation.
- Normalize price formatting and numeric sorting, and provide bounded authenticated BrickLink image caching and fallbacks.
Scanner and matcher
- Add Workbench parts scanning and matching, conservative colour/name matching, mould/alternate resolution and manual figure mappings.
- Resolve scanner-added pictures with authoritative part mappings and exact-colour sources; show owned sets needing loose stock and support reviewed inventory transfers.
Tests
- Add offline Python coverage for stores, API, migrations, imports, prices, matching and UI contracts, plus Node runtime harnesses for toni interactions.
- Add the repository check gate and synthetic order fixtures with invented order, set and catalogue identities.
Upstream history
Releases 1.4.2 and older come from the upstream BrickTracker project: see its repository.
